@aeriajs/compiler 0.0.11 → 0.0.14

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.
@@ -53,6 +53,9 @@ const makeJSContractsCode = (contractAst) => {
53
53
  [utils_js_1.UnquotedSymbol]: responseString,
54
54
  };
55
55
  }
56
+ if (roles) {
57
+ contractSchema.roles = roles;
58
+ }
56
59
  return `export const ${name} = defineContract(${(0, utils_js_1.stringify)(contractSchema)})`;
57
60
  }).join('\n\n');
58
61
  return `import { ${Array.from(imports).join(', ')} } from \'aeria\'\n\n` + declarations;
@@ -79,11 +82,12 @@ const makeTSContractsCode = (contractAst) => {
79
82
  }
80
83
  }
81
84
  const contractProperties = (0, utils_js_1.getProperties)(contractSchema);
82
- return `export declare const ${contractNode.name}: ${(0, utils_js_1.stringify)({
83
- ...contractProperties,
84
- ...(responseSchema && {
85
- response: responseSchema,
86
- }),
87
- })}`;
85
+ if (responseSchema) {
86
+ contractProperties.response = responseSchema;
87
+ }
88
+ if (roles) {
89
+ contractProperties.roles = roles;
90
+ }
91
+ return `export declare const ${contractNode.name}: ${(0, utils_js_1.stringify)(contractProperties)}`;
88
92
  }).join('\n\n');
89
93
  };
@@ -47,6 +47,9 @@ const makeJSContractsCode = (contractAst) => {
47
47
  [UnquotedSymbol]: responseString
48
48
  };
49
49
  }
50
+ if (roles) {
51
+ contractSchema.roles = roles;
52
+ }
50
53
  return `export const ${name} = defineContract(${stringify(contractSchema)})`;
51
54
  }).join("\n\n");
