@aeriajs/compiler 0.0.10 → 0.0.12
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 +18 -9
- package/dist/codegen/generateContracts.mjs +18 -9
- package/dist/codegen/utils.d.ts +1 -1
- package/dist/codegen/utils.js +6 -7
- package/dist/codegen/utils.mjs +5 -5
- 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 +83 -17
- package/dist/parser.mjs +79 -16
- package/package.json +1 -1
|
@@ -31,8 +31,9 @@ const makeJSContractsCode = (contractAst) => {
|
|
|
31
31
|
};
|
|
32
32
|
const declarations = contractAst.map((contractNode) => {
|
|
33
33
|
const { name, kind, roles, response, ...contractProperty } = contractNode;
|
|
34
|
-
let responseString
|
|
34
|
+
let responseString;
|
|
35
35
|
if (response) {
|
|
36
|
+
responseString = '';
|
|
36
37
|
if (Array.isArray(response)) {
|
|
37
38
|
const responseArray = [];
|
|
38
39
|
for (const responseElement of response) {
|
|
@@ -47,10 +48,15 @@ const makeJSContractsCode = (contractAst) => {
|
|
|
47
48
|
}
|
|
48
49
|
}
|
|
49
50
|
const contractSchema = (0, utils_js_1.getProperties)(contractProperty);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
if (responseString) {
|
|
52
|
+
contractSchema.response = {
|
|
53
|
+
[utils_js_1.UnquotedSymbol]: responseString,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
if (roles) {
|
|
57
|
+
contractSchema.roles = roles;
|
|
58
|
+
}
|
|
59
|
+
return `export const ${name} = defineContract(${(0, utils_js_1.stringify)(contractSchema)})`;
|
|
54
60
|
}).join('\n\n');
|
|
55
61
|
return `import { ${Array.from(imports).join(', ')} } from \'aeria\'\n\n` + declarations;
|
|
56
62
|
};
|
|
@@ -76,9 +82,12 @@ const makeTSContractsCode = (contractAst) => {
|
|
|
76
82
|
}
|
|
77
83
|
}
|
|
78
84
|
const contractProperties = (0, utils_js_1.getProperties)(contractSchema);
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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)}`;
|
|
83
92
|
}).join('\n\n');
|
|
84
93
|
};
|
|
@@ -26,8 +26,9 @@ const makeJSContractsCode = (contractAst) => {
|
|
|
26
26
|
};
|
|
27
27
|
const declarations = contractAst.map((contractNode) => {
|
|
28
28
|
const { name, kind, roles, response, ...contractProperty } = contractNode;
|
|
29
|
-
let responseString
|
|
29
|
+
let responseString;
|
|
30
30
|
if (response) {
|
|
31
|
+
responseString = "";
|
|
31
32
|
if (Array.isArray(response)) {
|
|
32
33
|
const responseArray = [];
|
|
33
34
|
for (const responseElement of response) {
|
|
@@ -41,10 +42,15 @@ const makeJSContractsCode = (contractAst) => {
|
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
const contractSchema = getProperties(contractProperty);
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
if (responseString) {
|
|
46
|
+
contractSchema.response = {
|
|
47
|
+
[UnquotedSymbol]: responseString
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
if (roles) {
|
|
51
|
+
contractSchema.roles = roles;
|
|
52
|
+
}
|
|
53
|
+
return `export const ${name} = defineContract(${stringify(contractSchema)})`;
|
|
48
54
|
}).join("\n\n");
|
|
49
55
|
return `import { ${Array.from(imports).join(", ")} } from 'aeria'
|
|
50
56
|
|
|
@@ -69,9 +75,12 @@ const makeTSContractsCode = (contractAst) => {
|
|
|
69
75
|
}
|
|
70
76
|
}
|
|
71
77
|
const contractProperties = getProperties(contractSchema);
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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)}`;
|
|
76
85
|
}).join("\n\n");
|
|
77
86
|
};
|
package/dist/codegen/utils.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export declare const makeASTImports: (ast: AST.Node[], initialImports?: Record<s
|
|
|
13
13
|
code: string[];
|
|
14
14
|
modifiedSymbols: Record<string, string>;
|
|
15
15
|
};
|
|
16
|
-
export declare const propertyToSchema: (
|
|
16
|
+
export declare const propertyToSchema: ({ property, nestedProperties }: Pick<AST.PropertyNode, "property" | "nestedProperties">) => Property;
|
|
17
17
|
/** Transforms the AST properties to the format of aeria schema properties */
|
|
18
18
|
export declare const getProperties: <TProperties extends Record<string, AST.PropertyNode | AST.PropertyNode[]>, TReturnType = TProperties[keyof TProperties] extends unknown[] ? Record<string, Property[]> : Record<string, Property>>(properties: TProperties) => TReturnType;
|
|
19
19
|
export declare const UnquotedSymbol: unique symbol;
|
package/dist/codegen/utils.js
CHANGED
|
@@ -14,8 +14,7 @@ exports.DEFAULT_FUNCTIONS = [
|
|
|
14
14
|
];
|
|
15
15
|
exports.ArraySymbol = Symbol('array');
|
|
16
16
|
const getExposedFunctions = (astFunctions) => {
|
|
17
|
-
return Object.fromEntries(Object.entries(astFunctions)
|
|
18
|
-
.map(([key, value]) => [
|
|
17
|
+
return Object.fromEntries(Object.entries(astFunctions).map(([key, value]) => [
|
|
19
18
|
key,
|
|
20
19
|
value.accessCondition,
|
|
21
20
|
]));
|
|
@@ -56,22 +55,22 @@ const makeASTImports = (ast, initialImports) => {
|
|
|
56
55
|
};
|
|
57
56
|
};
|
|
58
57
|
exports.makeASTImports = makeASTImports;
|
|
59
|
-
const propertyToSchema = (
|
|
60
|
-
const propertySchema =
|
|
58
|
+
const propertyToSchema = ({ property, nestedProperties }) => {
|
|
59
|
+
const propertySchema = property;
|
|
61
60
|
if ('$ref' in propertySchema) {
|
|
62
61
|
propertySchema.$ref = (0, exports.getCollectionId)(propertySchema.$ref);
|
|
63
62
|
}
|
|
64
63
|
else if ('items' in propertySchema && '$ref' in propertySchema.items) {
|
|
65
64
|
propertySchema.items.$ref = (0, exports.getCollectionId)(propertySchema.items.$ref);
|
|
66
65
|
}
|
|
67
|
-
if (
|
|
66
|
+
if (nestedProperties && 'type' in propertySchema) {
|
|
68
67
|
if (propertySchema.type === 'object' && 'properties' in propertySchema) {
|
|
69
|
-
propertySchema.properties = (0, exports.getProperties)(
|
|
68
|
+
propertySchema.properties = (0, exports.getProperties)(nestedProperties);
|
|
70
69
|
}
|
|
71
70
|
else if (propertySchema.type === 'array') {
|
|
72
71
|
propertySchema.items = {
|
|
73
72
|
type: 'object',
|
|
74
|
-
properties: (0, exports.getProperties)(
|
|
73
|
+
properties: (0, exports.getProperties)(nestedProperties),
|
|
75
74
|
};
|
|
76
75
|
}
|
|
77
76
|
}
|
package/dist/codegen/utils.mjs
CHANGED
|
@@ -48,20 +48,20 @@ export const makeASTImports = (ast, initialImports) => {
|
|
|
48
48
|
modifiedSymbols
|
|
49
49
|
};
|
|
50
50
|
};
|
|
51
|
-
export const propertyToSchema = (
|
|
52
|
-
const propertySchema =
|
|
51
|
+
export const propertyToSchema = ({ property, nestedProperties }) => {
|
|
52
|
+
const propertySchema = property;
|
|
53
53
|
if ("$ref" in propertySchema) {
|
|
54
54
|
propertySchema.$ref = getCollectionId(propertySchema.$ref);
|
|
55
55
|
} else if ("items" in propertySchema && "$ref" in propertySchema.items) {
|
|
56
56
|
propertySchema.items.$ref = getCollectionId(propertySchema.items.$ref);
|
|
57
57
|
}
|
|
58
|
-
if (
|
|
58
|
+
if (nestedProperties && "type" in propertySchema) {
|
|
59
59
|
if (propertySchema.type === "object" && "properties" in propertySchema) {
|
|
60
|
-
propertySchema.properties = getProperties(
|
|
60
|
+
propertySchema.properties = getProperties(nestedProperties);
|
|
61
61
|
} else if (propertySchema.type === "array") {
|
|
62
62
|
propertySchema.items = {
|
|
63
63
|
type: "object",
|
|
64
|
-
properties: getProperties(
|
|
64
|
+
properties: getProperties(nestedProperties)
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
67
|
}
|
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 = {
|
|
@@ -126,18 +139,35 @@ const parse = (tokens) => {
|
|
|
126
139
|
}
|
|
127
140
|
}
|
|
128
141
|
};
|
|
129
|
-
const parseArray = (
|
|
130
|
-
consume(token_js_1.TokenType.LeftSquareBracket);
|
|
142
|
+
const parseArray = (types) => {
|
|
143
|
+
const { location: openingLocation } = consume(token_js_1.TokenType.LeftSquareBracket);
|
|
131
144
|
const array = [];
|
|
145
|
+
const symbols = [];
|
|
146
|
+
let type;
|
|
147
|
+
for (const typeCandidate of types) {
|
|
148
|
+
if (match(typeCandidate)) {
|
|
149
|
+
type = typeCandidate;
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (!type) {
|
|
154
|
+
throw new diagnostic_js_1.Diagnostic(`array got an invalid type, accepted ones are: ${types.join(' | ')}`, openingLocation);
|
|
155
|
+
}
|
|
132
156
|
while (!match(token_js_1.TokenType.RightSquareBracket)) {
|
|
133
|
-
const { value } = consume(type);
|
|
157
|
+
const { value, location } = consume(type);
|
|
158
|
+
const elemSymbol = Symbol();
|
|
134
159
|
array.push(value);
|
|
160
|
+
symbols.push(elemSymbol);
|
|
161
|
+
exports.locationMap.set(elemSymbol, location);
|
|
135
162
|
if (match(token_js_1.TokenType.Comma)) {
|
|
136
163
|
consume(token_js_1.TokenType.Comma);
|
|
137
164
|
}
|
|
138
165
|
}
|
|
139
166
|
consume(token_js_1.TokenType.RightSquareBracket);
|
|
140
|
-
return
|
|
167
|
+
return {
|
|
168
|
+
value: array,
|
|
169
|
+
symbols,
|
|
170
|
+
};
|
|
141
171
|
};
|
|
142
172
|
const parseArrayBlock = (value) => {
|
|
143
173
|
const array = [];
|
|
@@ -189,7 +219,10 @@ const parse = (tokens) => {
|
|
|
189
219
|
return true;
|
|
190
220
|
};
|
|
191
221
|
if ('enum' in property && attributeName === 'values') {
|
|
192
|
-
property.enum = parseArray(
|
|
222
|
+
property.enum = parseArray([
|
|
223
|
+
token_js_1.TokenType.QuotedString,
|
|
224
|
+
token_js_1.TokenType.Number,
|
|
225
|
+
]).value;
|
|
193
226
|
return;
|
|
194
227
|
}
|
|
195
228
|
switch (attributeName) {
|
|
@@ -216,7 +249,7 @@ const parse = (tokens) => {
|
|
|
216
249
|
case 'form':
|
|
217
250
|
case 'populate':
|
|
218
251
|
case 'indexes': {
|
|
219
|
-
property[attributeName] = parseArray(token_js_1.TokenType.Identifier);
|
|
252
|
+
property[attributeName] = parseArray([token_js_1.TokenType.Identifier]).value;
|
|
220
253
|
return;
|
|
221
254
|
}
|
|
222
255
|
case 'populateDepth': {
|
|
@@ -229,7 +262,7 @@ const parse = (tokens) => {
|
|
|
229
262
|
switch (attributeName) {
|
|
230
263
|
case 'extensions':
|
|
231
264
|
case 'accept': {
|
|
232
|
-
property[attributeName] = parseArray(token_js_1.TokenType.QuotedString);
|
|
265
|
+
property[attributeName] = parseArray([token_js_1.TokenType.QuotedString]).value;
|
|
233
266
|
return;
|
|
234
267
|
}
|
|
235
268
|
}
|
|
@@ -246,7 +279,7 @@ const parse = (tokens) => {
|
|
|
246
279
|
}
|
|
247
280
|
case 'mask': {
|
|
248
281
|
if (match(token_js_1.TokenType.LeftSquareBracket)) {
|
|
249
|
-
property[attributeName] = parseArray(token_js_1.TokenType.QuotedString);
|
|
282
|
+
property[attributeName] = parseArray([token_js_1.TokenType.QuotedString]).value;
|
|
250
283
|
return;
|
|
251
284
|
}
|
|
252
285
|
else {
|
|
@@ -584,15 +617,15 @@ const parse = (tokens) => {
|
|
|
584
617
|
}
|
|
585
618
|
case 'icon': {
|
|
586
619
|
const { value } = consume(token_js_1.TokenType.QuotedString, ICON_NAMES);
|
|
587
|
-
node
|
|
620
|
+
node[keyword] = value;
|
|
588
621
|
break;
|
|
589
622
|
}
|
|
590
623
|
case 'properties': {
|
|
591
|
-
node
|
|
624
|
+
node[keyword] = parsePropertiesBlock();
|
|
592
625
|
break;
|
|
593
626
|
}
|
|
594
627
|
case 'functions': {
|
|
595
|
-
node
|
|
628
|
+
node[keyword] = parseFunctionsBlock(ast);
|
|
596
629
|
break;
|
|
597
630
|
}
|
|
598
631
|
case 'individualActions':
|
|
@@ -647,6 +680,26 @@ const parse = (tokens) => {
|
|
|
647
680
|
while (!match(token_js_1.TokenType.RightBracket)) {
|
|
648
681
|
const { value: keyword } = consume(token_js_1.TokenType.Keyword, lexer.CONTRACT_KEYWORDS);
|
|
649
682
|
switch (keyword) {
|
|
683
|
+
case 'roles': {
|
|
684
|
+
if (match(token_js_1.TokenType.Boolean)) {
|
|
685
|
+
const { value: boolean } = consume(token_js_1.TokenType.Boolean);
|
|
686
|
+
node.roles = boolean;
|
|
687
|
+
}
|
|
688
|
+
else if (match(token_js_1.TokenType.QuotedString, 'unauthenticated')) {
|
|
689
|
+
consume(token_js_1.TokenType.QuotedString);
|
|
690
|
+
node.roles = 'unauthenticated';
|
|
691
|
+
}
|
|
692
|
+
else if (match(token_js_1.TokenType.QuotedString, 'unauthenticated-only')) {
|
|
693
|
+
consume(token_js_1.TokenType.QuotedString);
|
|
694
|
+
node.roles = 'unauthenticated-only';
|
|
695
|
+
}
|
|
696
|
+
else {
|
|
697
|
+
const { value, symbols } = parseArrayBlock();
|
|
698
|
+
const roles = checkForValidRoles(value, symbols);
|
|
699
|
+
node.roles = roles;
|
|
700
|
+
}
|
|
701
|
+
break;
|
|
702
|
+
}
|
|
650
703
|
case 'payload': {
|
|
651
704
|
node.payload = parsePropertyType({
|
|
652
705
|
allowModifiers: true,
|
|
@@ -716,9 +769,10 @@ const parse = (tokens) => {
|
|
|
716
769
|
};
|
|
717
770
|
}
|
|
718
771
|
else {
|
|
719
|
-
const value = parseArray(token_js_1.TokenType.QuotedString);
|
|
772
|
+
const { value, symbols } = parseArray([token_js_1.TokenType.QuotedString]);
|
|
773
|
+
const roles = checkForValidRoles(value, symbols);
|
|
720
774
|
functions[functionName] = {
|
|
721
|
-
accessCondition:
|
|
775
|
+
accessCondition: roles,
|
|
722
776
|
};
|
|
723
777
|
}
|
|
724
778
|
consume(token_js_1.TokenType.RightParens);
|
|
@@ -780,9 +834,14 @@ const parse = (tokens) => {
|
|
|
780
834
|
baseSlots[keyword] = value;
|
|
781
835
|
break;
|
|
782
836
|
}
|
|
783
|
-
case 'roles':
|
|
837
|
+
case 'roles': {
|
|
838
|
+
const { value, symbols } = parseArray([token_js_1.TokenType.Identifier]);
|
|
839
|
+
const roles = checkForValidRoles(value, symbols);
|
|
840
|
+
baseSlots[keyword] = roles;
|
|
841
|
+
break;
|
|
842
|
+
}
|
|
784
843
|
case 'requires': {
|
|
785
|
-
const value = parseArray(token_js_1.TokenType.Identifier);
|
|
844
|
+
const { value } = parseArray([token_js_1.TokenType.Identifier]);
|
|
786
845
|
baseSlots[keyword] = value;
|
|
787
846
|
break;
|
|
788
847
|
}
|
|
@@ -875,7 +934,14 @@ const parse = (tokens) => {
|
|
|
875
934
|
try {
|
|
876
935
|
switch (declType) {
|
|
877
936
|
case 'collection': {
|
|
878
|
-
|
|
937
|
+
const collection = parseCollection(ast);
|
|
938
|
+
if (collection.name === 'User') {
|
|
939
|
+
const { properties } = collection;
|
|
940
|
+
if ('roles' in properties && 'items' in properties.roles.property && 'enum' in properties.roles.property.items) {
|
|
941
|
+
exports.memoTable.roles = properties.roles.property.items.enum;
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
ast.collections.push(collection);
|
|
879
945
|
break;
|
|
880
946
|
}
|
|
881
947
|
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 = {
|
|
@@ -88,18 +101,35 @@ export const parse = (tokens) => {
|
|
|
88
101
|
}
|
|
89
102
|
}
|
|
90
103
|
};
|
|
91
|
-
const parseArray = (
|
|
92
|
-
consume(TokenType.LeftSquareBracket);
|
|
104
|
+
const parseArray = (types) => {
|
|
105
|
+
const { location: openingLocation } = consume(TokenType.LeftSquareBracket);
|
|
93
106
|
const array = [];
|
|
107
|
+
const symbols = [];
|
|
108
|
+
let type;
|
|
109
|
+
for (const typeCandidate of types) {
|
|
110
|
+
if (match(typeCandidate)) {
|
|
111
|
+
type = typeCandidate;
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (!type) {
|
|
116
|
+
throw new Diagnostic(`array got an invalid type, accepted ones are: ${types.join(" | ")}`, openingLocation);
|
|
117
|
+
}
|
|
94
118
|
while (!match(TokenType.RightSquareBracket)) {
|
|
95
|
-
const { value } = consume(type);
|
|
119
|
+
const { value, location } = consume(type);
|
|
120
|
+
const elemSymbol = Symbol();
|
|
96
121
|
array.push(value);
|
|
122
|
+
symbols.push(elemSymbol);
|
|
123
|
+
locationMap.set(elemSymbol, location);
|
|
97
124
|
if (match(TokenType.Comma)) {
|
|
98
125
|
consume(TokenType.Comma);
|
|
99
126
|
}
|
|
100
127
|
}
|
|
101
128
|
consume(TokenType.RightSquareBracket);
|
|
102
|
-
return
|
|
129
|
+
return {
|
|
130
|
+
value: array,
|
|
131
|
+
symbols
|
|
132
|
+
};
|
|
103
133
|
};
|
|
104
134
|
const parseArrayBlock = (value) => {
|
|
105
135
|
const array = [];
|
|
@@ -148,7 +178,10 @@ export const parse = (tokens) => {
|
|
|
148
178
|
return true;
|
|
149
179
|
};
|
|
150
180
|
if ("enum" in property && attributeName === "values") {
|
|
151
|
-
property.enum = parseArray(
|
|
181
|
+
property.enum = parseArray([
|
|
182
|
+
TokenType.QuotedString,
|
|
183
|
+
TokenType.Number
|
|
184
|
+
]).value;
|
|
152
185
|
return;
|
|
153
186
|
}
|
|
154
187
|
switch (attributeName) {
|
|
@@ -175,7 +208,7 @@ export const parse = (tokens) => {
|
|
|
175
208
|
case "form":
|
|
176
209
|
case "populate":
|
|
177
210
|
case "indexes": {
|
|
178
|
-
property[attributeName] = parseArray(TokenType.Identifier);
|
|
211
|
+
property[attributeName] = parseArray([TokenType.Identifier]).value;
|
|
179
212
|
return;
|
|
180
213
|
}
|
|
181
214
|
case "populateDepth": {
|
|
@@ -188,7 +221,7 @@ export const parse = (tokens) => {
|
|
|
188
221
|
switch (attributeName) {
|
|
189
222
|
case "extensions":
|
|
190
223
|
case "accept": {
|
|
191
|
-
property[attributeName] = parseArray(TokenType.QuotedString);
|
|
224
|
+
property[attributeName] = parseArray([TokenType.QuotedString]).value;
|
|
192
225
|
return;
|
|
193
226
|
}
|
|
194
227
|
}
|
|
@@ -205,7 +238,7 @@ export const parse = (tokens) => {
|
|
|
205
238
|
}
|
|
206
239
|
case "mask": {
|
|
207
240
|
if (match(TokenType.LeftSquareBracket)) {
|
|
208
|
-
property[attributeName] = parseArray(TokenType.QuotedString);
|
|
241
|
+
property[attributeName] = parseArray([TokenType.QuotedString]).value;
|
|
209
242
|
return;
|
|
210
243
|
} else {
|
|
211
244
|
const { value } = consume(TokenType.QuotedString);
|
|
@@ -535,15 +568,15 @@ export const parse = (tokens) => {
|
|
|
535
568
|
}
|
|
536
569
|
case "icon": {
|
|
537
570
|
const { value } = consume(TokenType.QuotedString, ICON_NAMES);
|
|
538
|
-
node
|
|
571
|
+
node[keyword] = value;
|
|
539
572
|
break;
|
|
540
573
|
}
|
|
541
574
|
case "properties": {
|
|
542
|
-
node
|
|
575
|
+
node[keyword] = parsePropertiesBlock();
|
|
543
576
|
break;
|
|
544
577
|
}
|
|
545
578
|
case "functions": {
|
|
546
|
-
node
|
|
579
|
+
node[keyword] = parseFunctionsBlock(ast2);
|
|
547
580
|
break;
|
|
548
581
|
}
|
|
549
582
|
case "individualActions":
|
|
@@ -597,6 +630,23 @@ export const parse = (tokens) => {
|
|
|
597
630
|
while (!match(TokenType.RightBracket)) {
|
|
598
631
|
const { value: keyword } = consume(TokenType.Keyword, lexer.CONTRACT_KEYWORDS);
|
|
599
632
|
switch (keyword) {
|
|
633
|
+
case "roles": {
|
|
634
|
+
if (match(TokenType.Boolean)) {
|
|
635
|
+
const { value: boolean } = consume(TokenType.Boolean);
|
|
636
|
+
node.roles = boolean;
|
|
637
|
+
} else if (match(TokenType.QuotedString, "unauthenticated")) {
|
|
638
|
+
consume(TokenType.QuotedString);
|
|
639
|
+
node.roles = "unauthenticated";
|
|
640
|
+
} else if (match(TokenType.QuotedString, "unauthenticated-only")) {
|
|
641
|
+
consume(TokenType.QuotedString);
|
|
642
|
+
node.roles = "unauthenticated-only";
|
|
643
|
+
} else {
|
|
644
|
+
const { value, symbols } = parseArrayBlock();
|
|
645
|
+
const roles = checkForValidRoles(value, symbols);
|
|
646
|
+
node.roles = roles;
|
|
647
|
+
}
|
|
648
|
+
break;
|
|
649
|
+
}
|
|
600
650
|
case "payload": {
|
|
601
651
|
node.payload = parsePropertyType({
|
|
602
652
|
allowModifiers: true
|
|
@@ -664,9 +714,10 @@ export const parse = (tokens) => {
|
|
|
664
714
|
accessCondition: value
|
|
665
715
|
};
|
|
666
716
|
} else {
|
|
667
|
-
const value = parseArray(TokenType.QuotedString);
|
|
717
|
+
const { value, symbols } = parseArray([TokenType.QuotedString]);
|
|
718
|
+
const roles = checkForValidRoles(value, symbols);
|
|
668
719
|
functions[functionName] = {
|
|
669
|
-
accessCondition:
|
|
720
|
+
accessCondition: roles
|
|
670
721
|
};
|
|
671
722
|
}
|
|
672
723
|
consume(TokenType.RightParens);
|
|
@@ -727,9 +778,14 @@ export const parse = (tokens) => {
|
|
|
727
778
|
baseSlots[keyword] = value;
|
|
728
779
|
break;
|
|
729
780
|
}
|
|
730
|
-
case "roles":
|
|
781
|
+
case "roles": {
|
|
782
|
+
const { value, symbols } = parseArray([TokenType.Identifier]);
|
|
783
|
+
const roles = checkForValidRoles(value, symbols);
|
|
784
|
+
baseSlots[keyword] = roles;
|
|
785
|
+
break;
|
|
786
|
+
}
|
|
731
787
|
case "requires": {
|
|
732
|
-
const value = parseArray(TokenType.Identifier);
|
|
788
|
+
const { value } = parseArray([TokenType.Identifier]);
|
|
733
789
|
baseSlots[keyword] = value;
|
|
734
790
|
break;
|
|
735
791
|
}
|
|
@@ -821,7 +877,14 @@ export const parse = (tokens) => {
|
|
|
821
877
|
try {
|
|
822
878
|
switch (declType) {
|
|
823
879
|
case "collection": {
|
|
824
|
-
|
|
880
|
+
const collection = parseCollection(ast);
|
|
881
|
+
if (collection.name === "User") {
|
|
882
|
+
const { properties } = collection;
|
|
883
|
+
if ("roles" in properties && "items" in properties.roles.property && "enum" in properties.roles.property.items) {
|
|
884
|
+
memoTable.roles = properties.roles.property.items.enum;
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
ast.collections.push(collection);
|
|
825
888
|
break;
|
|
826
889
|
}
|
|
827
890
|
case "contract": {
|