jsonParser.js 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. var __extends = (this && this.__extends) || (function () {
  6. var extendStatics = function (d, b) {
  7. extendStatics = Object.setPrototypeOf ||
  8. ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
  9. function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
  10. return extendStatics(d, b);
  11. };
  12. return function (d, b) {
  13. if (typeof b !== "function" && b !== null)
  14. throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
  15. extendStatics(d, b);
  16. function __() { this.constructor = d; }
  17. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  18. };
  19. })();
  20. import * as Json from 'jsonc-parser';
  21. import { isNumber, equals, isBoolean, isString, isDefined } from '../utils/objects';
  22. import { extendedRegExp } from '../utils/strings';
  23. import { ErrorCode, Diagnostic, DiagnosticSeverity, Range } from '../jsonLanguageTypes';
  24. import * as nls from 'vscode-nls';
  25. var localize = nls.loadMessageBundle();
  26. var formats = {
  27. 'color-hex': { errorMessage: localize('colorHexFormatWarning', 'Invalid color format. Use #RGB, #RGBA, #RRGGBB or #RRGGBBAA.'), pattern: /^#([0-9A-Fa-f]{3,4}|([0-9A-Fa-f]{2}){3,4})$/ },
  28. 'date-time': { errorMessage: localize('dateTimeFormatWarning', 'String is not a RFC3339 date-time.'), pattern: /^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]|60)(\.[0-9]+)?(Z|(\+|-)([01][0-9]|2[0-3]):([0-5][0-9]))$/i },
  29. 'date': { errorMessage: localize('dateFormatWarning', 'String is not a RFC3339 date.'), pattern: /^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/i },
  30. 'time': { errorMessage: localize('timeFormatWarning', 'String is not a RFC3339 time.'), pattern: /^([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]|60)(\.[0-9]+)?(Z|(\+|-)([01][0-9]|2[0-3]):([0-5][0-9]))$/i },
  31. 'email': { errorMessage: localize('emailFormatWarning', 'String is not an e-mail address.'), pattern: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ }
  32. };
  33. var ASTNodeImpl = /** @class */ (function () {
  34. function ASTNodeImpl(parent, offset, length) {
  35. if (length === void 0) { length = 0; }
  36. this.offset = offset;
  37. this.length = length;
  38. this.parent = parent;
  39. }
  40. Object.defineProperty(ASTNodeImpl.prototype, "children", {
  41. get: function () {
  42. return [];
  43. },
  44. enumerable: false,
  45. configurable: true
  46. });
  47. ASTNodeImpl.prototype.toString = function () {
  48. return 'type: ' + this.type + ' (' + this.offset + '/' + this.length + ')' + (this.parent ? ' parent: {' + this.parent.toString() + '}' : '');
  49. };
  50. return ASTNodeImpl;
  51. }());
  52. export { ASTNodeImpl };
  53. var NullASTNodeImpl = /** @class */ (function (_super) {
  54. __extends(NullASTNodeImpl, _super);
  55. function NullASTNodeImpl(parent, offset) {
  56. var _this = _super.call(this, parent, offset) || this;
  57. _this.type = 'null';
  58. _this.value = null;
  59. return _this;
  60. }
  61. return NullASTNodeImpl;
  62. }(ASTNodeImpl));
  63. export { NullASTNodeImpl };
  64. var BooleanASTNodeImpl = /** @class */ (function (_super) {
  65. __extends(BooleanASTNodeImpl, _super);
  66. function BooleanASTNodeImpl(parent, boolValue, offset) {
  67. var _this = _super.call(this, parent, offset) || this;
  68. _this.type = 'boolean';
  69. _this.value = boolValue;
  70. return _this;
  71. }
  72. return BooleanASTNodeImpl;
  73. }(ASTNodeImpl));
  74. export { BooleanASTNodeImpl };
  75. var ArrayASTNodeImpl = /** @class */ (function (_super) {
  76. __extends(ArrayASTNodeImpl, _super);
  77. function ArrayASTNodeImpl(parent, offset) {
  78. var _this = _super.call(this, parent, offset) || this;
  79. _this.type = 'array';
  80. _this.items = [];
  81. return _this;
  82. }
  83. Object.defineProperty(ArrayASTNodeImpl.prototype, "children", {
  84. get: function () {
  85. return this.items;
  86. },
  87. enumerable: false,
  88. configurable: true
  89. });
  90. return ArrayASTNodeImpl;
  91. }(ASTNodeImpl));
  92. export { ArrayASTNodeImpl };
  93. var NumberASTNodeImpl = /** @class */ (function (_super) {
  94. __extends(NumberASTNodeImpl, _super);
  95. function NumberASTNodeImpl(parent, offset) {
  96. var _this = _super.call(this, parent, offset) || this;
  97. _this.type = 'number';
  98. _this.isInteger = true;
  99. _this.value = Number.NaN;
  100. return _this;
  101. }
  102. return NumberASTNodeImpl;
  103. }(ASTNodeImpl));
  104. export { NumberASTNodeImpl };
  105. var StringASTNodeImpl = /** @class */ (function (_super) {
  106. __extends(StringASTNodeImpl, _super);
  107. function StringASTNodeImpl(parent, offset, length) {
  108. var _this = _super.call(this, parent, offset, length) || this;
  109. _this.type = 'string';
  110. _this.value = '';
  111. return _this;
  112. }
  113. return StringASTNodeImpl;
  114. }(ASTNodeImpl));
  115. export { StringASTNodeImpl };
  116. var PropertyASTNodeImpl = /** @class */ (function (_super) {
  117. __extends(PropertyASTNodeImpl, _super);
  118. function PropertyASTNodeImpl(parent, offset, keyNode) {
  119. var _this = _super.call(this, parent, offset) || this;
  120. _this.type = 'property';
  121. _this.colonOffset = -1;
  122. _this.keyNode = keyNode;
  123. return _this;
  124. }
  125. Object.defineProperty(PropertyASTNodeImpl.prototype, "children", {
  126. get: function () {
  127. return this.valueNode ? [this.keyNode, this.valueNode] : [this.keyNode];
  128. },
  129. enumerable: false,
  130. configurable: true
  131. });
  132. return PropertyASTNodeImpl;
  133. }(ASTNodeImpl));
  134. export { PropertyASTNodeImpl };
  135. var ObjectASTNodeImpl = /** @class */ (function (_super) {
  136. __extends(ObjectASTNodeImpl, _super);
  137. function ObjectASTNodeImpl(parent, offset) {
  138. var _this = _super.call(this, parent, offset) || this;
  139. _this.type = 'object';
  140. _this.properties = [];
  141. return _this;
  142. }
  143. Object.defineProperty(ObjectASTNodeImpl.prototype, "children", {
  144. get: function () {
  145. return this.properties;
  146. },
  147. enumerable: false,
  148. configurable: true
  149. });
  150. return ObjectASTNodeImpl;
  151. }(ASTNodeImpl));
  152. export { ObjectASTNodeImpl };
  153. export function asSchema(schema) {
  154. if (isBoolean(schema)) {
  155. return schema ? {} : { "not": {} };
  156. }
  157. return schema;
  158. }
  159. export var EnumMatch;
  160. (function (EnumMatch) {
  161. EnumMatch[EnumMatch["Key"] = 0] = "Key";
  162. EnumMatch[EnumMatch["Enum"] = 1] = "Enum";
  163. })(EnumMatch || (EnumMatch = {}));
  164. var SchemaCollector = /** @class */ (function () {
  165. function SchemaCollector(focusOffset, exclude) {
  166. if (focusOffset === void 0) { focusOffset = -1; }
  167. this.focusOffset = focusOffset;
  168. this.exclude = exclude;
  169. this.schemas = [];
  170. }
  171. SchemaCollector.prototype.add = function (schema) {
  172. this.schemas.push(schema);
  173. };
  174. SchemaCollector.prototype.merge = function (other) {
  175. Array.prototype.push.apply(this.schemas, other.schemas);
  176. };
  177. SchemaCollector.prototype.include = function (node) {
  178. return (this.focusOffset === -1 || contains(node, this.focusOffset)) && (node !== this.exclude);
  179. };
  180. SchemaCollector.prototype.newSub = function () {
  181. return new SchemaCollector(-1, this.exclude);
  182. };
  183. return SchemaCollector;
  184. }());
  185. var NoOpSchemaCollector = /** @class */ (function () {
  186. function NoOpSchemaCollector() {
  187. }
  188. Object.defineProperty(NoOpSchemaCollector.prototype, "schemas", {
  189. get: function () { return []; },
  190. enumerable: false,
  191. configurable: true
  192. });
  193. NoOpSchemaCollector.prototype.add = function (schema) { };
  194. NoOpSchemaCollector.prototype.merge = function (other) { };
  195. NoOpSchemaCollector.prototype.include = function (node) { return true; };
  196. NoOpSchemaCollector.prototype.newSub = function () { return this; };
  197. NoOpSchemaCollector.instance = new NoOpSchemaCollector();
  198. return NoOpSchemaCollector;
  199. }());
  200. var ValidationResult = /** @class */ (function () {
  201. function ValidationResult() {
  202. this.problems = [];
  203. this.propertiesMatches = 0;
  204. this.propertiesValueMatches = 0;
  205. this.primaryValueMatches = 0;
  206. this.enumValueMatch = false;
  207. this.enumValues = undefined;
  208. }
  209. ValidationResult.prototype.hasProblems = function () {
  210. return !!this.problems.length;
  211. };
  212. ValidationResult.prototype.mergeAll = function (validationResults) {
  213. for (var _i = 0, validationResults_1 = validationResults; _i < validationResults_1.length; _i++) {
  214. var validationResult = validationResults_1[_i];
  215. this.merge(validationResult);
  216. }
  217. };
  218. ValidationResult.prototype.merge = function (validationResult) {
  219. this.problems = this.problems.concat(validationResult.problems);
  220. };
  221. ValidationResult.prototype.mergeEnumValues = function (validationResult) {
  222. if (!this.enumValueMatch && !validationResult.enumValueMatch && this.enumValues && validationResult.enumValues) {
  223. this.enumValues = this.enumValues.concat(validationResult.enumValues);
  224. for (var _i = 0, _a = this.problems; _i < _a.length; _i++) {
  225. var error = _a[_i];
  226. if (error.code === ErrorCode.EnumValueMismatch) {
  227. error.message = localize('enumWarning', 'Value is not accepted. Valid values: {0}.', this.enumValues.map(function (v) { return JSON.stringify(v); }).join(', '));
  228. }
  229. }
  230. }
  231. };
  232. ValidationResult.prototype.mergePropertyMatch = function (propertyValidationResult) {
  233. this.merge(propertyValidationResult);
  234. this.propertiesMatches++;
  235. if (propertyValidationResult.enumValueMatch || !propertyValidationResult.hasProblems() && propertyValidationResult.propertiesMatches) {
  236. this.propertiesValueMatches++;
  237. }
  238. if (propertyValidationResult.enumValueMatch && propertyValidationResult.enumValues && propertyValidationResult.enumValues.length === 1) {
  239. this.primaryValueMatches++;
  240. }
  241. };
  242. ValidationResult.prototype.compare = function (other) {
  243. var hasProblems = this.hasProblems();
  244. if (hasProblems !== other.hasProblems()) {
  245. return hasProblems ? -1 : 1;
  246. }
  247. if (this.enumValueMatch !== other.enumValueMatch) {
  248. return other.enumValueMatch ? -1 : 1;
  249. }
  250. if (this.primaryValueMatches !== other.primaryValueMatches) {
  251. return this.primaryValueMatches - other.primaryValueMatches;
  252. }
  253. if (this.propertiesValueMatches !== other.propertiesValueMatches) {
  254. return this.propertiesValueMatches - other.propertiesValueMatches;
  255. }
  256. return this.propertiesMatches - other.propertiesMatches;
  257. };
  258. return ValidationResult;
  259. }());
  260. export { ValidationResult };
  261. export function newJSONDocument(root, diagnostics) {
  262. if (diagnostics === void 0) { diagnostics = []; }
  263. return new JSONDocument(root, diagnostics, []);
  264. }
  265. export function getNodeValue(node) {
  266. return Json.getNodeValue(node);
  267. }
  268. export function getNodePath(node) {
  269. return Json.getNodePath(node);
  270. }
  271. export function contains(node, offset, includeRightBound) {
  272. if (includeRightBound === void 0) { includeRightBound = false; }
  273. return offset >= node.offset && offset < (node.offset + node.length) || includeRightBound && offset === (node.offset + node.length);
  274. }
  275. var JSONDocument = /** @class */ (function () {
  276. function JSONDocument(root, syntaxErrors, comments) {
  277. if (syntaxErrors === void 0) { syntaxErrors = []; }
  278. if (comments === void 0) { comments = []; }
  279. this.root = root;
  280. this.syntaxErrors = syntaxErrors;
  281. this.comments = comments;
  282. }
  283. JSONDocument.prototype.getNodeFromOffset = function (offset, includeRightBound) {
  284. if (includeRightBound === void 0) { includeRightBound = false; }
  285. if (this.root) {
  286. return Json.findNodeAtOffset(this.root, offset, includeRightBound);
  287. }
  288. return undefined;
  289. };
  290. JSONDocument.prototype.visit = function (visitor) {
  291. if (this.root) {
  292. var doVisit_1 = function (node) {
  293. var ctn = visitor(node);
  294. var children = node.children;
  295. if (Array.isArray(children)) {
  296. for (var i = 0; i < children.length && ctn; i++) {
  297. ctn = doVisit_1(children[i]);
  298. }
  299. }
  300. return ctn;
  301. };
  302. doVisit_1(this.root);
  303. }
  304. };
  305. JSONDocument.prototype.validate = function (textDocument, schema, severity) {
  306. if (severity === void 0) { severity = DiagnosticSeverity.Warning; }
  307. if (this.root && schema) {
  308. var validationResult = new ValidationResult();
  309. validate(this.root, schema, validationResult, NoOpSchemaCollector.instance);
  310. return validationResult.problems.map(function (p) {
  311. var _a;
  312. var range = Range.create(textDocument.positionAt(p.location.offset), textDocument.positionAt(p.location.offset + p.location.length));
  313. return Diagnostic.create(range, p.message, (_a = p.severity) !== null && _a !== void 0 ? _a : severity, p.code);
  314. });
  315. }
  316. return undefined;
  317. };
  318. JSONDocument.prototype.getMatchingSchemas = function (schema, focusOffset, exclude) {
  319. if (focusOffset === void 0) { focusOffset = -1; }
  320. var matchingSchemas = new SchemaCollector(focusOffset, exclude);
  321. if (this.root && schema) {
  322. validate(this.root, schema, new ValidationResult(), matchingSchemas);
  323. }
  324. return matchingSchemas.schemas;
  325. };
  326. return JSONDocument;
  327. }());
  328. export { JSONDocument };
  329. function validate(n, schema, validationResult, matchingSchemas) {
  330. if (!n || !matchingSchemas.include(n)) {
  331. return;
  332. }
  333. var node = n;
  334. switch (node.type) {
  335. case 'object':
  336. _validateObjectNode(node, schema, validationResult, matchingSchemas);
  337. break;
  338. case 'array':
  339. _validateArrayNode(node, schema, validationResult, matchingSchemas);
  340. break;
  341. case 'string':
  342. _validateStringNode(node, schema, validationResult, matchingSchemas);
  343. break;
  344. case 'number':
  345. _validateNumberNode(node, schema, validationResult, matchingSchemas);
  346. break;
  347. case 'property':
  348. return validate(node.valueNode, schema, validationResult, matchingSchemas);
  349. }
  350. _validateNode();
  351. matchingSchemas.add({ node: node, schema: schema });
  352. function _validateNode() {
  353. function matchesType(type) {
  354. return node.type === type || (type === 'integer' && node.type === 'number' && node.isInteger);
  355. }
  356. if (Array.isArray(schema.type)) {
  357. if (!schema.type.some(matchesType)) {
  358. validationResult.problems.push({
  359. location: { offset: node.offset, length: node.length },
  360. message: schema.errorMessage || localize('typeArrayMismatchWarning', 'Incorrect type. Expected one of {0}.', schema.type.join(', '))
  361. });
  362. }
  363. }
  364. else if (schema.type) {
  365. if (!matchesType(schema.type)) {
  366. validationResult.problems.push({
  367. location: { offset: node.offset, length: node.length },
  368. message: schema.errorMessage || localize('typeMismatchWarning', 'Incorrect type. Expected "{0}".', schema.type)
  369. });
  370. }
  371. }
  372. if (Array.isArray(schema.allOf)) {
  373. for (var _i = 0, _a = schema.allOf; _i < _a.length; _i++) {
  374. var subSchemaRef = _a[_i];
  375. validate(node, asSchema(subSchemaRef), validationResult, matchingSchemas);
  376. }
  377. }
  378. var notSchema = asSchema(schema.not);
  379. if (notSchema) {
  380. var subValidationResult = new ValidationResult();
  381. var subMatchingSchemas = matchingSchemas.newSub();
  382. validate(node, notSchema, subValidationResult, subMatchingSchemas);
  383. if (!subValidationResult.hasProblems()) {
  384. validationResult.problems.push({
  385. location: { offset: node.offset, length: node.length },
  386. message: localize('notSchemaWarning', "Matches a schema that is not allowed.")
  387. });
  388. }
  389. for (var _b = 0, _c = subMatchingSchemas.schemas; _b < _c.length; _b++) {
  390. var ms = _c[_b];
  391. ms.inverted = !ms.inverted;
  392. matchingSchemas.add(ms);
  393. }
  394. }
  395. var testAlternatives = function (alternatives, maxOneMatch) {
  396. var matches = [];
  397. // remember the best match that is used for error messages
  398. var bestMatch = undefined;
  399. for (var _i = 0, alternatives_1 = alternatives; _i < alternatives_1.length; _i++) {
  400. var subSchemaRef = alternatives_1[_i];
  401. var subSchema = asSchema(subSchemaRef);
  402. var subValidationResult = new ValidationResult();
  403. var subMatchingSchemas = matchingSchemas.newSub();
  404. validate(node, subSchema, subValidationResult, subMatchingSchemas);
  405. if (!subValidationResult.hasProblems()) {
  406. matches.push(subSchema);
  407. }
  408. if (!bestMatch) {
  409. bestMatch = { schema: subSchema, validationResult: subValidationResult, matchingSchemas: subMatchingSchemas };
  410. }
  411. else {
  412. if (!maxOneMatch && !subValidationResult.hasProblems() && !bestMatch.validationResult.hasProblems()) {
  413. // no errors, both are equally good matches
  414. bestMatch.matchingSchemas.merge(subMatchingSchemas);
  415. bestMatch.validationResult.propertiesMatches += subValidationResult.propertiesMatches;
  416. bestMatch.validationResult.propertiesValueMatches += subValidationResult.propertiesValueMatches;
  417. }
  418. else {
  419. var compareResult = subValidationResult.compare(bestMatch.validationResult);
  420. if (compareResult > 0) {
  421. // our node is the best matching so far
  422. bestMatch = { schema: subSchema, validationResult: subValidationResult, matchingSchemas: subMatchingSchemas };
  423. }
  424. else if (compareResult === 0) {
  425. // there's already a best matching but we are as good
  426. bestMatch.matchingSchemas.merge(subMatchingSchemas);
  427. bestMatch.validationResult.mergeEnumValues(subValidationResult);
  428. }
  429. }
  430. }
  431. }
  432. if (matches.length > 1 && maxOneMatch) {
  433. validationResult.problems.push({
  434. location: { offset: node.offset, length: 1 },
  435. message: localize('oneOfWarning', "Matches multiple schemas when only one must validate.")
  436. });
  437. }
  438. if (bestMatch) {
  439. validationResult.merge(bestMatch.validationResult);
  440. validationResult.propertiesMatches += bestMatch.validationResult.propertiesMatches;
  441. validationResult.propertiesValueMatches += bestMatch.validationResult.propertiesValueMatches;
  442. matchingSchemas.merge(bestMatch.matchingSchemas);
  443. }
  444. return matches.length;
  445. };
  446. if (Array.isArray(schema.anyOf)) {
  447. testAlternatives(schema.anyOf, false);
  448. }
  449. if (Array.isArray(schema.oneOf)) {
  450. testAlternatives(schema.oneOf, true);
  451. }
  452. var testBranch = function (schema) {
  453. var subValidationResult = new ValidationResult();
  454. var subMatchingSchemas = matchingSchemas.newSub();
  455. validate(node, asSchema(schema), subValidationResult, subMatchingSchemas);
  456. validationResult.merge(subValidationResult);
  457. validationResult.propertiesMatches += subValidationResult.propertiesMatches;
  458. validationResult.propertiesValueMatches += subValidationResult.propertiesValueMatches;
  459. matchingSchemas.merge(subMatchingSchemas);
  460. };
  461. var testCondition = function (ifSchema, thenSchema, elseSchema) {
  462. var subSchema = asSchema(ifSchema);
  463. var subValidationResult = new ValidationResult();
  464. var subMatchingSchemas = matchingSchemas.newSub();
  465. validate(node, subSchema, subValidationResult, subMatchingSchemas);
  466. matchingSchemas.merge(subMatchingSchemas);
  467. if (!subValidationResult.hasProblems()) {
  468. if (thenSchema) {
  469. testBranch(thenSchema);
  470. }
  471. }
  472. else if (elseSchema) {
  473. testBranch(elseSchema);
  474. }
  475. };
  476. var ifSchema = asSchema(schema.if);
  477. if (ifSchema) {
  478. testCondition(ifSchema, asSchema(schema.then), asSchema(schema.else));
  479. }
  480. if (Array.isArray(schema.enum)) {
  481. var val = getNodeValue(node);
  482. var enumValueMatch = false;
  483. for (var _d = 0, _e = schema.enum; _d < _e.length; _d++) {
  484. var e = _e[_d];
  485. if (equals(val, e)) {
  486. enumValueMatch = true;
  487. break;
  488. }
  489. }
  490. validationResult.enumValues = schema.enum;
  491. validationResult.enumValueMatch = enumValueMatch;
  492. if (!enumValueMatch) {
  493. validationResult.problems.push({
  494. location: { offset: node.offset, length: node.length },
  495. code: ErrorCode.EnumValueMismatch,
  496. message: schema.errorMessage || localize('enumWarning', 'Value is not accepted. Valid values: {0}.', schema.enum.map(function (v) { return JSON.stringify(v); }).join(', '))
  497. });
  498. }
  499. }
  500. if (isDefined(schema.const)) {
  501. var val = getNodeValue(node);
  502. if (!equals(val, schema.const)) {
  503. validationResult.problems.push({
  504. location: { offset: node.offset, length: node.length },
  505. code: ErrorCode.EnumValueMismatch,
  506. message: schema.errorMessage || localize('constWarning', 'Value must be {0}.', JSON.stringify(schema.const))
  507. });
  508. validationResult.enumValueMatch = false;
  509. }
  510. else {
  511. validationResult.enumValueMatch = true;
  512. }
  513. validationResult.enumValues = [schema.const];
  514. }
  515. if (schema.deprecationMessage && node.parent) {
  516. validationResult.problems.push({
  517. location: { offset: node.parent.offset, length: node.parent.length },
  518. severity: DiagnosticSeverity.Warning,
  519. message: schema.deprecationMessage,
  520. code: ErrorCode.Deprecated
  521. });
  522. }
  523. }
  524. function _validateNumberNode(node, schema, validationResult, matchingSchemas) {
  525. var val = node.value;
  526. function normalizeFloats(float) {
  527. var _a;
  528. var parts = /^(-?\d+)(?:\.(\d+))?(?:e([-+]\d+))?$/.exec(float.toString());
  529. return parts && {
  530. value: Number(parts[1] + (parts[2] || '')),
  531. multiplier: (((_a = parts[2]) === null || _a === void 0 ? void 0 : _a.length) || 0) - (parseInt(parts[3]) || 0)
  532. };
  533. }
  534. ;
  535. if (isNumber(schema.multipleOf)) {
  536. var remainder = -1;
  537. if (Number.isInteger(schema.multipleOf)) {
  538. remainder = val % schema.multipleOf;
  539. }
  540. else {
  541. var normMultipleOf = normalizeFloats(schema.multipleOf);
  542. var normValue = normalizeFloats(val);
  543. if (normMultipleOf && normValue) {
  544. var multiplier = Math.pow(10, Math.abs(normValue.multiplier - normMultipleOf.multiplier));
  545. if (normValue.multiplier < normMultipleOf.multiplier) {
  546. normValue.value *= multiplier;
  547. }
  548. else {
  549. normMultipleOf.value *= multiplier;
  550. }
  551. remainder = normValue.value % normMultipleOf.value;
  552. }
  553. }
  554. if (remainder !== 0) {
  555. validationResult.problems.push({
  556. location: { offset: node.offset, length: node.length },
  557. message: localize('multipleOfWarning', 'Value is not divisible by {0}.', schema.multipleOf)
  558. });
  559. }
  560. }
  561. function getExclusiveLimit(limit, exclusive) {
  562. if (isNumber(exclusive)) {
  563. return exclusive;
  564. }
  565. if (isBoolean(exclusive) && exclusive) {
  566. return limit;
  567. }
  568. return undefined;
  569. }
  570. function getLimit(limit, exclusive) {
  571. if (!isBoolean(exclusive) || !exclusive) {
  572. return limit;
  573. }
  574. return undefined;
  575. }
  576. var exclusiveMinimum = getExclusiveLimit(schema.minimum, schema.exclusiveMinimum);
  577. if (isNumber(exclusiveMinimum) && val <= exclusiveMinimum) {
  578. validationResult.problems.push({
  579. location: { offset: node.offset, length: node.length },
  580. message: localize('exclusiveMinimumWarning', 'Value is below the exclusive minimum of {0}.', exclusiveMinimum)
  581. });
  582. }
  583. var exclusiveMaximum = getExclusiveLimit(schema.maximum, schema.exclusiveMaximum);
  584. if (isNumber(exclusiveMaximum) && val >= exclusiveMaximum) {
  585. validationResult.problems.push({
  586. location: { offset: node.offset, length: node.length },
  587. message: localize('exclusiveMaximumWarning', 'Value is above the exclusive maximum of {0}.', exclusiveMaximum)
  588. });
  589. }
  590. var minimum = getLimit(schema.minimum, schema.exclusiveMinimum);
  591. if (isNumber(minimum) && val < minimum) {
  592. validationResult.problems.push({
  593. location: { offset: node.offset, length: node.length },
  594. message: localize('minimumWarning', 'Value is below the minimum of {0}.', minimum)
  595. });
  596. }
  597. var maximum = getLimit(schema.maximum, schema.exclusiveMaximum);
  598. if (isNumber(maximum) && val > maximum) {
  599. validationResult.problems.push({
  600. location: { offset: node.offset, length: node.length },
  601. message: localize('maximumWarning', 'Value is above the maximum of {0}.', maximum)
  602. });
  603. }
  604. }
  605. function _validateStringNode(node, schema, validationResult, matchingSchemas) {
  606. if (isNumber(schema.minLength) && node.value.length < schema.minLength) {
  607. validationResult.problems.push({
  608. location: { offset: node.offset, length: node.length },
  609. message: localize('minLengthWarning', 'String is shorter than the minimum length of {0}.', schema.minLength)
  610. });
  611. }
  612. if (isNumber(schema.maxLength) && node.value.length > schema.maxLength) {
  613. validationResult.problems.push({
  614. location: { offset: node.offset, length: node.length },
  615. message: localize('maxLengthWarning', 'String is longer than the maximum length of {0}.', schema.maxLength)
  616. });
  617. }
  618. if (isString(schema.pattern)) {
  619. var regex = extendedRegExp(schema.pattern);
  620. if (!regex.test(node.value)) {
  621. validationResult.problems.push({
  622. location: { offset: node.offset, length: node.length },
  623. message: schema.patternErrorMessage || schema.errorMessage || localize('patternWarning', 'String does not match the pattern of "{0}".', schema.pattern)
  624. });
  625. }
  626. }
  627. if (schema.format) {
  628. switch (schema.format) {
  629. case 'uri':
  630. case 'uri-reference':
  631. {
  632. var errorMessage = void 0;
  633. if (!node.value) {
  634. errorMessage = localize('uriEmpty', 'URI expected.');
  635. }
  636. else {
  637. var match = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/.exec(node.value);
  638. if (!match) {
  639. errorMessage = localize('uriMissing', 'URI is expected.');
  640. }
  641. else if (!match[2] && schema.format === 'uri') {
  642. errorMessage = localize('uriSchemeMissing', 'URI with a scheme is expected.');
  643. }
  644. }
  645. if (errorMessage) {
  646. validationResult.problems.push({
  647. location: { offset: node.offset, length: node.length },
  648. message: schema.patternErrorMessage || schema.errorMessage || localize('uriFormatWarning', 'String is not a URI: {0}', errorMessage)
  649. });
  650. }
  651. }
  652. break;
  653. case 'color-hex':
  654. case 'date-time':
  655. case 'date':
  656. case 'time':
  657. case 'email':
  658. var format = formats[schema.format];
  659. if (!node.value || !format.pattern.exec(node.value)) {
  660. validationResult.problems.push({
  661. location: { offset: node.offset, length: node.length },
  662. message: schema.patternErrorMessage || schema.errorMessage || format.errorMessage
  663. });
  664. }
  665. default:
  666. }
  667. }
  668. }
  669. function _validateArrayNode(node, schema, validationResult, matchingSchemas) {
  670. if (Array.isArray(schema.items)) {
  671. var subSchemas = schema.items;
  672. for (var index = 0; index < subSchemas.length; index++) {
  673. var subSchemaRef = subSchemas[index];
  674. var subSchema = asSchema(subSchemaRef);
  675. var itemValidationResult = new ValidationResult();
  676. var item = node.items[index];
  677. if (item) {
  678. validate(item, subSchema, itemValidationResult, matchingSchemas);
  679. validationResult.mergePropertyMatch(itemValidationResult);
  680. }
  681. else if (node.items.length >= subSchemas.length) {
  682. validationResult.propertiesValueMatches++;
  683. }
  684. }
  685. if (node.items.length > subSchemas.length) {
  686. if (typeof schema.additionalItems === 'object') {
  687. for (var i = subSchemas.length; i < node.items.length; i++) {
  688. var itemValidationResult = new ValidationResult();
  689. validate(node.items[i], schema.additionalItems, itemValidationResult, matchingSchemas);
  690. validationResult.mergePropertyMatch(itemValidationResult);
  691. }
  692. }
  693. else if (schema.additionalItems === false) {
  694. validationResult.problems.push({
  695. location: { offset: node.offset, length: node.length },
  696. message: localize('additionalItemsWarning', 'Array has too many items according to schema. Expected {0} or fewer.', subSchemas.length)
  697. });
  698. }
  699. }
  700. }
  701. else {
  702. var itemSchema = asSchema(schema.items);
  703. if (itemSchema) {
  704. for (var _i = 0, _a = node.items; _i < _a.length; _i++) {
  705. var item = _a[_i];
  706. var itemValidationResult = new ValidationResult();
  707. validate(item, itemSchema, itemValidationResult, matchingSchemas);
  708. validationResult.mergePropertyMatch(itemValidationResult);
  709. }
  710. }
  711. }
  712. var containsSchema = asSchema(schema.contains);
  713. if (containsSchema) {
  714. var doesContain = node.items.some(function (item) {
  715. var itemValidationResult = new ValidationResult();
  716. validate(item, containsSchema, itemValidationResult, NoOpSchemaCollector.instance);
  717. return !itemValidationResult.hasProblems();
  718. });
  719. if (!doesContain) {
  720. validationResult.problems.push({
  721. location: { offset: node.offset, length: node.length },
  722. message: schema.errorMessage || localize('requiredItemMissingWarning', 'Array does not contain required item.')
  723. });
  724. }
  725. }
  726. if (isNumber(schema.minItems) && node.items.length < schema.minItems) {
  727. validationResult.problems.push({
  728. location: { offset: node.offset, length: node.length },
  729. message: localize('minItemsWarning', 'Array has too few items. Expected {0} or more.', schema.minItems)
  730. });
  731. }
  732. if (isNumber(schema.maxItems) && node.items.length > schema.maxItems) {
  733. validationResult.problems.push({
  734. location: { offset: node.offset, length: node.length },
  735. message: localize('maxItemsWarning', 'Array has too many items. Expected {0} or fewer.', schema.maxItems)
  736. });
  737. }
  738. if (schema.uniqueItems === true) {
  739. var values_1 = getNodeValue(node);
  740. var duplicates = values_1.some(function (value, index) {
  741. return index !== values_1.lastIndexOf(value);
  742. });
  743. if (duplicates) {
  744. validationResult.problems.push({
  745. location: { offset: node.offset, length: node.length },
  746. message: localize('uniqueItemsWarning', 'Array has duplicate items.')
  747. });
  748. }
  749. }
  750. }
  751. function _validateObjectNode(node, schema, validationResult, matchingSchemas) {
  752. var seenKeys = Object.create(null);
  753. var unprocessedProperties = [];
  754. for (var _i = 0, _a = node.properties; _i < _a.length; _i++) {
  755. var propertyNode = _a[_i];
  756. var key = propertyNode.keyNode.value;
  757. seenKeys[key] = propertyNode.valueNode;
  758. unprocessedProperties.push(key);
  759. }
  760. if (Array.isArray(schema.required)) {
  761. for (var _b = 0, _c = schema.required; _b < _c.length; _b++) {
  762. var propertyName = _c[_b];
  763. if (!seenKeys[propertyName]) {
  764. var keyNode = node.parent && node.parent.type === 'property' && node.parent.keyNode;
  765. var location = keyNode ? { offset: keyNode.offset, length: keyNode.length } : { offset: node.offset, length: 1 };
  766. validationResult.problems.push({
  767. location: location,
  768. message: localize('MissingRequiredPropWarning', 'Missing property "{0}".', propertyName)
  769. });
  770. }
  771. }
  772. }
  773. var propertyProcessed = function (prop) {
  774. var index = unprocessedProperties.indexOf(prop);
  775. while (index >= 0) {
  776. unprocessedProperties.splice(index, 1);
  777. index = unprocessedProperties.indexOf(prop);
  778. }
  779. };
  780. if (schema.properties) {
  781. for (var _d = 0, _e = Object.keys(schema.properties); _d < _e.length; _d++) {
  782. var propertyName = _e[_d];
  783. propertyProcessed(propertyName);
  784. var propertySchema = schema.properties[propertyName];
  785. var child = seenKeys[propertyName];
  786. if (child) {
  787. if (isBoolean(propertySchema)) {
  788. if (!propertySchema) {
  789. var propertyNode = child.parent;
  790. validationResult.problems.push({
  791. location: { offset: propertyNode.keyNode.offset, length: propertyNode.keyNode.length },
  792. message: schema.errorMessage || localize('DisallowedExtraPropWarning', 'Property {0} is not allowed.', propertyName)
  793. });
  794. }
  795. else {
  796. validationResult.propertiesMatches++;
  797. validationResult.propertiesValueMatches++;
  798. }
  799. }
  800. else {
  801. var propertyValidationResult = new ValidationResult();
  802. validate(child, propertySchema, propertyValidationResult, matchingSchemas);
  803. validationResult.mergePropertyMatch(propertyValidationResult);
  804. }
  805. }
  806. }
  807. }
  808. if (schema.patternProperties) {
  809. for (var _f = 0, _g = Object.keys(schema.patternProperties); _f < _g.length; _f++) {
  810. var propertyPattern = _g[_f];
  811. var regex = extendedRegExp(propertyPattern);
  812. for (var _h = 0, _j = unprocessedProperties.slice(0); _h < _j.length; _h++) {
  813. var propertyName = _j[_h];
  814. if (regex.test(propertyName)) {
  815. propertyProcessed(propertyName);
  816. var child = seenKeys[propertyName];
  817. if (child) {
  818. var propertySchema = schema.patternProperties[propertyPattern];
  819. if (isBoolean(propertySchema)) {
  820. if (!propertySchema) {
  821. var propertyNode = child.parent;
  822. validationResult.problems.push({
  823. location: { offset: propertyNode.keyNode.offset, length: propertyNode.keyNode.length },
  824. message: schema.errorMessage || localize('DisallowedExtraPropWarning', 'Property {0} is not allowed.', propertyName)
  825. });
  826. }
  827. else {
  828. validationResult.propertiesMatches++;
  829. validationResult.propertiesValueMatches++;
  830. }
  831. }
  832. else {
  833. var propertyValidationResult = new ValidationResult();
  834. validate(child, propertySchema, propertyValidationResult, matchingSchemas);
  835. validationResult.mergePropertyMatch(propertyValidationResult);
  836. }
  837. }
  838. }
  839. }
  840. }
  841. }
  842. if (typeof schema.additionalProperties === 'object') {
  843. for (var _k = 0, unprocessedProperties_1 = unprocessedProperties; _k < unprocessedProperties_1.length; _k++) {
  844. var propertyName = unprocessedProperties_1[_k];
  845. var child = seenKeys[propertyName];
  846. if (child) {
  847. var propertyValidationResult = new ValidationResult();
  848. validate(child, schema.additionalProperties, propertyValidationResult, matchingSchemas);
  849. validationResult.mergePropertyMatch(propertyValidationResult);
  850. }
  851. }
  852. }
  853. else if (schema.additionalProperties === false) {
  854. if (unprocessedProperties.length > 0) {
  855. for (var _l = 0, unprocessedProperties_2 = unprocessedProperties; _l < unprocessedProperties_2.length; _l++) {
  856. var propertyName = unprocessedProperties_2[_l];
  857. var child = seenKeys[propertyName];
  858. if (child) {
  859. var propertyNode = child.parent;
  860. validationResult.problems.push({
  861. location: { offset: propertyNode.keyNode.offset, length: propertyNode.keyNode.length },
  862. message: schema.errorMessage || localize('DisallowedExtraPropWarning', 'Property {0} is not allowed.', propertyName)
  863. });
  864. }
  865. }
  866. }
  867. }
  868. if (isNumber(schema.maxProperties)) {
  869. if (node.properties.length > schema.maxProperties) {
  870. validationResult.problems.push({
  871. location: { offset: node.offset, length: node.length },
  872. message: localize('MaxPropWarning', 'Object has more properties than limit of {0}.', schema.maxProperties)
  873. });
  874. }
  875. }
  876. if (isNumber(schema.minProperties)) {
  877. if (node.properties.length < schema.minProperties) {
  878. validationResult.problems.push({
  879. location: { offset: node.offset, length: node.length },
  880. message: localize('MinPropWarning', 'Object has fewer properties than the required number of {0}', schema.minProperties)
  881. });
  882. }
  883. }
  884. if (schema.dependencies) {
  885. for (var _m = 0, _o = Object.keys(schema.dependencies); _m < _o.length; _m++) {
  886. var key = _o[_m];
  887. var prop = seenKeys[key];
  888. if (prop) {
  889. var propertyDep = schema.dependencies[key];
  890. if (Array.isArray(propertyDep)) {
  891. for (var _p = 0, propertyDep_1 = propertyDep; _p < propertyDep_1.length; _p++) {
  892. var requiredProp = propertyDep_1[_p];
  893. if (!seenKeys[requiredProp]) {
  894. validationResult.problems.push({
  895. location: { offset: node.offset, length: node.length },
  896. message: localize('RequiredDependentPropWarning', 'Object is missing property {0} required by property {1}.', requiredProp, key)
  897. });
  898. }
  899. else {
  900. validationResult.propertiesValueMatches++;
  901. }
  902. }
  903. }
  904. else {
  905. var propertySchema = asSchema(propertyDep);
  906. if (propertySchema) {
  907. var propertyValidationResult = new ValidationResult();
  908. validate(node, propertySchema, propertyValidationResult, matchingSchemas);
  909. validationResult.mergePropertyMatch(propertyValidationResult);
  910. }
  911. }
  912. }
  913. }
  914. }
  915. var propertyNames = asSchema(schema.propertyNames);
  916. if (propertyNames) {
  917. for (var _q = 0, _r = node.properties; _q < _r.length; _q++) {
  918. var f = _r[_q];
  919. var key = f.keyNode;
  920. if (key) {
  921. validate(key, propertyNames, validationResult, NoOpSchemaCollector.instance);
  922. }
  923. }
  924. }
  925. }
  926. }
  927. export function parse(textDocument, config) {
  928. var problems = [];
  929. var lastProblemOffset = -1;
  930. var text = textDocument.getText();
  931. var scanner = Json.createScanner(text, false);
  932. var commentRanges = config && config.collectComments ? [] : undefined;
  933. function _scanNext() {
  934. while (true) {
  935. var token_1 = scanner.scan();
  936. _checkScanError();
  937. switch (token_1) {
  938. case 12 /* LineCommentTrivia */:
  939. case 13 /* BlockCommentTrivia */:
  940. if (Array.isArray(commentRanges)) {
  941. commentRanges.push(Range.create(textDocument.positionAt(scanner.getTokenOffset()), textDocument.positionAt(scanner.getTokenOffset() + scanner.getTokenLength())));
  942. }
  943. break;
  944. case 15 /* Trivia */:
  945. case 14 /* LineBreakTrivia */:
  946. break;
  947. default:
  948. return token_1;
  949. }
  950. }
  951. }
  952. function _accept(token) {
  953. if (scanner.getToken() === token) {
  954. _scanNext();
  955. return true;
  956. }
  957. return false;
  958. }
  959. function _errorAtRange(message, code, startOffset, endOffset, severity) {
  960. if (severity === void 0) { severity = DiagnosticSeverity.Error; }
  961. if (problems.length === 0 || startOffset !== lastProblemOffset) {
  962. var range = Range.create(textDocument.positionAt(startOffset), textDocument.positionAt(endOffset));
  963. problems.push(Diagnostic.create(range, message, severity, code, textDocument.languageId));
  964. lastProblemOffset = startOffset;
  965. }
  966. }
  967. function _error(message, code, node, skipUntilAfter, skipUntil) {
  968. if (node === void 0) { node = undefined; }
  969. if (skipUntilAfter === void 0) { skipUntilAfter = []; }
  970. if (skipUntil === void 0) { skipUntil = []; }
  971. var start = scanner.getTokenOffset();
  972. var end = scanner.getTokenOffset() + scanner.getTokenLength();
  973. if (start === end && start > 0) {
  974. start--;
  975. while (start > 0 && /\s/.test(text.charAt(start))) {
  976. start--;
  977. }
  978. end = start + 1;
  979. }
  980. _errorAtRange(message, code, start, end);
  981. if (node) {
  982. _finalize(node, false);
  983. }
  984. if (skipUntilAfter.length + skipUntil.length > 0) {
  985. var token_2 = scanner.getToken();
  986. while (token_2 !== 17 /* EOF */) {
  987. if (skipUntilAfter.indexOf(token_2) !== -1) {
  988. _scanNext();
  989. break;
  990. }
  991. else if (skipUntil.indexOf(token_2) !== -1) {
  992. break;
  993. }
  994. token_2 = _scanNext();
  995. }
  996. }
  997. return node;
  998. }
  999. function _checkScanError() {
  1000. switch (scanner.getTokenError()) {
  1001. case 4 /* InvalidUnicode */:
  1002. _error(localize('InvalidUnicode', 'Invalid unicode sequence in string.'), ErrorCode.InvalidUnicode);
  1003. return true;
  1004. case 5 /* InvalidEscapeCharacter */:
  1005. _error(localize('InvalidEscapeCharacter', 'Invalid escape character in string.'), ErrorCode.InvalidEscapeCharacter);
  1006. return true;
  1007. case 3 /* UnexpectedEndOfNumber */:
  1008. _error(localize('UnexpectedEndOfNumber', 'Unexpected end of number.'), ErrorCode.UnexpectedEndOfNumber);
  1009. return true;
  1010. case 1 /* UnexpectedEndOfComment */:
  1011. _error(localize('UnexpectedEndOfComment', 'Unexpected end of comment.'), ErrorCode.UnexpectedEndOfComment);
  1012. return true;
  1013. case 2 /* UnexpectedEndOfString */:
  1014. _error(localize('UnexpectedEndOfString', 'Unexpected end of string.'), ErrorCode.UnexpectedEndOfString);
  1015. return true;
  1016. case 6 /* InvalidCharacter */:
  1017. _error(localize('InvalidCharacter', 'Invalid characters in string. Control characters must be escaped.'), ErrorCode.InvalidCharacter);
  1018. return true;
  1019. }
  1020. return false;
  1021. }
  1022. function _finalize(node, scanNext) {
  1023. node.length = scanner.getTokenOffset() + scanner.getTokenLength() - node.offset;
  1024. if (scanNext) {
  1025. _scanNext();
  1026. }
  1027. return node;
  1028. }
  1029. function _parseArray(parent) {
  1030. if (scanner.getToken() !== 3 /* OpenBracketToken */) {
  1031. return undefined;
  1032. }
  1033. var node = new ArrayASTNodeImpl(parent, scanner.getTokenOffset());
  1034. _scanNext(); // consume OpenBracketToken
  1035. var count = 0;
  1036. var needsComma = false;
  1037. while (scanner.getToken() !== 4 /* CloseBracketToken */ && scanner.getToken() !== 17 /* EOF */) {
  1038. if (scanner.getToken() === 5 /* CommaToken */) {
  1039. if (!needsComma) {
  1040. _error(localize('ValueExpected', 'Value expected'), ErrorCode.ValueExpected);
  1041. }
  1042. var commaOffset = scanner.getTokenOffset();
  1043. _scanNext(); // consume comma
  1044. if (scanner.getToken() === 4 /* CloseBracketToken */) {
  1045. if (needsComma) {
  1046. _errorAtRange(localize('TrailingComma', 'Trailing comma'), ErrorCode.TrailingComma, commaOffset, commaOffset + 1);
  1047. }
  1048. continue;
  1049. }
  1050. }
  1051. else if (needsComma) {
  1052. _error(localize('ExpectedComma', 'Expected comma'), ErrorCode.CommaExpected);
  1053. }
  1054. var item = _parseValue(node);
  1055. if (!item) {
  1056. _error(localize('PropertyExpected', 'Value expected'), ErrorCode.ValueExpected, undefined, [], [4 /* CloseBracketToken */, 5 /* CommaToken */]);
  1057. }
  1058. else {
  1059. node.items.push(item);
  1060. }
  1061. needsComma = true;
  1062. }
  1063. if (scanner.getToken() !== 4 /* CloseBracketToken */) {
  1064. return _error(localize('ExpectedCloseBracket', 'Expected comma or closing bracket'), ErrorCode.CommaOrCloseBacketExpected, node);
  1065. }
  1066. return _finalize(node, true);
  1067. }
  1068. var keyPlaceholder = new StringASTNodeImpl(undefined, 0, 0);
  1069. function _parseProperty(parent, keysSeen) {
  1070. var node = new PropertyASTNodeImpl(parent, scanner.getTokenOffset(), keyPlaceholder);
  1071. var key = _parseString(node);
  1072. if (!key) {
  1073. if (scanner.getToken() === 16 /* Unknown */) {
  1074. // give a more helpful error message
  1075. _error(localize('DoubleQuotesExpected', 'Property keys must be doublequoted'), ErrorCode.Undefined);
  1076. var keyNode = new StringASTNodeImpl(node, scanner.getTokenOffset(), scanner.getTokenLength());
  1077. keyNode.value = scanner.getTokenValue();
  1078. key = keyNode;
  1079. _scanNext(); // consume Unknown
  1080. }
  1081. else {
  1082. return undefined;
  1083. }
  1084. }
  1085. node.keyNode = key;
  1086. var seen = keysSeen[key.value];
  1087. if (seen) {
  1088. _errorAtRange(localize('DuplicateKeyWarning', "Duplicate object key"), ErrorCode.DuplicateKey, node.keyNode.offset, node.keyNode.offset + node.keyNode.length, DiagnosticSeverity.Warning);
  1089. if (typeof seen === 'object') {
  1090. _errorAtRange(localize('DuplicateKeyWarning', "Duplicate object key"), ErrorCode.DuplicateKey, seen.keyNode.offset, seen.keyNode.offset + seen.keyNode.length, DiagnosticSeverity.Warning);
  1091. }
  1092. keysSeen[key.value] = true; // if the same key is duplicate again, avoid duplicate error reporting
  1093. }
  1094. else {
  1095. keysSeen[key.value] = node;
  1096. }
  1097. if (scanner.getToken() === 6 /* ColonToken */) {
  1098. node.colonOffset = scanner.getTokenOffset();
  1099. _scanNext(); // consume ColonToken
  1100. }
  1101. else {
  1102. _error(localize('ColonExpected', 'Colon expected'), ErrorCode.ColonExpected);
  1103. if (scanner.getToken() === 10 /* StringLiteral */ && textDocument.positionAt(key.offset + key.length).line < textDocument.positionAt(scanner.getTokenOffset()).line) {
  1104. node.length = key.length;
  1105. return node;
  1106. }
  1107. }
  1108. var value = _parseValue(node);
  1109. if (!value) {
  1110. return _error(localize('ValueExpected', 'Value expected'), ErrorCode.ValueExpected, node, [], [2 /* CloseBraceToken */, 5 /* CommaToken */]);
  1111. }
  1112. node.valueNode = value;
  1113. node.length = value.offset + value.length - node.offset;
  1114. return node;
  1115. }
  1116. function _parseObject(parent) {
  1117. if (scanner.getToken() !== 1 /* OpenBraceToken */) {
  1118. return undefined;
  1119. }
  1120. var node = new ObjectASTNodeImpl(parent, scanner.getTokenOffset());
  1121. var keysSeen = Object.create(null);
  1122. _scanNext(); // consume OpenBraceToken
  1123. var needsComma = false;
  1124. while (scanner.getToken() !== 2 /* CloseBraceToken */ && scanner.getToken() !== 17 /* EOF */) {
  1125. if (scanner.getToken() === 5 /* CommaToken */) {
  1126. if (!needsComma) {
  1127. _error(localize('PropertyExpected', 'Property expected'), ErrorCode.PropertyExpected);
  1128. }
  1129. var commaOffset = scanner.getTokenOffset();
  1130. _scanNext(); // consume comma
  1131. if (scanner.getToken() === 2 /* CloseBraceToken */) {
  1132. if (needsComma) {
  1133. _errorAtRange(localize('TrailingComma', 'Trailing comma'), ErrorCode.TrailingComma, commaOffset, commaOffset + 1);
  1134. }
  1135. continue;
  1136. }
  1137. }
  1138. else if (needsComma) {
  1139. _error(localize('ExpectedComma', 'Expected comma'), ErrorCode.CommaExpected);
  1140. }
  1141. var property = _parseProperty(node, keysSeen);
  1142. if (!property) {
  1143. _error(localize('PropertyExpected', 'Property expected'), ErrorCode.PropertyExpected, undefined, [], [2 /* CloseBraceToken */, 5 /* CommaToken */]);
  1144. }
  1145. else {
  1146. node.properties.push(property);
  1147. }
  1148. needsComma = true;
  1149. }
  1150. if (scanner.getToken() !== 2 /* CloseBraceToken */) {
  1151. return _error(localize('ExpectedCloseBrace', 'Expected comma or closing brace'), ErrorCode.CommaOrCloseBraceExpected, node);
  1152. }
  1153. return _finalize(node, true);
  1154. }
  1155. function _parseString(parent) {
  1156. if (scanner.getToken() !== 10 /* StringLiteral */) {
  1157. return undefined;
  1158. }
  1159. var node = new StringASTNodeImpl(parent, scanner.getTokenOffset());
  1160. node.value = scanner.getTokenValue();
  1161. return _finalize(node, true);
  1162. }
  1163. function _parseNumber(parent) {
  1164. if (scanner.getToken() !== 11 /* NumericLiteral */) {
  1165. return undefined;
  1166. }
  1167. var node = new NumberASTNodeImpl(parent, scanner.getTokenOffset());
  1168. if (scanner.getTokenError() === 0 /* None */) {
  1169. var tokenValue = scanner.getTokenValue();
  1170. try {
  1171. var numberValue = JSON.parse(tokenValue);
  1172. if (!isNumber(numberValue)) {
  1173. return _error(localize('InvalidNumberFormat', 'Invalid number format.'), ErrorCode.Undefined, node);
  1174. }
  1175. node.value = numberValue;
  1176. }
  1177. catch (e) {
  1178. return _error(localize('InvalidNumberFormat', 'Invalid number format.'), ErrorCode.Undefined, node);
  1179. }
  1180. node.isInteger = tokenValue.indexOf('.') === -1;
  1181. }
  1182. return _finalize(node, true);
  1183. }
  1184. function _parseLiteral(parent) {
  1185. var node;
  1186. switch (scanner.getToken()) {
  1187. case 7 /* NullKeyword */:
  1188. return _finalize(new NullASTNodeImpl(parent, scanner.getTokenOffset()), true);
  1189. case 8 /* TrueKeyword */:
  1190. return _finalize(new BooleanASTNodeImpl(parent, true, scanner.getTokenOffset()), true);
  1191. case 9 /* FalseKeyword */:
  1192. return _finalize(new BooleanASTNodeImpl(parent, false, scanner.getTokenOffset()), true);
  1193. default:
  1194. return undefined;
  1195. }
  1196. }
  1197. function _parseValue(parent) {
  1198. return _parseArray(parent) || _parseObject(parent) || _parseString(parent) || _parseNumber(parent) || _parseLiteral(parent);
  1199. }
  1200. var _root = undefined;
  1201. var token = _scanNext();
  1202. if (token !== 17 /* EOF */) {
  1203. _root = _parseValue(_root);
  1204. if (!_root) {
  1205. _error(localize('Invalid symbol', 'Expected a JSON object, array or literal.'), ErrorCode.Undefined);
  1206. }
  1207. else if (scanner.getToken() !== 17 /* EOF */) {
  1208. _error(localize('End of file expected', 'End of file expected.'), ErrorCode.Undefined);
  1209. }
  1210. }
  1211. return new JSONDocument(_root, problems, commentRanges);
  1212. }