source: trip-planner-front/node_modules/ajv/dist/compile/jtd/parse.js@ 8d391a1

Last change on this file since 8d391a1 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 13.1 KB
Line 
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const types_1 = require("./types");
4const __1 = require("..");
5const codegen_1 = require("../codegen");
6const ref_error_1 = require("../ref_error");
7const names_1 = require("../names");
8const code_1 = require("../../vocabularies/code");
9const ref_1 = require("../../vocabularies/jtd/ref");
10const type_1 = require("../../vocabularies/jtd/type");
11const parseJson_1 = require("../../runtime/parseJson");
12const util_1 = require("../util");
13const timestamp_1 = require("../../runtime/timestamp");
14const genParse = {
15 elements: parseElements,
16 values: parseValues,
17 discriminator: parseDiscriminator,
18 properties: parseProperties,
19 optionalProperties: parseProperties,
20 enum: parseEnum,
21 type: parseType,
22 ref: parseRef,
23};
24function compileParser(sch, definitions) {
25 const _sch = __1.getCompilingSchema.call(this, sch);
26 if (_sch)
27 return _sch;
28 const { es5, lines } = this.opts.code;
29 const { ownProperties } = this.opts;
30 const gen = new codegen_1.CodeGen(this.scope, { es5, lines, ownProperties });
31 const parseName = gen.scopeName("parse");
32 const cxt = {
33 self: this,
34 gen,
35 schema: sch.schema,
36 schemaEnv: sch,
37 definitions,
38 data: names_1.default.data,
39 parseName,
40 char: gen.name("c"),
41 };
42 let sourceCode;
43 try {
44 this._compilations.add(sch);
45 sch.parseName = parseName;
46 parserFunction(cxt);
47 gen.optimize(this.opts.code.optimize);
48 const parseFuncCode = gen.toString();
49 sourceCode = `${gen.scopeRefs(names_1.default.scope)}return ${parseFuncCode}`;
50 const makeParse = new Function(`${names_1.default.scope}`, sourceCode);
51 const parse = makeParse(this.scope.get());
52 this.scope.value(parseName, { ref: parse });
53 sch.parse = parse;
54 }
55 catch (e) {
56 if (sourceCode)
57 this.logger.error("Error compiling parser, function code:", sourceCode);
58 delete sch.parse;
59 delete sch.parseName;
60 throw e;
61 }
62 finally {
63 this._compilations.delete(sch);
64 }
65 return sch;
66}
67exports.default = compileParser;
68const undef = codegen_1._ `undefined`;
69function parserFunction(cxt) {
70 const { gen, parseName, char } = cxt;
71 gen.func(parseName, codegen_1._ `${names_1.default.json}, ${names_1.default.jsonPos}, ${names_1.default.jsonPart}`, false, () => {
72 gen.let(names_1.default.data);
73 gen.let(char);
74 gen.assign(codegen_1._ `${parseName}.message`, undef);
75 gen.assign(codegen_1._ `${parseName}.position`, undef);
76 gen.assign(names_1.default.jsonPos, codegen_1._ `${names_1.default.jsonPos} || 0`);
77 gen.const(names_1.default.jsonLen, codegen_1._ `${names_1.default.json}.length`);
78 parseCode(cxt);
79 skipWhitespace(cxt);
80 gen.if(names_1.default.jsonPart, () => {
81 gen.assign(codegen_1._ `${parseName}.position`, names_1.default.jsonPos);
82 gen.return(names_1.default.data);
83 });
84 gen.if(codegen_1._ `${names_1.default.jsonPos} === ${names_1.default.jsonLen}`, () => gen.return(names_1.default.data));
85 jsonSyntaxError(cxt);
86 });
87}
88function parseCode(cxt) {
89 let form;
90 for (const key of types_1.jtdForms) {
91 if (key in cxt.schema) {
92 form = key;
93 break;
94 }
95 }
96 if (form)
97 parseNullable(cxt, genParse[form]);
98 else
99 parseEmpty(cxt);
100}
101const parseBoolean = parseBooleanToken(true, parseBooleanToken(false, jsonSyntaxError));
102function parseNullable(cxt, parseForm) {
103 const { gen, schema, data } = cxt;
104 if (!schema.nullable)
105 return parseForm(cxt);
106 tryParseToken(cxt, "null", parseForm, () => gen.assign(data, null));
107}
108function parseElements(cxt) {
109 const { gen, schema, data } = cxt;
110 parseToken(cxt, "[");
111 const ix = gen.let("i", 0);
112 gen.assign(data, codegen_1._ `[]`);
113 parseItems(cxt, "]", () => {
114 const el = gen.let("el");
115 parseCode({ ...cxt, schema: schema.elements, data: el });
116 gen.assign(codegen_1._ `${data}[${ix}++]`, el);
117 });
118}
119function parseValues(cxt) {
120 const { gen, schema, data } = cxt;
121 parseToken(cxt, "{");
122 gen.assign(data, codegen_1._ `{}`);
123 parseItems(cxt, "}", () => parseKeyValue(cxt, schema.values));
124}
125function parseItems(cxt, endToken, block) {
126 tryParseItems(cxt, endToken, block);
127 parseToken(cxt, endToken);
128}
129function tryParseItems(cxt, endToken, block) {
130 const { gen } = cxt;
131 gen.for(codegen_1._ `;${names_1.default.jsonPos}<${names_1.default.jsonLen} && ${jsonSlice(1)}!==${endToken};`, () => {
132 block();
133 tryParseToken(cxt, ",", () => gen.break(), hasItem);
134 });
135 function hasItem() {
136 tryParseToken(cxt, endToken, () => { }, jsonSyntaxError);
137 }
138}
139function parseKeyValue(cxt, schema) {
140 const { gen } = cxt;
141 const key = gen.let("key");
142 parseString({ ...cxt, data: key });
143 parseToken(cxt, ":");
144 parsePropertyValue(cxt, key, schema);
145}
146function parseDiscriminator(cxt) {
147 const { gen, data, schema } = cxt;
148 const { discriminator, mapping } = schema;
149 parseToken(cxt, "{");
150 gen.assign(data, codegen_1._ `{}`);
151 const startPos = gen.const("pos", names_1.default.jsonPos);
152 const value = gen.let("value");
153 const tag = gen.let("tag");
154 tryParseItems(cxt, "}", () => {
155 const key = gen.let("key");
156 parseString({ ...cxt, data: key });
157 parseToken(cxt, ":");
158 gen.if(codegen_1._ `${key} === ${discriminator}`, () => {
159 parseString({ ...cxt, data: tag });
160 gen.assign(codegen_1._ `${data}[${key}]`, tag);
161 gen.break();
162 }, () => parseEmpty({ ...cxt, data: value }) // can be discarded/skipped
163 );
164 });
165 gen.assign(names_1.default.jsonPos, startPos);
166 gen.if(codegen_1._ `${tag} === undefined`);
167 parsingError(cxt, codegen_1.str `discriminator tag not found`);
168 for (const tagValue in mapping) {
169 gen.elseIf(codegen_1._ `${tag} === ${tagValue}`);
170 parseSchemaProperties({ ...cxt, schema: mapping[tagValue] }, discriminator);
171 }
172 gen.else();
173 parsingError(cxt, codegen_1.str `discriminator value not in schema`);
174 gen.endIf();
175}
176function parseProperties(cxt) {
177 const { gen, data } = cxt;
178 parseToken(cxt, "{");
179 gen.assign(data, codegen_1._ `{}`);
180 parseSchemaProperties(cxt);
181}
182function parseSchemaProperties(cxt, discriminator) {
183 const { gen, schema, data } = cxt;
184 const { properties, optionalProperties, additionalProperties } = schema;
185 parseItems(cxt, "}", () => {
186 const key = gen.let("key");
187 parseString({ ...cxt, data: key });
188 parseToken(cxt, ":");
189 gen.if(false);
190 parseDefinedProperty(cxt, key, properties);
191 parseDefinedProperty(cxt, key, optionalProperties);
192 if (discriminator) {
193 gen.elseIf(codegen_1._ `${key} === ${discriminator}`);
194 const tag = gen.let("tag");
195 parseString({ ...cxt, data: tag }); // can be discarded, it is already assigned
196 }
197 gen.else();
198 if (additionalProperties) {
199 parseEmpty({ ...cxt, data: codegen_1._ `${data}[${key}]` });
200 }
201 else {
202 parsingError(cxt, codegen_1.str `property ${key} not allowed`);
203 }
204 gen.endIf();
205 });
206 if (properties) {
207 const hasProp = code_1.hasPropFunc(gen);
208 const allProps = codegen_1.and(...Object.keys(properties).map((p) => codegen_1._ `${hasProp}.call(${data}, ${p})`));
209 gen.if(codegen_1.not(allProps), () => parsingError(cxt, codegen_1.str `missing required properties`));
210 }
211}
212function parseDefinedProperty(cxt, key, schemas = {}) {
213 const { gen } = cxt;
214 for (const prop in schemas) {
215 gen.elseIf(codegen_1._ `${key} === ${prop}`);
216 parsePropertyValue(cxt, key, schemas[prop]);
217 }
218}
219function parsePropertyValue(cxt, key, schema) {
220 parseCode({ ...cxt, schema, data: codegen_1._ `${cxt.data}[${key}]` });
221}
222function parseType(cxt) {
223 const { gen, schema, data, self } = cxt;
224 switch (schema.type) {
225 case "boolean":
226 parseBoolean(cxt);
227 break;
228 case "string":
229 parseString(cxt);
230 break;
231 case "timestamp": {
232 parseString(cxt);
233 const vts = util_1.useFunc(gen, timestamp_1.default);
234 const { allowDate, parseDate } = self.opts;
235 const notValid = allowDate ? codegen_1._ `!${vts}(${data}, true)` : codegen_1._ `!${vts}(${data})`;
236 const fail = parseDate
237 ? codegen_1.or(notValid, codegen_1._ `(${data} = new Date(${data}), false)`, codegen_1._ `isNaN(${data}.valueOf())`)
238 : notValid;
239 gen.if(fail, () => parsingError(cxt, codegen_1.str `invalid timestamp`));
240 break;
241 }
242 case "float32":
243 case "float64":
244 parseNumber(cxt);
245 break;
246 default: {
247 const t = schema.type;
248 if (!self.opts.int32range && (t === "int32" || t === "uint32")) {
249 parseNumber(cxt, 16); // 2 ** 53 - max safe integer
250 if (t === "uint32") {
251 gen.if(codegen_1._ `${data} < 0`, () => parsingError(cxt, codegen_1.str `integer out of range`));
252 }
253 }
254 else {
255 const [min, max, maxDigits] = type_1.intRange[t];
256 parseNumber(cxt, maxDigits);
257 gen.if(codegen_1._ `${data} < ${min} || ${data} > ${max}`, () => parsingError(cxt, codegen_1.str `integer out of range`));
258 }
259 }
260 }
261}
262function parseString(cxt) {
263 parseToken(cxt, '"');
264 parseWith(cxt, parseJson_1.parseJsonString);
265}
266function parseEnum(cxt) {
267 const { gen, data, schema } = cxt;
268 const enumSch = schema.enum;
269 parseToken(cxt, '"');
270 // TODO loopEnum
271 gen.if(false);
272 for (const value of enumSch) {
273 const valueStr = JSON.stringify(value).slice(1); // remove starting quote
274 gen.elseIf(codegen_1._ `${jsonSlice(valueStr.length)} === ${valueStr}`);
275 gen.assign(data, codegen_1.str `${value}`);
276 gen.add(names_1.default.jsonPos, valueStr.length);
277 }
278 gen.else();
279 jsonSyntaxError(cxt);
280 gen.endIf();
281}
282function parseNumber(cxt, maxDigits) {
283 const { gen } = cxt;
284 skipWhitespace(cxt);
285 gen.if(codegen_1._ `"-0123456789".indexOf(${jsonSlice(1)}) < 0`, () => jsonSyntaxError(cxt), () => parseWith(cxt, parseJson_1.parseJsonNumber, maxDigits));
286}
287function parseBooleanToken(bool, fail) {
288 return (cxt) => {
289 const { gen, data } = cxt;
290 tryParseToken(cxt, `${bool}`, () => fail(cxt), () => gen.assign(data, bool));
291 };
292}
293function parseRef(cxt) {
294 const { gen, self, definitions, schema, schemaEnv } = cxt;
295 const { ref } = schema;
296 const refSchema = definitions[ref];
297 if (!refSchema)
298 throw new ref_error_1.default("", ref, `No definition ${ref}`);
299 if (!ref_1.hasRef(refSchema))
300 return parseCode({ ...cxt, schema: refSchema });
301 const { root } = schemaEnv;
302 const sch = compileParser.call(self, new __1.SchemaEnv({ schema: refSchema, root }), definitions);
303 partialParse(cxt, getParser(gen, sch), true);
304}
305function getParser(gen, sch) {
306 return sch.parse
307 ? gen.scopeValue("parse", { ref: sch.parse })
308 : codegen_1._ `${gen.scopeValue("wrapper", { ref: sch })}.parse`;
309}
310function parseEmpty(cxt) {
311 parseWith(cxt, parseJson_1.parseJson);
312}
313function parseWith(cxt, parseFunc, args) {
314 partialParse(cxt, util_1.useFunc(cxt.gen, parseFunc), args);
315}
316function partialParse(cxt, parseFunc, args) {
317 const { gen, data } = cxt;
318 gen.assign(data, codegen_1._ `${parseFunc}(${names_1.default.json}, ${names_1.default.jsonPos}${args ? codegen_1._ `, ${args}` : codegen_1.nil})`);
319 gen.assign(names_1.default.jsonPos, codegen_1._ `${parseFunc}.position`);
320 gen.if(codegen_1._ `${data} === undefined`, () => parsingError(cxt, codegen_1._ `${parseFunc}.message`));
321}
322function parseToken(cxt, tok) {
323 tryParseToken(cxt, tok, jsonSyntaxError);
324}
325function tryParseToken(cxt, tok, fail, success) {
326 const { gen } = cxt;
327 const n = tok.length;
328 skipWhitespace(cxt);
329 gen.if(codegen_1._ `${jsonSlice(n)} === ${tok}`, () => {
330 gen.add(names_1.default.jsonPos, n);
331 success === null || success === void 0 ? void 0 : success(cxt);
332 }, () => fail(cxt));
333}
334function skipWhitespace({ gen, char: c }) {
335 gen.code(codegen_1._ `while((${c}=${names_1.default.json}[${names_1.default.jsonPos}],${c}===" "||${c}==="\\n"||${c}==="\\r"||${c}==="\\t"))${names_1.default.jsonPos}++;`);
336}
337function jsonSlice(len) {
338 return len === 1
339 ? codegen_1._ `${names_1.default.json}[${names_1.default.jsonPos}]`
340 : codegen_1._ `${names_1.default.json}.slice(${names_1.default.jsonPos}, ${names_1.default.jsonPos}+${len})`;
341}
342function jsonSyntaxError(cxt) {
343 parsingError(cxt, codegen_1._ `"unexpected token " + ${names_1.default.json}[${names_1.default.jsonPos}]`);
344}
345function parsingError({ gen, parseName }, msg) {
346 gen.assign(codegen_1._ `${parseName}.message`, msg);
347 gen.assign(codegen_1._ `${parseName}.position`, names_1.default.jsonPos);
348 gen.return(undef);
349}
350//# sourceMappingURL=parse.js.map
Note: See TracBrowser for help on using the repository browser.