52
55
  return `import { ${Array.from(imports).join(", ")} } from 'aeria'
@@ -72,11 +75,12 @@ const makeTSContractsCode = (contractAst) => {
72
75
  }
73
76
  }
74
77
  const contractProperties = getProperties(contractSchema);
75
- return `export declare const ${contractNode.name}: ${stringify({
76
- ...contractProperties,
77
- ...responseSchema && {
78
- response: responseSchema
79
- }
80
- })}`;
78
+ if (responseSchema) {
79
+ contractProperties.response = responseSchema;
80
+ }
81
+ if (roles) {
82
+ contractProperties.roles = roles;
83
+ }
84
+ return `export declare const ${contractNode.name}: ${stringify(contractProperties)}`;
81
85
  }).join("\n\n");
82
86
  };
package/dist/compile.js CHANGED
@@ -99,7 +99,7 @@ const compileFromFiles = async (schemaDir, options) => {
99
99
  });
100
100
  }
101
101
  const result = await (0, exports.parseAndCheck)(sources, options);
102
- if (!result.ast) {
102
+ if (!result.ast || result.errorCount > 0) {
103
103
  return result;
104
104
  }
105
105
  const emittedFiles = await (0, codegen_js_1.generateCode)(result.ast, options);
package/dist/compile.mjs CHANGED
@@ -59,7 +59,7 @@ export const compileFromFiles = async (schemaDir, options) => {
59
59
  });
60
60
  }
61
61
  const result = await parseAndCheck(sources, options);
62
- if (!result.ast) {
62
+ if (!result.ast || result.errorCount > 0) {
63
63
  return result;
64
64
  }
65
65
  const emittedFiles = await generateCode(result.ast, options);
package/dist/lexer.d.ts CHANGED
@@ -4,7 +4,7 @@ export type Keyword = typeof COLLECTION_KEYWORDS[number] | typeof COLLECTION_ACT
4
4
  export declare const COLLECTION_KEYWORDS: readonly ["actions", "filters", "form", "functions", "icon", "indexes", "individualActions", "owned", "presets", "properties", "required", "search", "table"];
5
5
  export declare const COLLECTION_ACTIONS_KEYWORDS: readonly ["ask", "button", "clearItem", "effect", "event", "fetchItem", "function", "icon", "label", "params", "query", "requires", "roles", "route", "selection", "setItem", "translate"];
6
6
  export declare const COLLECTION_SEARCH_KEYWORDS: readonly ["indexes", "placeholder", "exactMatches"];
7
- export declare const CONTRACT_KEYWORDS: readonly ["payload", "query", "response"];
7
+ export declare const CONTRACT_KEYWORDS: readonly ["roles", "payload", "query", "response"];
8
8
  export declare const TOPLEVEL_KEYWORDS: readonly ["collection", "contract", "functionset"];
9
9
  export declare const MISC_KEYWORDS: readonly ["extends"];
10
10
  export declare const KEYWORDS: Keyword[];
package/dist/lexer.js CHANGED
@@ -43,6 +43,7 @@ exports.COLLECTION_SEARCH_KEYWORDS = [
43
43
  'exactMatches',
44
44
  ];
45
45
  exports.CONTRACT_KEYWORDS = [
46
+ 'roles',
46
47
  'payload',
47
48
  'query',
48
49
  'response',
package/dist/lexer.mjs CHANGED
@@ -41,6 +41,7 @@ export const COLLECTION_SEARCH_KEYWORDS = [
41
41
  "exactMatches"
42
42
  ];
43
43
  export const CONTRACT_KEYWORDS = [
44
+ "roles",
44
45
  "payload",
45
46
  "query",
46
47
  "response"
package/dist/parser.d.ts CHANGED
@@ -2,6 +2,9 @@ import { type Token, type Location } from './token.js';
2
2
  import { Diagnostic } from './diagnostic.js';
3
3
  import * as AST from './ast.js';
4
4
  export declare const locationMap: WeakMap<symbol, Location>;
5
+ export declare const memoTable: {
6
+ roles?: string[];
7
+ };
5
8
  export declare const parse: (tokens: (Token | undefined)[]) => {
6
9
  ast: AST.ProgramNode;
7
10
  errors: Diagnostic[];
package/dist/parser.js CHANGED
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.parse = exports.locationMap = void 0;
36
+ exports.parse = exports.memoTable = exports.locationMap = void 0;
37
37
  const token_js_1 = require("./token.js");
38
38
  const types_1 = require("@aeriajs/types");
39
39
  const core_1 = require("@phosphor-icons/core");
@@ -44,9 +44,22 @@ const lexer = __importStar(require("./lexer.js"));
44
44
  const MAX_ERROR_MESSAGE_ITEMS = 20;
45
45
  const ICON_NAMES = core_1.icons.map((icon) => icon.name);
46
46
  exports.locationMap = new WeakMap();
47
+ exports.memoTable = {};
47
48
  const isFileProperty = (property) => {
48
49
  return property.$ref === 'File';
49
50
  };
51
+ const checkForValidRoles = (roles, symbols) => {
52
+ if (exports.memoTable.roles) {
53
+ for (const [i, role] of roles.entries()) {
54
+ const symbol = symbols[i];
55
+ if (!exports.memoTable.roles.includes(role)) {
56
+ const location = exports.locationMap.get(symbol);
57
+ throw new diagnostic_js_1.Diagnostic(`invalid role "${role}"`, location);
58
+ }
59
+ }
60
+ }
61
+ return roles;
62
+ };
50
63
  const parse = (tokens) => {
51
64
  let index = 0;
52
65
  const ast = {
@@ -127,8 +140,9 @@ const parse = (tokens) => {
127
140
  }
128
141
  };
129
142
  const parseArray = (types) => {
130
- const { location } = consume(token_js_1.TokenType.LeftSquareBracket);
143
+ const { location: openingLocation } = consume(token_js_1.TokenType.LeftSquareBracket);
131
144
  const array = [];
145
+ const symbols = [];
132
146
  let type;
133
147
  for (const typeCandidate of types) {
134
148
  if (match(typeCandidate)) {
@@ -137,17 +151,23 @@ const parse = (tokens) => {
137
151
  }
138
152
  }
139
153
  if (!type) {
140
- throw new diagnostic_js_1.Diagnostic(`array got an invalid type, accepted ones are: ${types.join(' | ')}`, location);
154
+ throw new diagnostic_js_1.Diagnostic(`array got an invalid type, accepted ones are: ${types.join(' | ')}`, openingLocation);
141
155
  }
142
156
  while (!match(token_js_1.TokenType.RightSquareBracket)) {
143
- const { value } = consume(type);
157
+ const { value, location } = consume(type);
158
+ const elemSymbol = Symbol();
144
159
  array.push(value);
160
+ symbols.push(elemSymbol);
161
+ exports.locationMap.set(elemSymbol, location);
145
162
  if (match(token_js_1.TokenType.Comma)) {
146
163
  consume(token_js_1.TokenType.Comma);
147
164
  }
148
165
  }
149
166
  consume(token_js_1.TokenType.RightSquareBracket);
150
- return array;
167
+ return {
168
+ value: array,
169
+ symbols,
170
+ };
151
171
  };
152
172
  const parseArrayBlock = (value) => {
153
173
  const array = [];
@@ -202,7 +222,7 @@ const parse = (tokens) => {
202
222
  property.enum = parseArray([
203
223
  token_js_1.TokenType.QuotedString,
204
224
  token_js_1.TokenType.Number,
205
- ]);
225
+ ]).value;
206
226
  return;
207
227
  }
208
228
  switch (attributeName) {
@@ -229,7 +249,7 @@ const parse = (tokens) => {
229
249
  case 'form':
230
250
  case 'populate':
231
251
  case 'indexes': {
232
- property[attributeName] = parseArray([token_js_1.TokenType.Identifier]);
252
+ property[attributeName] = parseArray([token_js_1.TokenType.Identifier]).value;
233
253
  return;
234
254
  }
235
255
  case 'populateDepth': {
@@ -242,7 +262,7 @@ const parse = (tokens) => {
242
262
  switch (attributeName) {
243
263
  case 'extensions':
244
264
  case 'accept': {
245
- property[attributeName] = parseArray([token_js_1.TokenType.QuotedString]);
265
+ property[attributeName] = parseArray([token_js_1.TokenType.QuotedString]).value;
246
266
  return;
247
267
  }
248
268
  }
@@ -259,7 +279,7 @@ const parse = (tokens) => {
259
279
  }
260
280
  case 'mask': {
261
281
  if (match(token_js_1.TokenType.LeftSquareBracket)) {
262
- property[attributeName] = parseArray([token_js_1.TokenType.QuotedString]);
282
+ property[attributeName] = parseArray([token_js_1.TokenType.QuotedString]).value;
263
283
  return;
264
284
  }
265
285
  else {
@@ -560,6 +580,30 @@ const parse = (tokens) => {
560
580
  }
561
581
  return parsePropertyType(options);
562
582
  };
583
+ const parseAccessCondition = (options = {
584
+ arrayBlock: false,
585
+ }) => {
586
+ if (match(token_js_1.TokenType.Boolean)) {
587
+ const { value } = consume(token_js_1.TokenType.Boolean);
588
+ return value;
589
+ }
590
+ else if (match(token_js_1.TokenType.QuotedString, [
591
+ 'unauthenticated',
592
+ 'unauthenticated-only',
593
+ ])) {
594
+ const { value } = consume(token_js_1.TokenType.QuotedString, [
595
+ 'unauthenticated',
596
+ 'unauthenticated-only',
597
+ ]);
598
+ return value;
599
+ }
600
+ else {
601
+ const { value, symbols } = options.arrayBlock
602
+ ? parseArrayBlock()
603
+ : parseArray([token_js_1.TokenType.QuotedString]);
604
+ return checkForValidRoles(value, symbols);
605
+ }
606
+ };
563
607
  const parseCollection = (ast) => {
564
608
  consume(token_js_1.TokenType.Keyword, 'collection');
565
609
  const { value: name } = consume(token_js_1.TokenType.Identifier);
@@ -597,15 +641,15 @@ const parse = (tokens) => {
597
641
  }
598
642
  case 'icon': {
599
643
  const { value } = consume(token_js_1.TokenType.QuotedString, ICON_NAMES);
600
- node.icon = value;
644
+ node[keyword] = value;
601
645
  break;
602
646
  }
603
647
  case 'properties': {
604
- node.properties = parsePropertiesBlock();
648
+ node[keyword] = parsePropertiesBlock();
605
649
  break;
606
650
  }
607
651
  case 'functions': {
608
- node.functions = parseFunctionsBlock(ast);
652
+ node[keyword] = parseFunctionsBlock(ast);
609
653
  break;
610
654
  }
611
655
  case 'individualActions':
@@ -660,6 +704,12 @@ const parse = (tokens) => {
660
704
  while (!match(token_js_1.TokenType.RightBracket)) {
661
705
  const { value: keyword } = consume(token_js_1.TokenType.Keyword, lexer.CONTRACT_KEYWORDS);
662
706
  switch (keyword) {
707
+ case 'roles': {
708
+ node.roles = parseAccessCondition({
709
+ arrayBlock: true,
710
+ });
711
+ break;
712
+ }
663
713
  case 'payload': {
664
714
  node.payload = parsePropertyType({
665
715
  allowModifiers: true,
@@ -687,59 +737,52 @@ const parse = (tokens) => {
687
737
  consume(token_js_1.TokenType.LeftBracket);
688
738
  const functions = {};
689
739
  while (!match(token_js_1.TokenType.RightBracket)) {
690
- if (match(token_js_1.TokenType.MacroName)) {
691
- const { value: macroName } = consume(token_js_1.TokenType.MacroName, ['include']);
692
- switch (macroName) {
693
- case 'include': {
694
- const { value: functionSetName, location } = consume(token_js_1.TokenType.Identifier);
695
- const functionset = ast.functionsets.find((node) => node.name === functionSetName);
696
- if (!functionset) {
697
- throw new diagnostic_js_1.Diagnostic(`functionset "${functionSetName}" not found`, location);
740
+ try {
741
+ if (match(token_js_1.TokenType.MacroName)) {
742
+ const { value: macroName } = consume(token_js_1.TokenType.MacroName, ['include']);
743
+ switch (macroName) {
744
+ case 'include': {
745
+ const { value: functionSetName, location } = consume(token_js_1.TokenType.Identifier);
746
+ const functionset = ast.functionsets.find((node) => node.name === functionSetName);
747
+ if (!functionset) {
748
+ throw new diagnostic_js_1.Diagnostic(`functionset "${functionSetName}" not found`, location);
749
+ }
750
+ Object.assign(functions, functionset.functions);
751
+ consume(token_js_1.TokenType.RightParens);
698
752
  }
699
- Object.assign(functions, functionset.functions);
700
- consume(token_js_1.TokenType.RightParens);
701
753
  }
754
+ continue;
702
755
  }
703
- continue;
704
- }
705
- const { value: functionName } = consume(token_js_1.TokenType.Identifier);
706
- functions[functionName] = {
707
- accessCondition: false,
708
- };
709
- while (match(token_js_1.TokenType.AttributeName, 'expose')) {
710
- consume(token_js_1.TokenType.AttributeName, 'expose');
711
- if (match(token_js_1.TokenType.LeftParens)) {
712
- consume(token_js_1.TokenType.LeftParens);
713
- if (match(token_js_1.TokenType.Boolean)) {
714
- const { value } = consume(token_js_1.TokenType.Boolean);
715
- functions[functionName] = {
716
- accessCondition: value,
717
- };
718
- }
719
- else if (match(token_js_1.TokenType.QuotedString, [
720
- 'unauthenticated',
721
- 'unauthenticated-only',
722
- ])) {
723
- const { value } = consume(token_js_1.TokenType.QuotedString, [
724
- 'unauthenticated',
725
- 'unauthenticated-only',
726
- ]);
756
+ const { value: functionName } = consume(token_js_1.TokenType.Identifier);
757
+ functions[functionName] = {
758
+ accessCondition: false,
759
+ };
760
+ while (match(token_js_1.TokenType.AttributeName, 'expose')) {
761
+ consume(token_js_1.TokenType.AttributeName, 'expose');
762
+ if (match(token_js_1.TokenType.LeftParens)) {
763
+ consume(token_js_1.TokenType.LeftParens);
727
764
  functions[functionName] = {
728
- accessCondition: value,
765
+ accessCondition: parseAccessCondition(),
729
766
  };
767
+ consume(token_js_1.TokenType.RightParens);
730
768
  }
731
769
  else {
732
- const value = parseArray([token_js_1.TokenType.QuotedString]);
733
770
  functions[functionName] = {
734
- accessCondition: value,
771
+ accessCondition: true,
735
772
  };
736
773
  }
737
- consume(token_js_1.TokenType.RightParens);
738
774
  }
739
- else {
740
- functions[functionName] = {
741
- accessCondition: true,
742
- };
775
+ }
776
+ catch (err) {
777
+ if (err instanceof diagnostic_js_1.Diagnostic) {
778
+ let token;
779
+ while (token = tokens[++index]) {
780
+ if (token.type === token_js_1.TokenType.Identifier || token.type === token_js_1.TokenType.RightBracket) {
781
+ break;
782
+ }
783
+ }
784
+ errors.push(err);
785
+ continue;
743
786
  }
744
787
  }
745
788
  }
@@ -793,9 +836,14 @@ const parse = (tokens) => {
793
836
  baseSlots[keyword] = value;
794
837
  break;
795
838
  }
796
- case 'roles':
839
+ case 'roles': {
840
+ const { value, symbols } = parseArray([token_js_1.TokenType.Identifier]);
841
+ const roles = checkForValidRoles(value, symbols);
842
+ baseSlots[keyword] = roles;
843
+ break;
844
+ }
797
845
  case 'requires': {
798
- const value = parseArray([token_js_1.TokenType.Identifier]);
846
+ const { value } = parseArray([token_js_1.TokenType.Identifier]);
799
847
  baseSlots[keyword] = value;
800
848
  break;
801
849
  }
@@ -888,7 +936,14 @@ const parse = (tokens) => {
888
936
  try {
889
937
  switch (declType) {
890
938
  case 'collection': {
891
- ast.collections.push(parseCollection(ast));
939
+ const collection = parseCollection(ast);
940
+ if (collection.name === 'User') {
941
+ const { properties } = collection;
942
+ if ('roles' in properties && 'items' in properties.roles.property && 'enum' in properties.roles.property.items) {
943
+ exports.memoTable.roles = properties.roles.property.items.enum;
944
+ }
945
+ }
946
+ ast.collections.push(collection);
892
947
  break;
893
948
  }
894
949
  case 'contract': {
package/dist/parser.mjs CHANGED
@@ -9,9 +9,22 @@ import * as lexer from "./lexer.mjs";
9
9
  const MAX_ERROR_MESSAGE_ITEMS = 20;
10
10
  const ICON_NAMES = icons.map((icon) => icon.name);
11
11
  export const locationMap = /* @__PURE__ */ new WeakMap();
12
+ export const memoTable = {};
12
13
  const isFileProperty = (property) => {
13
14
  return property.$ref === "File";
14
15
  };
16
+ const checkForValidRoles = (roles, symbols) => {
17
+ if (memoTable.roles) {
18
+ for (const [i, role] of roles.entries()) {
19
+ const symbol = symbols[i];
20
+ if (!memoTable.roles.includes(role)) {
21
+ const location = locationMap.get(symbol);
22
+ throw new Diagnostic(`invalid role "${role}"`, location);
23
+ }
24
+ }
25
+ }
26
+ return roles;
27
+ };
15
28
  export const parse = (tokens) => {
16
29
  let index = 0;
17
30
  const ast = {
@@ -89,8 +102,9 @@ export const parse = (tokens) => {
89
102
  }
90
103
  };
91
104
  const parseArray = (types) => {
92
- const { location } = consume(TokenType.LeftSquareBracket);
105
+ const { location: openingLocation } = consume(TokenType.LeftSquareBracket);
93
106
  const array = [];
107
+ const symbols = [];
94
108
  let type;
95
109
  for (const typeCandidate of types) {
96
110
  if (match(typeCandidate)) {
@@ -99,17 +113,23 @@ export const parse = (tokens) => {
99
113
  }
100
114
  }
101
115
  if (!type) {
102
- throw new Diagnostic(`array got an invalid type, accepted ones are: ${types.join(" | ")}`, location);
116
+ throw new Diagnostic(`array got an invalid type, accepted ones are: ${types.join(" | ")}`, openingLocation);
103
117
  }
104
118
  while (!match(TokenType.RightSquareBracket)) {
105
- const { value } = consume(type);
119
+ const { value, location } = consume(type);
120
+ const elemSymbol = Symbol();
106
121
  array.push(value);
122
+ symbols.push(elemSymbol);
123
+ locationMap.set(elemSymbol, location);
107
124
  if (match(TokenType.Comma)) {
108
125
  consume(TokenType.Comma);
109
126
  }
110
127
  }
111
128
  consume(TokenType.RightSquareBracket);
112
- return array;
129
+ return {
130
+ value: array,
131
+ symbols
132
+ };
113
133
  };
114
134
  const parseArrayBlock = (value) => {
115
135
  const array = [];
@@ -161,7 +181,7 @@ export const parse = (tokens) => {
161
181
  property.enum = parseArray([
162
182
  TokenType.QuotedString,
163
183
  TokenType.Number
164
- ]);
184
+ ]).value;
165
185
  return;
166
186
  }
167
187
  switch (attributeName) {
@@ -188,7 +208,7 @@ export const parse = (tokens) => {
188
208
  case "form":
189
209
  case "populate":
190
210
  case "indexes": {
191
- property[attributeName] = parseArray([TokenType.Identifier]);
211
+ property[attributeName] = parseArray([TokenType.Identifier]).value;
192
212
  return;
193
213
  }
194
214
  case "populateDepth": {
@@ -201,7 +221,7 @@ export const parse = (tokens) => {
201
221
  switch (attributeName) {
202
222
  case "extensions":
203
223
  case "accept": {
204
- property[attributeName] = parseArray([TokenType.QuotedString]);
224
+ property[attributeName] = parseArray([TokenType.QuotedString]).value;
205
225
  return;
206
226
  }
207
227
  }
@@ -218,7 +238,7 @@ export const parse = (tokens) => {
218
238
  }
219
239
  case "mask": {
220
240
  if (match(TokenType.LeftSquareBracket)) {
221
- property[attributeName] = parseArray([TokenType.QuotedString]);
241
+ property[attributeName] = parseArray([TokenType.QuotedString]).value;
222
242
  return;
223
243
  } else {
224
244
  const { value } = consume(TokenType.QuotedString);
@@ -511,6 +531,26 @@ export const parse = (tokens) => {
511
531
  }
512
532
  return parsePropertyType(options);
513
533
  };
534
+ const parseAccessCondition = (options = {
535
+ arrayBlock: false
536
+ }) => {
537
+ if (match(TokenType.Boolean)) {
538
+ const { value } = consume(TokenType.Boolean);
539
+ return value;
540
+ } else if (match(TokenType.QuotedString, [
541
+ "unauthenticated",
542
+ "unauthenticated-only"
543
+ ])) {
544
+ const { value } = consume(TokenType.QuotedString, [
545
+ "unauthenticated",
546
+ "unauthenticated-only"
547
+ ]);
548
+ return value;
549
+ } else {
550
+ const { value, symbols } = options.arrayBlock ? parseArrayBlock() : parseArray([TokenType.QuotedString]);
551
+ return checkForValidRoles(value, symbols);
552
+ }
553
+ };
514
554
  const parseCollection = (ast2) => {
515
555
  consume(TokenType.Keyword, "collection");
516
556
  const { value: name } = consume(TokenType.Identifier);
@@ -548,15 +588,15 @@ export const parse = (tokens) => {
548
588
  }
549
589
  case "icon": {
550
590
  const { value } = consume(TokenType.QuotedString, ICON_NAMES);
551
- node.icon = value;
591
+ node[keyword] = value;
552
592
  break;
553
593
  }
554
594
  case "properties": {
555
- node.properties = parsePropertiesBlock();
595
+ node[keyword] = parsePropertiesBlock();
556
596
  break;
557
597
  }
558
598
  case "functions": {
559
- node.functions = parseFunctionsBlock(ast2);
599
+ node[keyword] = parseFunctionsBlock(ast2);
560
600
  break;
561
601
  }
562
602
  case "individualActions":
@@ -610,6 +650,12 @@ export const parse = (tokens) => {
610
650
  while (!match(TokenType.RightBracket)) {
611
651
  const { value: keyword } = consume(TokenType.Keyword, lexer.CONTRACT_KEYWORDS);
612
652
  switch (keyword) {
653
+ case "roles": {
654
+ node.roles = parseAccessCondition({
655
+ arrayBlock: true
656
+ });
657
+ break;
658
+ }
613
659
  case "payload": {
614
660
  node.payload = parsePropertyType({
615
661
  allowModifiers: true
@@ -637,56 +683,50 @@ export const parse = (tokens) => {
637
683
  consume(TokenType.LeftBracket);
638
684
  const functions = {};
639
685
  while (!match(TokenType.RightBracket)) {
640
- if (match(TokenType.MacroName)) {
641
- const { value: macroName } = consume(TokenType.MacroName, ["include"]);
642
- switch (macroName) {
643
- case "include": {
644
- const { value: functionSetName, location } = consume(TokenType.Identifier);
645
- const functionset = ast2.functionsets.find((node) => node.name === functionSetName);
646
- if (!functionset) {
647
- throw new Diagnostic(`functionset "${functionSetName}" not found`, location);
686
+ try {
687
+ if (match(TokenType.MacroName)) {
688
+ const { value: macroName } = consume(TokenType.MacroName, ["include"]);
689
+ switch (macroName) {
690
+ case "include": {
691
+ const { value: functionSetName, location } = consume(TokenType.Identifier);
692
+ const functionset = ast2.functionsets.find((node) => node.name === functionSetName);
693
+ if (!functionset) {
694
+ throw new Diagnostic(`functionset "${functionSetName}" not found`, location);
695
+ }
696
+ Object.assign(functions, functionset.functions);
697
+ consume(TokenType.RightParens);
648
698
  }
649
- Object.assign(functions, functionset.functions);
650
- consume(TokenType.RightParens);
651
699
  }
700
+ continue;
652
701
  }
653
- continue;
654
- }
655
- const { value: functionName } = consume(TokenType.Identifier);
656
- functions[functionName] = {
657
- accessCondition: false
658
- };
659
- while (match(TokenType.AttributeName, "expose")) {
660
- consume(TokenType.AttributeName, "expose");
661
- if (match(TokenType.LeftParens)) {
662
- consume(TokenType.LeftParens);
663
- if (match(TokenType.Boolean)) {
664
- const { value } = consume(TokenType.Boolean);
665
- functions[functionName] = {
666
- accessCondition: value
667
- };
668
- } else if (match(TokenType.QuotedString, [
669
- "unauthenticated",
670
- "unauthenticated-only"
671
- ])) {
672
- const { value } = consume(TokenType.QuotedString, [
673
- "unauthenticated",
674
- "unauthenticated-only"
675
- ]);
702
+ const { value: functionName } = consume(TokenType.Identifier);
703
+ functions[functionName] = {
704
+ accessCondition: false
705
+ };
706
+ while (match(TokenType.AttributeName, "expose")) {
707
+ consume(TokenType.AttributeName, "expose");
708
+ if (match(TokenType.LeftParens)) {
709
+ consume(TokenType.LeftParens);
676
710
  functions[functionName] = {
677
- accessCondition: value
711
+ accessCondition: parseAccessCondition()
678
712
  };
713
+ consume(TokenType.RightParens);
679
714
  } else {
680
- const value = parseArray([TokenType.QuotedString]);
681
715
  functions[functionName] = {
682
- accessCondition: value
716
+ accessCondition: true
683
717
  };
684
718
  }
685
- consume(TokenType.RightParens);
686
- } else {
687
- functions[functionName] = {
688
- accessCondition: true
689
- };
719
+ }
720
+ } catch (err) {
721
+ if (err instanceof Diagnostic) {
722
+ let token;
723
+ while (token = tokens[++index]) {
724
+ if (token.type === TokenType.Identifier || token.type === TokenType.RightBracket) {
725
+ break;
726
+ }
727
+ }
728
+ errors.push(err);
729
+ continue;
690
730
  }
691
731
  }
692
732
  }
@@ -740,9 +780,14 @@ export const parse = (tokens) => {
740
780
  baseSlots[keyword] = value;
741
781
  break;
742
782
  }
743
- case "roles":
783
+ case "roles": {
784
+ const { value, symbols } = parseArray([TokenType.Identifier]);
785
+ const roles = checkForValidRoles(value, symbols);
786
+ baseSlots[keyword] = roles;
787
+ break;
788
+ }
744
789
  case "requires": {
745
- const value = parseArray([TokenType.Identifier]);
790
+ const { value } = parseArray([TokenType.Identifier]);
746
791
  baseSlots[keyword] = value;
747
792
  break;
748
793
  }
@@ -834,7 +879,14 @@ export const parse = (tokens) => {
834
879
  try {
835
880
  switch (declType) {
836
881
  case "collection": {
837
- ast.collections.push(parseCollection(ast));
882
+ const collection = parseCollection(ast);
883
+ if (collection.name === "User") {
884
+ const { properties } = collection;
885
+ if ("roles" in properties && "items" in properties.roles.property && "enum" in properties.roles.property.items) {
886
+ memoTable.roles = properties.roles.property.items.enum;
887
+ }
888
+ }
889
+ ast.collections.push(collection);
838
890
  break;
839
891
  }
840
892
  case "contract": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aeriajs/compiler",
3
- "version": "0.0.11",
3
+ "version": "0.0.14",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",