@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.
- package/dist/codegen/generateContracts.js +10 -6
- package/dist/codegen/generateContracts.mjs +10 -6
- package/dist/compile.js +1 -1
- package/dist/compile.mjs +1 -1
- package/dist/lexer.d.ts +1 -1
- package/dist/lexer.js +1 -0
- package/dist/lexer.mjs +1 -0
- package/dist/parser.d.ts +3 -0
- package/dist/parser.js +112 -57
- package/dist/parser.mjs +107 -55
- package/package.json +1 -1
|
@@ -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
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
package/dist/lexer.mjs
CHANGED
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(' | ')}`,
|
|
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
|
|
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
|
|
644
|
+
node[keyword] = value;
|
|
601
645
|
break;
|
|
602
646
|
}
|
|
603
647
|
case 'properties': {
|
|
604
|
-
node
|
|
648
|
+
node[keyword] = parsePropertiesBlock();
|
|
605
649
|
break;
|
|
606
650
|
}
|
|
607
651
|
case 'functions': {
|
|
608
|
-
node
|
|
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
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
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
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
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:
|
|
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:
|
|
771
|
+
accessCondition: true,
|
|
735
772
|
};
|
|
736
773
|
}
|
|
737
|
-
consume(token_js_1.TokenType.RightParens);
|
|
738
774
|
}
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
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
|
-
|
|
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(" | ")}`,
|
|
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
|
|
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
|
|
591
|
+
node[keyword] = value;
|
|
552
592
|
break;
|
|
553
593
|
}
|
|
554
594
|
case "properties": {
|
|
555
|
-
node
|
|
595
|
+
node[keyword] = parsePropertiesBlock();
|
|
556
596
|
break;
|
|
557
597
|
}
|
|
558
598
|
case "functions": {
|
|
559
|
-
node
|
|
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
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
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
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
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:
|
|
711
|
+
accessCondition: parseAccessCondition()
|
|
678
712
|
};
|
|
713
|
+
consume(TokenType.RightParens);
|
|
679
714
|
} else {
|
|
680
|
-
const value = parseArray([TokenType.QuotedString]);
|
|
681
715
|
functions[functionName] = {
|
|
682
|
-
accessCondition:
|
|
716
|
+
accessCondition: true
|
|
683
717
|
};
|
|
684
718
|
}
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
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
|
-
|
|
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": {
|