@aeriajs/compiler 0.0.4 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/ast.d.ts +79 -0
  2. package/dist/ast.js +23 -0
  3. package/dist/ast.mjs +21 -0
  4. package/dist/codegen/generateContracts.d.ts +5 -0
  5. package/dist/codegen/generateContracts.js +84 -0
  6. package/dist/codegen/generateContracts.mjs +77 -0
  7. package/dist/codegen/generateExports.d.ts +15 -0
  8. package/dist/codegen/generateExports.js +41 -0
  9. package/dist/codegen/generateExports.mjs +32 -0
  10. package/dist/codegen/generateJSCollections.d.ts +2 -0
  11. package/dist/codegen/generateJSCollections.js +91 -0
  12. package/dist/codegen/generateJSCollections.mjs +82 -0
  13. package/dist/codegen/generateTSCollections.d.ts +2 -0
  14. package/dist/codegen/generateTSCollections.js +107 -0
  15. package/dist/codegen/generateTSCollections.mjs +99 -0
  16. package/dist/codegen/index.d.ts +4 -0
  17. package/dist/codegen/index.js +20 -0
  18. package/dist/codegen/index.mjs +5 -0
  19. package/dist/codegen/utils.d.ts +29 -0
  20. package/dist/codegen/utils.js +135 -0
  21. package/dist/codegen/utils.mjs +114 -0
  22. package/dist/codegen.d.ts +3 -0
  23. package/dist/codegen.js +102 -0
  24. package/dist/codegen.mjs +52 -0
  25. package/dist/compile.d.ts +21 -0
  26. package/dist/compile.js +96 -0
  27. package/dist/compile.mjs +57 -0
  28. package/dist/diagnostic.d.ts +8 -0
  29. package/dist/diagnostic.js +22 -0
  30. package/dist/diagnostic.mjs +16 -0
  31. package/dist/guards.d.ts +3 -0
  32. package/dist/guards.js +45 -0
  33. package/dist/guards.mjs +8 -0
  34. package/dist/index.d.ts +7 -0
  35. package/dist/index.js +23 -0
  36. package/dist/index.mjs +8 -0
  37. package/dist/lexer.d.ts +14 -0
  38. package/dist/lexer.js +272 -0
  39. package/dist/lexer.mjs +270 -0
  40. package/dist/parser.d.ts +8 -0
  41. package/dist/parser.js +907 -0
  42. package/dist/parser.mjs +851 -0
  43. package/dist/semantic.d.ts +5 -0
  44. package/dist/semantic.js +149 -0
  45. package/dist/semantic.mjs +111 -0
  46. package/dist/token.d.ts +38 -0
  47. package/dist/token.js +24 -0
  48. package/dist/token.mjs +22 -0
  49. package/dist/utils.d.ts +3 -0
  50. package/dist/utils.js +2 -0
  51. package/dist/utils.mjs +1 -0
  52. package/package.json +2 -3
package/dist/parser.js ADDED
@@ -0,0 +1,907 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.parse = exports.locationMap = void 0;
37
+ const token_js_1 = require("./token.js");
38
+ const types_1 = require("@aeriajs/types");
39
+ const core_1 = require("@phosphor-icons/core");
40
+ const diagnostic_js_1 = require("./diagnostic.js");
41
+ const AST = __importStar(require("./ast.js"));
42
+ const guards = __importStar(require("./guards.js"));
43
+ const lexer = __importStar(require("./lexer.js"));
44
+ const MAX_ERROR_MESSAGE_ITEMS = 20;
45
+ const ICON_NAMES = core_1.icons.map((icon) => icon.name);
46
+ exports.locationMap = new WeakMap();
47
+ const isFileProperty = (property) => {
48
+ return property.$ref === 'File';
49
+ };
50
+ const parse = (tokens) => {
51
+ let index = 0;
52
+ const ast = {
53
+ kind: 'program',
54
+ collections: [],
55
+ contracts: [],
56
+ functionsets: [],
57
+ };
58
+ const errors = [];
59
+ const advance = () => index++;
60
+ const next = () => {
61
+ const token = tokens[index + 1];
62
+ if (!token) {
63
+ throw new diagnostic_js_1.Diagnostic('unexpected EOF', current().location);
64
+ }
65
+ return token;
66
+ };
67
+ const previous = () => {
68
+ const token = tokens[index - 1];
69
+ if (!token) {
70
+ throw new diagnostic_js_1.Diagnostic('invalid position');
71
+ }
72
+ return token;
73
+ };
74
+ const current = () => {
75
+ const token = tokens[index];
76
+ if (!token) {
77
+ throw new diagnostic_js_1.Diagnostic('unexpected EOF', previous().location);
78
+ }
79
+ return token;
80
+ };
81
+ const foldBrackets = () => {
82
+ if (match(token_js_1.TokenType.LeftBracket)) {
83
+ advance();
84
+ while (!match(token_js_1.TokenType.RightBracket)) {
85
+ foldBrackets();
86
+ advance();
87
+ }
88
+ }
89
+ };
90
+ const match = (expected, value) => {
91
+ const token = current();
92
+ if (token.type === expected) {
93
+ if (value !== undefined) {
94
+ return Array.isArray(value)
95
+ ? value.includes(token.value)
96
+ : token.value === value;
97
+ }
98
+ return true;
99
+ }
100
+ return false;
101
+ };
102
+ const consume = (expected, value) => {
103
+ const token = current();
104
+ if (match(expected, value)) {
105
+ advance();
106
+ return token;
107
+ }
108
+ let expectedValue;
109
+ if (value) {
110
+ expectedValue = Array.isArray(value)
111
+ ? value.slice(0, MAX_ERROR_MESSAGE_ITEMS).map((elem) => `"${elem}"`).join(' | ')
112
+ : `"${value}"`;
113
+ }
114
+ if (Array.isArray(value) && value.length > MAX_ERROR_MESSAGE_ITEMS) {
115
+ expectedValue += ' | ...';
116
+ }
117
+ throw new diagnostic_js_1.Diagnostic(expectedValue
118
+ ? `expected ${expected} with value ${expectedValue} but found ${token.type} with value "${token.value}" instead`
119
+ : `expected ${expected} but found ${token.type} instead`, token.location);
120
+ };
121
+ const recover = (keywords) => {
122
+ let token;
123
+ while (token = tokens[++index]) {
124
+ if (token.type === token_js_1.TokenType.Keyword && keywords.includes(token.value)) {
125
+ break;
126
+ }
127
+ }
128
+ };
129
+ const parseArray = (type) => {
130
+ consume(token_js_1.TokenType.LeftSquareBracket);
131
+ const array = [];
132
+ while (!match(token_js_1.TokenType.RightSquareBracket)) {
133
+ const { value } = consume(type);
134
+ array.push(value);
135
+ if (match(token_js_1.TokenType.Comma)) {
136
+ consume(token_js_1.TokenType.Comma);
137
+ }
138
+ }
139
+ consume(token_js_1.TokenType.RightSquareBracket);
140
+ return array;
141
+ };
142
+ const parseArrayBlock = (value) => {
143
+ const array = [];
144
+ const symbols = [];
145
+ consume(token_js_1.TokenType.LeftBracket);
146
+ while (!match(token_js_1.TokenType.RightBracket)) {
147
+ const { value: identifier, location } = consume(token_js_1.TokenType.Identifier, value);
148
+ const elemSymbol = Symbol();
149
+ array.push(identifier);
150
+ symbols.push(elemSymbol);
151
+ exports.locationMap.set(elemSymbol, location);
152
+ }
153
+ consume(token_js_1.TokenType.RightBracket);
154
+ return {
155
+ value: array,
156
+ symbols,
157
+ };
158
+ };
159
+ const parseArrayBlockWithAttributes = () => {
160
+ const array = {};
161
+ let hasAttributes = false;
162
+ consume(token_js_1.TokenType.LeftBracket);
163
+ while (!match(token_js_1.TokenType.RightBracket)) {
164
+ const { value: identifier } = consume(token_js_1.TokenType.Identifier);
165
+ array[identifier] = {};
166
+ while (match(token_js_1.TokenType.AttributeName)) {
167
+ hasAttributes = true;
168
+ const { value: attributeName } = consume(token_js_1.TokenType.AttributeName);
169
+ if (match(token_js_1.TokenType.LeftParens)) {
170
+ consume(token_js_1.TokenType.LeftParens);
171
+ consume(token_js_1.TokenType.RightParens);
172
+ }
173
+ else {
174
+ array[identifier][attributeName] = true;
175
+ }
176
+ }
177
+ }
178
+ consume(token_js_1.TokenType.RightBracket);
179
+ return hasAttributes
180
+ ? array
181
+ : Object.keys(array);
182
+ };
183
+ const parsePropertyAttributeValue = (attributeName, property, location) => {
184
+ const consumeBoolean = () => {
185
+ if (match(token_js_1.TokenType.Boolean)) {
186
+ const { value } = consume(token_js_1.TokenType.Boolean);
187
+ return value;
188
+ }
189
+ return true;
190
+ };
191
+ if ('enum' in property && attributeName === 'values') {
192
+ property.enum = parseArray(token_js_1.TokenType.QuotedString);
193
+ return;
194
+ }
195
+ switch (attributeName) {
196
+ case 'icon': {
197
+ const { value } = consume(token_js_1.TokenType.QuotedString, ICON_NAMES);
198
+ property[attributeName] = value;
199
+ return;
200
+ }
201
+ case 'hint':
202
+ case 'description': {
203
+ const { value } = consume(token_js_1.TokenType.QuotedString);
204
+ property[attributeName] = value;
205
+ return;
206
+ }
207
+ }
208
+ if ('$ref' in property) {
209
+ switch (attributeName) {
210
+ case 'purge':
211
+ case 'inline': {
212
+ property[attributeName] = consumeBoolean();
213
+ return;
214
+ }
215
+ case 'select':
216
+ case 'form':
217
+ case 'populate':
218
+ case 'indexes': {
219
+ property[attributeName] = parseArray(token_js_1.TokenType.Identifier);
220
+ return;
221
+ }
222
+ case 'populateDepth': {
223
+ const { value } = consume(token_js_1.TokenType.Number);
224
+ property[attributeName] = value;
225
+ return;
226
+ }
227
+ }
228
+ if (isFileProperty(property)) {
229
+ switch (attributeName) {
230
+ case 'extensions':
231
+ case 'accept': {
232
+ property[attributeName] = parseArray(token_js_1.TokenType.QuotedString);
233
+ return;
234
+ }
235
+ }
236
+ }
237
+ }
238
+ if ('type' in property) {
239
+ switch (property.type) {
240
+ case 'string': {
241
+ switch (attributeName) {
242
+ case 'format': {
243
+ const { value } = consume(token_js_1.TokenType.QuotedString, types_1.PROPERTY_FORMATS);
244
+ property[attributeName] = value;
245
+ return;
246
+ }
247
+ case 'mask': {
248
+ if (match(token_js_1.TokenType.LeftSquareBracket)) {
249
+ property[attributeName] = parseArray(token_js_1.TokenType.QuotedString);
250
+ return;
251
+ }
252
+ else {
253
+ const { value } = consume(token_js_1.TokenType.QuotedString);
254
+ property[attributeName] = value;
255
+ return;
256
+ }
257
+ }
258
+ case 'maskedValue': {
259
+ const { value } = consume(token_js_1.TokenType.Boolean);
260
+ property[attributeName] = value;
261
+ return;
262
+ }
263
+ case 'minLength':
264
+ case 'maxLength': {
265
+ const { value } = consume(token_js_1.TokenType.Number);
266
+ property[attributeName] = value;
267
+ return;
268
+ }
269
+ case 'inputType': {
270
+ const { value } = consume(token_js_1.TokenType.QuotedString, types_1.PROPERTY_INPUT_TYPES);
271
+ property[attributeName] = value;
272
+ return;
273
+ }
274
+ case 'element': {
275
+ const { value } = consume(token_js_1.TokenType.QuotedString, types_1.PROPERTY_INPUT_ELEMENTS);
276
+ property[attributeName] = value;
277
+ return;
278
+ }
279
+ case 'placeholder': {
280
+ const { value } = consume(token_js_1.TokenType.QuotedString);
281
+ property[attributeName] = value;
282
+ return;
283
+ }
284
+ }
285
+ break;
286
+ }
287
+ case 'integer':
288
+ case 'number': {
289
+ switch (attributeName) {
290
+ case 'exclusiveMinimum':
291
+ case 'exclusiveMaximum':
292
+ case 'minimum':
293
+ case 'maximum': {
294
+ const { value } = consume(token_js_1.TokenType.Number);
295
+ property[attributeName] = value;
296
+ return;
297
+ }
298
+ case 'placeholder': {
299
+ const { value } = consume(token_js_1.TokenType.QuotedString);
300
+ property[attributeName] = value;
301
+ return;
302
+ }
303
+ }
304
+ break;
305
+ }
306
+ case 'array': {
307
+ switch (attributeName) {
308
+ case 'uniqueItems': {
309
+ const { value } = consume(token_js_1.TokenType.Boolean);
310
+ property[attributeName] = value;
311
+ return;
312
+ }
313
+ case 'element': {
314
+ const { value } = consume(token_js_1.TokenType.QuotedString, types_1.PROPERTY_ARRAY_ELEMENTS);
315
+ property[attributeName] = value;
316
+ return;
317
+ }
318
+ }
319
+ }
320
+ }
321
+ }
322
+ throw new diagnostic_js_1.Diagnostic(`invalid attribute name "${attributeName}"`, location);
323
+ };
324
+ const parsePropertyType = (options = {
325
+ allowModifiers: false,
326
+ }) => {
327
+ let property;
328
+ let nestedProperties;
329
+ let modifierToken;
330
+ if (match(token_js_1.TokenType.LeftSquareBracket)) {
331
+ consume(token_js_1.TokenType.LeftSquareBracket);
332
+ const arrayProperty = {
333
+ type: 'array',
334
+ };
335
+ while (!match(token_js_1.TokenType.RightSquareBracket)) {
336
+ const attributeSymbol = Symbol();
337
+ arrayProperty[AST.LOCATION_SYMBOL] ??= {
338
+ attributes: {},
339
+ arrays: {},
340
+ };
341
+ if (match(token_js_1.TokenType.Range)) {
342
+ const { value: rangeSeparator } = consume(token_js_1.TokenType.Range);
343
+ let attributeName;
344
+ const minItems = rangeSeparator[0];
345
+ if (!isNaN(minItems)) {
346
+ attributeName = 'minItems';
347
+ arrayProperty[attributeName] = minItems,
348
+ arrayProperty[AST.LOCATION_SYMBOL].attributes[attributeName] = attributeSymbol;
349
+ }
350
+ const maxItems = rangeSeparator[1];
351
+ if (!isNaN(maxItems)) {
352
+ attributeName = 'maxItems';
353
+ arrayProperty[attributeName] = maxItems;
354
+ arrayProperty[AST.LOCATION_SYMBOL].attributes[attributeName] = attributeSymbol;
355
+ }
356
+ continue;
357
+ }
358
+ const { value: attributeName, location } = consume(token_js_1.TokenType.AttributeName);
359
+ if (match(token_js_1.TokenType.LeftParens)) {
360
+ consume(token_js_1.TokenType.LeftParens);
361
+ exports.locationMap.set(attributeSymbol, next().location);
362
+ arrayProperty[AST.LOCATION_SYMBOL].attributes[attributeName] = attributeSymbol;
363
+ parsePropertyAttributeValue(attributeName, arrayProperty, location);
364
+ consume(token_js_1.TokenType.RightParens);
365
+ }
366
+ else {
367
+ parsePropertyAttributeValue(attributeName, arrayProperty, location);
368
+ }
369
+ }
370
+ consume(token_js_1.TokenType.RightSquareBracket);
371
+ const { property: items, nestedProperties } = parsePropertyType(options);
372
+ property = {
373
+ ...arrayProperty,
374
+ items,
375
+ };
376
+ return {
377
+ kind: 'property',
378
+ property,
379
+ nestedProperties,
380
+ };
381
+ }
382
+ if (options.allowModifiers) {
383
+ const nextToken = next();
384
+ const currentTokenValue = current().value;
385
+ if (match(token_js_1.TokenType.Identifier) && typeof currentTokenValue === 'string' && guards.isValidPropertyModifier(currentTokenValue) && (nextToken.type === token_js_1.TokenType.LeftBracket || nextToken.type === token_js_1.TokenType.Identifier)) {
386
+ modifierToken = consume(token_js_1.TokenType.Identifier);
387
+ }
388
+ }
389
+ if (match(token_js_1.TokenType.LeftBracket)) {
390
+ consume(token_js_1.TokenType.LeftBracket);
391
+ property = {
392
+ type: 'object',
393
+ properties: {},
394
+ [AST.LOCATION_SYMBOL]: {
395
+ attributes: {},
396
+ arrays: {},
397
+ },
398
+ };
399
+ while (!match(token_js_1.TokenType.RightBracket)) {
400
+ const { value: keyword, location } = current();
401
+ switch (keyword) {
402
+ case 'writable':
403
+ case 'required': {
404
+ consume(token_js_1.TokenType.Keyword);
405
+ const { value, symbols } = parseArrayBlock();
406
+ property[keyword] = value;
407
+ property[AST.LOCATION_SYMBOL].arrays[keyword] = symbols;
408
+ break;
409
+ }
410
+ case 'properties': {
411
+ consume(token_js_1.TokenType.Keyword);
412
+ nestedProperties = parsePropertiesBlock(options);
413
+ break;
414
+ }
415
+ default:
416
+ throw new diagnostic_js_1.Diagnostic(`invalid keyword "${keyword}"`, location);
417
+ }
418
+ }
419
+ consume(token_js_1.TokenType.RightBracket);
420
+ }
421
+ else {
422
+ const { value: identifier, location } = consume(token_js_1.TokenType.Identifier);
423
+ if (guards.isNativePropertyType(identifier)) {
424
+ switch (identifier) {
425
+ case 'enum': {
426
+ property = {
427
+ enum: [],
428
+ };
429
+ break;
430
+ }
431
+ case 'date': {
432
+ property = {
433
+ type: 'string',
434
+ format: 'date',
435
+ };
436
+ break;
437
+ }
438
+ case 'datetime': {
439
+ property = {
440
+ type: 'string',
441
+ format: 'date-time',
442
+ };
443
+ break;
444
+ }
445
+ default:
446
+ property = {
447
+ type: AST.PropertyType[identifier],
448
+ };
449
+ }
450
+ }
451
+ else {
452
+ const collection = ast.collections.find((node) => node.name === identifier);
453
+ if (!collection) {
454
+ throw new diagnostic_js_1.Diagnostic(`invalid reference "${identifier}"`, location);
455
+ }
456
+ property = {
457
+ $ref: identifier,
458
+ };
459
+ }
460
+ }
461
+ while (match(token_js_1.TokenType.AttributeName)) {
462
+ const { value: attributeName, location } = consume(token_js_1.TokenType.AttributeName);
463
+ if (match(token_js_1.TokenType.LeftParens)) {
464
+ consume(token_js_1.TokenType.LeftParens);
465
+ const attributeSymbol = Symbol();
466
+ exports.locationMap.set(attributeSymbol, next().location);
467
+ property[AST.LOCATION_SYMBOL] ??= {
468
+ attributes: {},
469
+ arrays: {},
470
+ };
471
+ property[AST.LOCATION_SYMBOL].attributes[attributeName] = attributeSymbol;
472
+ parsePropertyAttributeValue(attributeName, property, location);
473
+ consume(token_js_1.TokenType.RightParens);
474
+ }
475
+ else {
476
+ parsePropertyAttributeValue(attributeName, property, location);
477
+ }
478
+ }
479
+ const node = {
480
+ kind: 'property',
481
+ property,
482
+ nestedProperties,
483
+ };
484
+ if (modifierToken) {
485
+ node.modifier = modifierToken.value;
486
+ }
487
+ return node;
488
+ };
489
+ const parsePropertiesBlock = (options = {
490
+ allowModifiers: false,
491
+ }) => {
492
+ consume(token_js_1.TokenType.LeftBracket);
493
+ const properties = {};
494
+ while (!match(token_js_1.TokenType.RightBracket)) {
495
+ try {
496
+ const { value: propName } = consume(token_js_1.TokenType.Identifier);
497
+ properties[propName] = parsePropertyType(options);
498
+ if (match(token_js_1.TokenType.Comma)) {
499
+ consume(token_js_1.TokenType.Comma);
500
+ }
501
+ }
502
+ catch (err) {
503
+ if (err instanceof diagnostic_js_1.Diagnostic) {
504
+ errors.push(err);
505
+ recoverLoop: for (;;) {
506
+ switch (current().type) {
507
+ case token_js_1.TokenType.RightBracket:
508
+ case token_js_1.TokenType.Identifier: {
509
+ break recoverLoop;
510
+ }
511
+ }
512
+ while (match(token_js_1.TokenType.AttributeName)) {
513
+ advance();
514
+ if (match(token_js_1.TokenType.LeftParens)) {
515
+ advance();
516
+ while (!match(token_js_1.TokenType.RightParens)) {
517
+ advance();
518
+ }
519
+ }
520
+ }
521
+ advance();
522
+ foldBrackets();
523
+ }
524
+ continue;
525
+ }
526
+ }
527
+ }
528
+ consume(token_js_1.TokenType.RightBracket);
529
+ return properties;
530
+ };
531
+ const parseMultiplePropertyTypes = (options = {
532
+ allowModifiers: false,
533
+ }) => {
534
+ if (match(token_js_1.TokenType.Pipe)) {
535
+ consume(token_js_1.TokenType.Pipe);
536
+ const properties = [];
537
+ while (index < tokens.length) {
538
+ properties.push(parsePropertyType(options));
539
+ if (match(token_js_1.TokenType.Pipe)) {
540
+ consume(token_js_1.TokenType.Pipe);
541
+ }
542
+ else {
543
+ break;
544
+ }
545
+ }
546
+ return properties;
547
+ }
548
+ return parsePropertyType(options);
549
+ };
550
+ const parseCollection = (ast) => {
551
+ consume(token_js_1.TokenType.Keyword, 'collection');
552
+ const { value: name } = consume(token_js_1.TokenType.Identifier);
553
+ const node = {
554
+ kind: 'collection',
555
+ name,
556
+ properties: {},
557
+ [AST.LOCATION_SYMBOL]: {
558
+ arrays: {},
559
+ },
560
+ };
561
+ if (match(token_js_1.TokenType.Keyword, 'extends')) {
562
+ consume(token_js_1.TokenType.Keyword);
563
+ const { value: packageName } = consume(token_js_1.TokenType.Identifier);
564
+ consume(token_js_1.TokenType.Dot);
565
+ const { value: symbolName } = consume(token_js_1.TokenType.Identifier);
566
+ node.extends = {
567
+ packageName,
568
+ symbolName: symbolName[0].toLowerCase() + symbolName.slice(1),
569
+ };
570
+ }
571
+ consume(token_js_1.TokenType.LeftBracket);
572
+ while (!match(token_js_1.TokenType.RightBracket)) {
573
+ const { value: keyword } = consume(token_js_1.TokenType.Keyword, lexer.COLLECTION_KEYWORDS);
574
+ try {
575
+ switch (keyword) {
576
+ case 'owned': {
577
+ if (match(token_js_1.TokenType.QuotedString, [
578
+ 'always',
579
+ 'on-write',
580
+ ])) {
581
+ node.owned = consume(token_js_1.TokenType.QuotedString).value;
582
+ }
583
+ break;
584
+ }
585
+ case 'icon': {
586
+ const { value } = consume(token_js_1.TokenType.QuotedString, ICON_NAMES);
587
+ node.icon = value;
588
+ break;
589
+ }
590
+ case 'properties': {
591
+ node.properties = parsePropertiesBlock();
592
+ break;
593
+ }
594
+ case 'functions': {
595
+ node.functions = parseFunctionsBlock(ast);
596
+ break;
597
+ }
598
+ case 'individualActions':
599
+ case 'actions': {
600
+ node[keyword] = parseActionsBlock();
601
+ break;
602
+ }
603
+ case 'required': {
604
+ node.required = parseArrayBlockWithAttributes();
605
+ break;
606
+ }
607
+ case 'presets': {
608
+ const { value, symbols } = parseArrayBlock(types_1.DESCRIPTION_PRESETS);
609
+ node[keyword] = value;
610
+ node[AST.LOCATION_SYMBOL].arrays[keyword] = symbols;
611
+ break;
612
+ }
613
+ case 'indexes':
614
+ case 'form':
615
+ case 'table':
616
+ case 'filters': {
617
+ const { value, symbols } = parseArrayBlock();
618
+ node[keyword] = value;
619
+ node[AST.LOCATION_SYMBOL].arrays[keyword] = symbols;
620
+ break;
621
+ }
622
+ case 'search': {
623
+ node[keyword] = parseSearchBlock();
624
+ break;
625
+ }
626
+ }
627
+ }
628
+ catch (err) {
629
+ if (err instanceof diagnostic_js_1.Diagnostic) {
630
+ errors.push(err);
631
+ recover(lexer.COLLECTION_KEYWORDS);
632
+ continue;
633
+ }
634
+ }
635
+ }
636
+ consume(token_js_1.TokenType.RightBracket);
637
+ return node;
638
+ };
639
+ const parseContract = () => {
640
+ consume(token_js_1.TokenType.Keyword, 'contract');
641
+ const { value: name } = consume(token_js_1.TokenType.Identifier);
642
+ consume(token_js_1.TokenType.LeftBracket);
643
+ const node = {
644
+ kind: 'contract',
645
+ name,
646
+ };
647
+ while (!match(token_js_1.TokenType.RightBracket)) {
648
+ const { value: keyword } = consume(token_js_1.TokenType.Keyword, lexer.CONTRACT_KEYWORDS);
649
+ switch (keyword) {
650
+ case 'payload': {
651
+ node.payload = parsePropertyType({
652
+ allowModifiers: true,
653
+ });
654
+ break;
655
+ }
656
+ case 'query': {
657
+ node.query = parsePropertyType({
658
+ allowModifiers: true,
659
+ });
660
+ break;
661
+ }
662
+ case 'response': {
663
+ node.response = parseMultiplePropertyTypes({
664
+ allowModifiers: true,
665
+ });
666
+ break;
667
+ }
668
+ }
669
+ }
670
+ consume(token_js_1.TokenType.RightBracket);
671
+ return node;
672
+ };
673
+ const parseFunctionsBlock = (ast) => {
674
+ consume(token_js_1.TokenType.LeftBracket);
675
+ const functions = {};
676
+ while (!match(token_js_1.TokenType.RightBracket)) {
677
+ if (match(token_js_1.TokenType.MacroName)) {
678
+ const { value: macroName } = consume(token_js_1.TokenType.MacroName, ['include']);
679
+ switch (macroName) {
680
+ case 'include': {
681
+ const { value: functionSetName, location } = consume(token_js_1.TokenType.Identifier);
682
+ const functionset = ast.functionsets.find((node) => node.name === functionSetName);
683
+ if (!functionset) {
684
+ throw new diagnostic_js_1.Diagnostic(`functionset "${functionSetName}" not found`, location);
685
+ }
686
+ Object.assign(functions, functionset.functions);
687
+ consume(token_js_1.TokenType.RightParens);
688
+ }
689
+ }
690
+ continue;
691
+ }
692
+ const { value: functionName } = consume(token_js_1.TokenType.Identifier);
693
+ functions[functionName] = {
694
+ accessCondition: false,
695
+ };
696
+ while (match(token_js_1.TokenType.AttributeName, 'expose')) {
697
+ consume(token_js_1.TokenType.AttributeName, 'expose');
698
+ if (match(token_js_1.TokenType.LeftParens)) {
699
+ consume(token_js_1.TokenType.LeftParens);
700
+ if (match(token_js_1.TokenType.Boolean)) {
701
+ const { value } = consume(token_js_1.TokenType.Boolean);
702
+ functions[functionName] = {
703
+ accessCondition: value,
704
+ };
705
+ }
706
+ else if (match(token_js_1.TokenType.QuotedString, [
707
+ 'unauthenticated',
708
+ 'unauthenticated-only',
709
+ ])) {
710
+ const { value } = consume(token_js_1.TokenType.QuotedString, [
711
+ 'unauthenticated',
712
+ 'unauthenticated-only',
713
+ ]);
714
+ functions[functionName] = {
715
+ accessCondition: value,
716
+ };
717
+ }
718
+ else {
719
+ const value = parseArray(token_js_1.TokenType.QuotedString);
720
+ functions[functionName] = {
721
+ accessCondition: value,
722
+ };
723
+ }
724
+ consume(token_js_1.TokenType.RightParens);
725
+ }
726
+ else {
727
+ functions[functionName] = {
728
+ accessCondition: true,
729
+ };
730
+ }
731
+ }
732
+ }
733
+ consume(token_js_1.TokenType.RightBracket);
734
+ return functions;
735
+ };
736
+ const parseFunctionSet = (ast) => {
737
+ consume(token_js_1.TokenType.Keyword, 'functionset');
738
+ const { value: name } = consume(token_js_1.TokenType.Identifier);
739
+ const node = {
740
+ kind: 'functionset',
741
+ name,
742
+ functions: parseFunctionsBlock(ast),
743
+ };
744
+ return node;
745
+ };
746
+ const parseActionsBlock = () => {
747
+ const actions = {};
748
+ consume(token_js_1.TokenType.LeftBracket);
749
+ while (!match(token_js_1.TokenType.RightBracket)) {
750
+ const { value: actionName } = consume(token_js_1.TokenType.Identifier);
751
+ consume(token_js_1.TokenType.LeftBracket);
752
+ const baseSlots = {};
753
+ const slots = {
754
+ route: {
755
+ route: {
756
+ name: '',
757
+ },
758
+ },
759
+ function: {},
760
+ event: {},
761
+ };
762
+ let actionType;
763
+ while (!match(token_js_1.TokenType.RightBracket)) {
764
+ const { value: keyword } = consume(token_js_1.TokenType.Keyword, lexer.COLLECTION_ACTIONS_KEYWORDS);
765
+ switch (keyword) {
766
+ case 'icon': {
767
+ const { value } = consume(token_js_1.TokenType.QuotedString, ICON_NAMES);
768
+ baseSlots[keyword] = value;
769
+ break;
770
+ }
771
+ case 'label': {
772
+ const { value } = consume(token_js_1.TokenType.QuotedString);
773
+ baseSlots[keyword] = value;
774
+ break;
775
+ }
776
+ case 'ask':
777
+ case 'button':
778
+ case 'translate': {
779
+ const { value } = consume(token_js_1.TokenType.Boolean);
780
+ baseSlots[keyword] = value;
781
+ break;
782
+ }
783
+ case 'roles':
784
+ case 'requires': {
785
+ const value = parseArray(token_js_1.TokenType.Identifier);
786
+ baseSlots[keyword] = value;
787
+ break;
788
+ }
789
+ case 'route': {
790
+ const { value } = consume(token_js_1.TokenType.QuotedString);
791
+ actionType = 'route';
792
+ slots.route.route.name = value;
793
+ break;
794
+ }
795
+ case 'setItem':
796
+ case 'fetchItem':
797
+ case 'clearItem': {
798
+ const { value } = consume(token_js_1.TokenType.Boolean);
799
+ slots.route.route[keyword] = value;
800
+ break;
801
+ }
802
+ case 'function': {
803
+ const { value } = consume(token_js_1.TokenType.QuotedString);
804
+ actionType = 'function';
805
+ slots.function.function = value;
806
+ break;
807
+ }
808
+ case 'effect': {
809
+ const { value } = consume(token_js_1.TokenType.QuotedString);
810
+ slots.function.effect = value;
811
+ break;
812
+ }
813
+ case 'selection': {
814
+ const { value } = consume(token_js_1.TokenType.Boolean);
815
+ slots.function.selection = value;
816
+ break;
817
+ }
818
+ case 'event': {
819
+ const { value } = consume(token_js_1.TokenType.QuotedString);
820
+ actionType = 'event';
821
+ slots.event.event = value;
822
+ break;
823
+ }
824
+ }
825
+ }
826
+ if (actionType) {
827
+ actions[actionName] = {
828
+ ...baseSlots,
829
+ ...slots[actionType],
830
+ };
831
+ }
832
+ else {
833
+ actions[actionName] = baseSlots;
834
+ }
835
+ consume(token_js_1.TokenType.RightBracket);
836
+ }
837
+ consume(token_js_1.TokenType.RightBracket);
838
+ return actions;
839
+ };
840
+ const parseSearchBlock = () => {
841
+ const searchSlots = {};
842
+ const { location } = consume(token_js_1.TokenType.LeftBracket);
843
+ while (!match(token_js_1.TokenType.RightBracket)) {
844
+ const { value: keyword } = consume(token_js_1.TokenType.Keyword, lexer.COLLECTION_SEARCH_KEYWORDS);
845
+ switch (keyword) {
846
+ case 'placeholder': {
847
+ const { value } = consume(token_js_1.TokenType.QuotedString);
848
+ searchSlots[keyword] = value;
849
+ break;
850
+ }
851
+ case 'exactMatches': {
852
+ const { value } = consume(token_js_1.TokenType.Boolean);
853
+ searchSlots[keyword] = value;
854
+ break;
855
+ }
856
+ case 'indexes': {
857
+ const { value } = parseArrayBlock();
858
+ searchSlots[keyword] = value;
859
+ break;
860
+ }
861
+ }
862
+ }
863
+ const { indexes } = searchSlots;
864
+ if (!indexes) {
865
+ throw new diagnostic_js_1.Diagnostic('"indexes" option is required', location);
866
+ }
867
+ consume(token_js_1.TokenType.RightBracket);
868
+ return {
869
+ ...searchSlots,
870
+ indexes,
871
+ };
872
+ };
873
+ while (index < tokens.length) {
874
+ const { value: declType, location } = current();
875
+ try {
876
+ switch (declType) {
877
+ case 'collection': {
878
+ ast.collections.push(parseCollection(ast));
879
+ break;
880
+ }
881
+ case 'contract': {
882
+ ast.contracts.push(parseContract());
883
+ break;
884
+ }
885
+ case 'functionset': {
886
+ ast.functionsets.push(parseFunctionSet(ast));
887
+ break;
888
+ }
889
+ default:
890
+ throw new diagnostic_js_1.Diagnostic(`invalid declaration type: "${declType}"`, location);
891
+ }
892
+ }
893
+ catch (err) {
894
+ if (err instanceof diagnostic_js_1.Diagnostic) {
895
+ errors.push(err);
896
+ recover(lexer.TOPLEVEL_KEYWORDS);
897
+ continue;
898
+ }
899
+ throw err;
900
+ }
901
+ }
902
+ return {
903
+ ast,
904
+ errors,
905
+ };
906
+ };
907
+ exports.parse = parse;