@aeriajs/compiler 0.0.25 → 0.0.27
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/ast.d.ts +12 -2
- package/dist/codegen/generateJSCollections.js +3 -0
- package/dist/codegen/generateJSCollections.mjs +3 -0
- package/dist/codegen/generateTSCollections.js +6 -0
- package/dist/codegen/generateTSCollections.mjs +6 -0
- package/dist/diagnostic.js +3 -0
- package/dist/diagnostic.mjs +3 -0
- package/dist/lexer.d.ts +4 -2
- package/dist/lexer.js +32 -10
- package/dist/lexer.mjs +31 -8
- package/dist/parser.js +150 -0
- package/dist/parser.mjs +147 -0
- package/dist/semantic.js +10 -0
- package/dist/semantic.mjs +10 -0
- package/dist/token.d.ts +1 -0
- package/dist/token.js +1 -0
- package/dist/token.mjs +2 -1
- package/package.json +3 -3
package/dist/ast.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Property, AccessCondition, CollectionActions, SearchOptions, DescriptionPreset, Icon, OwnershipMode, Layout, LayoutOptions } from '@aeriajs/types';
|
|
1
|
+
import type { Property, AccessCondition, CollectionActions, SearchOptions, DescriptionPreset, Icon, OwnershipMode, Layout, LayoutOptions, FormLayout, Description, FormLayoutField } from '@aeriajs/types';
|
|
2
2
|
import type { ArrayProperties } from './utils.js';
|
|
3
3
|
export declare const LOCATION_SYMBOL: unique symbol;
|
|
4
4
|
export declare const PropertyType: {
|
|
@@ -26,6 +26,16 @@ export type LayoutNode = NodeBase<'layout'> & Layout & {
|
|
|
26
26
|
};
|
|
27
27
|
};
|
|
28
28
|
};
|
|
29
|
+
export type FormLayoutNode = NodeBase<'formLayout'> & FormLayout<Description> & {
|
|
30
|
+
[LOCATION_SYMBOL]: {
|
|
31
|
+
fields: {
|
|
32
|
+
[P in string]: {
|
|
33
|
+
name: symbol;
|
|
34
|
+
field: FormLayoutField<Description>;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
};
|
|
29
39
|
export type PropertyNode = NodeBase<'property'> & {
|
|
30
40
|
modifier?: keyof typeof PropertyModifiers;
|
|
31
41
|
property: Property & {
|
|
@@ -61,6 +71,7 @@ export type CollectionNode = NodeBase<'collection'> & {
|
|
|
61
71
|
filters?: string[];
|
|
62
72
|
search?: SearchOptions<any>;
|
|
63
73
|
layout?: LayoutNode;
|
|
74
|
+
formLayout?: FormLayoutNode;
|
|
64
75
|
[LOCATION_SYMBOL]: {
|
|
65
76
|
arrays: {
|
|
66
77
|
[P in ArrayProperties<CollectionNode>]?: symbol[];
|
|
@@ -87,4 +98,3 @@ export type ProgramNode = NodeBase<'program'> & {
|
|
|
87
98
|
functionsets: FunctionSetNode[];
|
|
88
99
|
};
|
|
89
100
|
export type Node = CollectionNode | ContractNode | FunctionSetNode;
|
|
90
|
-
export type NoteKind = Node['kind'];
|
|
@@ -80,6 +80,9 @@ const makeJSCollectionSchema = (collectionNode, collectionId) => {
|
|
|
80
80
|
case 'layout':
|
|
81
81
|
collectionSchema.description[key] = collectionNode[key];
|
|
82
82
|
break;
|
|
83
|
+
case 'formLayout':
|
|
84
|
+
collectionSchema.description[key] = collectionNode[key];
|
|
85
|
+
break;
|
|
83
86
|
case 'required':
|
|
84
87
|
collectionSchema.description[key] = collectionNode[key];
|
|
85
88
|
break;
|
|
@@ -73,6 +73,9 @@ const makeJSCollectionSchema = (collectionNode, collectionId) => {
|
|
|
73
73
|
case "layout":
|
|
74
74
|
collectionSchema.description[key] = collectionNode[key];
|
|
75
75
|
break;
|
|
76
|
+
case "formLayout":
|
|
77
|
+
collectionSchema.description[key] = collectionNode[key];
|
|
78
|
+
break;
|
|
76
79
|
case "required":
|
|
77
80
|
collectionSchema.description[key] = collectionNode[key];
|
|
78
81
|
break;
|
|
@@ -87,6 +87,12 @@ const makeTSCollectionSchema = (collectionNode, collectionId) => {
|
|
|
87
87
|
case 'search':
|
|
88
88
|
collectionSchema.description[key] = collectionNode[key];
|
|
89
89
|
break;
|
|
90
|
+
case 'layout':
|
|
91
|
+
collectionSchema.description[key] = collectionNode[key];
|
|
92
|
+
break;
|
|
93
|
+
case 'formLayout':
|
|
94
|
+
collectionSchema.description[key] = collectionNode[key];
|
|
95
|
+
break;
|
|
90
96
|
case 'required':
|
|
91
97
|
collectionSchema.description[key] = collectionNode[key];
|
|
92
98
|
break;
|
|
@@ -82,6 +82,12 @@ const makeTSCollectionSchema = (collectionNode, collectionId) => {
|
|
|
82
82
|
case "search":
|
|
83
83
|
collectionSchema.description[key] = collectionNode[key];
|
|
84
84
|
break;
|
|
85
|
+
case "layout":
|
|
86
|
+
collectionSchema.description[key] = collectionNode[key];
|
|
87
|
+
break;
|
|
88
|
+
case "formLayout":
|
|
89
|
+
collectionSchema.description[key] = collectionNode[key];
|
|
90
|
+
break;
|
|
85
91
|
case "required":
|
|
86
92
|
collectionSchema.description[key] = collectionNode[key];
|
|
87
93
|
break;
|
package/dist/diagnostic.js
CHANGED
package/dist/diagnostic.mjs
CHANGED
package/dist/lexer.d.ts
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { type Token } from './token.js';
|
|
2
2
|
import { Diagnostic } from './diagnostic.js';
|
|
3
|
-
export declare const COLLECTION_KEYWORDS: readonly ["actions", "additionalProperties", "filters", "form", "functions", "icon", "indexes", "individualActions", "layout", "owned", "presets", "properties", "required", "search", "table"];
|
|
3
|
+
export declare const COLLECTION_KEYWORDS: readonly ["actions", "additionalProperties", "filters", "form", "formLayout", "functions", "icon", "indexes", "individualActions", "layout", "owned", "presets", "properties", "required", "search", "table"];
|
|
4
4
|
export declare const COLLECTION_ACTIONS_KEYWORDS: readonly ["ask", "button", "clearItem", "effect", "event", "fetchItem", "function", "icon", "label", "params", "query", "requires", "roles", "route", "selection", "setItem", "translate"];
|
|
5
5
|
export declare const COLLECTION_SEARCH_KEYWORDS: readonly ["indexes", "placeholder", "exactMatches"];
|
|
6
6
|
export declare const COLLECTION_LAYOUT_KEYWORDS: readonly ["name", "options"];
|
|
7
7
|
export declare const COLLECTION_LAYOUT_OPTIONS_KEYWORDS: readonly ["title", "picture", "badge", "information", "active", "translateBadge"];
|
|
8
|
+
export declare const COLLECTION_FORM_LAYOUT_KEYWORDS: readonly ["fields", "if", "span", "verticalSpacing", "separator"];
|
|
8
9
|
export declare const CONTRACT_KEYWORDS: readonly ["roles", "payload", "query", "response"];
|
|
9
10
|
export declare const TOPLEVEL_KEYWORDS: readonly ["collection", "contract", "functionset"];
|
|
10
11
|
export declare const MISC_KEYWORDS: readonly ["extends"];
|
|
11
|
-
export type Keyword = typeof COLLECTION_KEYWORDS[number] | typeof COLLECTION_ACTIONS_KEYWORDS[number] | typeof COLLECTION_SEARCH_KEYWORDS[number] | typeof COLLECTION_LAYOUT_KEYWORDS[number] | typeof COLLECTION_LAYOUT_OPTIONS_KEYWORDS[number] | typeof CONTRACT_KEYWORDS[number] | typeof TOPLEVEL_KEYWORDS[number] | typeof MISC_KEYWORDS[number];
|
|
12
|
+
export type Keyword = typeof COLLECTION_KEYWORDS[number] | typeof COLLECTION_ACTIONS_KEYWORDS[number] | typeof COLLECTION_SEARCH_KEYWORDS[number] | typeof COLLECTION_LAYOUT_KEYWORDS[number] | typeof COLLECTION_LAYOUT_OPTIONS_KEYWORDS[number] | typeof COLLECTION_FORM_LAYOUT_KEYWORDS[number] | typeof CONTRACT_KEYWORDS[number] | typeof TOPLEVEL_KEYWORDS[number] | typeof MISC_KEYWORDS[number];
|
|
12
13
|
export declare const KEYWORDS: Keyword[];
|
|
14
|
+
export declare const OPERATORS: readonly ["&&", "||", "==", "in", ">=", "<=", ">", "<"];
|
|
13
15
|
export declare const tokenize: (rawInput: string) => {
|
|
14
16
|
tokens: Token[];
|
|
15
17
|
errors: Diagnostic[];
|
package/dist/lexer.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.tokenize = exports.KEYWORDS = exports.MISC_KEYWORDS = exports.TOPLEVEL_KEYWORDS = exports.CONTRACT_KEYWORDS = exports.COLLECTION_LAYOUT_OPTIONS_KEYWORDS = exports.COLLECTION_LAYOUT_KEYWORDS = exports.COLLECTION_SEARCH_KEYWORDS = exports.COLLECTION_ACTIONS_KEYWORDS = exports.COLLECTION_KEYWORDS = void 0;
|
|
3
|
+
exports.tokenize = exports.OPERATORS = exports.KEYWORDS = exports.MISC_KEYWORDS = exports.TOPLEVEL_KEYWORDS = exports.CONTRACT_KEYWORDS = exports.COLLECTION_FORM_LAYOUT_KEYWORDS = exports.COLLECTION_LAYOUT_OPTIONS_KEYWORDS = exports.COLLECTION_LAYOUT_KEYWORDS = exports.COLLECTION_SEARCH_KEYWORDS = exports.COLLECTION_ACTIONS_KEYWORDS = exports.COLLECTION_KEYWORDS = void 0;
|
|
4
4
|
const token_js_1 = require("./token.js");
|
|
5
5
|
const diagnostic_js_1 = require("./diagnostic.js");
|
|
6
6
|
exports.COLLECTION_KEYWORDS = [
|
|
@@ -8,6 +8,7 @@ exports.COLLECTION_KEYWORDS = [
|
|
|
8
8
|
'additionalProperties',
|
|
9
9
|
'filters',
|
|
10
10
|
'form',
|
|
11
|
+
'formLayout',
|
|
11
12
|
'functions',
|
|
12
13
|
'icon',
|
|
13
14
|
'indexes',
|
|
@@ -56,6 +57,13 @@ exports.COLLECTION_LAYOUT_OPTIONS_KEYWORDS = [
|
|
|
56
57
|
'active',
|
|
57
58
|
'translateBadge',
|
|
58
59
|
];
|
|
60
|
+
exports.COLLECTION_FORM_LAYOUT_KEYWORDS = [
|
|
61
|
+
'fields',
|
|
62
|
+
'if',
|
|
63
|
+
'span',
|
|
64
|
+
'verticalSpacing',
|
|
65
|
+
'separator',
|
|
66
|
+
];
|
|
59
67
|
exports.CONTRACT_KEYWORDS = [
|
|
60
68
|
'roles',
|
|
61
69
|
'payload',
|
|
@@ -68,7 +76,17 @@ exports.TOPLEVEL_KEYWORDS = [
|
|
|
68
76
|
'functionset',
|
|
69
77
|
];
|
|
70
78
|
exports.MISC_KEYWORDS = ['extends'];
|
|
71
|
-
exports.KEYWORDS = [].concat(exports.COLLECTION_KEYWORDS, exports.COLLECTION_ACTIONS_KEYWORDS, exports.COLLECTION_SEARCH_KEYWORDS, exports.COLLECTION_LAYOUT_KEYWORDS, exports.COLLECTION_LAYOUT_OPTIONS_KEYWORDS, exports.CONTRACT_KEYWORDS, exports.TOPLEVEL_KEYWORDS, exports.MISC_KEYWORDS);
|
|
79
|
+
exports.KEYWORDS = [].concat(exports.COLLECTION_KEYWORDS, exports.COLLECTION_ACTIONS_KEYWORDS, exports.COLLECTION_SEARCH_KEYWORDS, exports.COLLECTION_LAYOUT_KEYWORDS, exports.COLLECTION_LAYOUT_OPTIONS_KEYWORDS, exports.COLLECTION_FORM_LAYOUT_KEYWORDS, exports.CONTRACT_KEYWORDS, exports.TOPLEVEL_KEYWORDS, exports.MISC_KEYWORDS);
|
|
80
|
+
exports.OPERATORS = [
|
|
81
|
+
'&&',
|
|
82
|
+
'||',
|
|
83
|
+
'==',
|
|
84
|
+
'in',
|
|
85
|
+
'>=',
|
|
86
|
+
'<=',
|
|
87
|
+
'>',
|
|
88
|
+
'<',
|
|
89
|
+
];
|
|
72
90
|
const keywordsSet = new Set();
|
|
73
91
|
for (const keyword of exports.KEYWORDS) {
|
|
74
92
|
keywordsSet.add(keyword);
|
|
@@ -110,6 +128,10 @@ const TOKENS = [
|
|
|
110
128
|
type: token_js_1.TokenType.RightSquareBracket,
|
|
111
129
|
matcher: ']',
|
|
112
130
|
},
|
|
131
|
+
{
|
|
132
|
+
type: token_js_1.TokenType.Operator,
|
|
133
|
+
matcher: exports.OPERATORS,
|
|
134
|
+
},
|
|
113
135
|
{
|
|
114
136
|
type: token_js_1.TokenType.Pipe,
|
|
115
137
|
matcher: '|',
|
|
@@ -150,7 +172,7 @@ const TOKENS = [
|
|
|
150
172
|
type: token_js_1.TokenType.Keyword,
|
|
151
173
|
matcher: Array.from(keywordsSet),
|
|
152
174
|
condition: (state, lastToken) => {
|
|
153
|
-
if (state.
|
|
175
|
+
if (state.variableScopeStack.at(-1)) {
|
|
154
176
|
return false;
|
|
155
177
|
}
|
|
156
178
|
if (lastToken && lastToken.type === token_js_1.TokenType.Keyword) {
|
|
@@ -190,7 +212,7 @@ const tokenize = function (rawInput) {
|
|
|
190
212
|
const tokens = [];
|
|
191
213
|
const errors = [];
|
|
192
214
|
const state = {
|
|
193
|
-
|
|
215
|
+
variableScopeStack: [],
|
|
194
216
|
};
|
|
195
217
|
while (index < input.length) {
|
|
196
218
|
let hasMatch = false;
|
|
@@ -260,8 +282,10 @@ const tokenize = function (rawInput) {
|
|
|
260
282
|
};
|
|
261
283
|
switch (type) {
|
|
262
284
|
case token_js_1.TokenType.LeftBracket: {
|
|
285
|
+
let variableScope = false;
|
|
263
286
|
if (lastToken && lastToken.type === token_js_1.TokenType.Keyword) {
|
|
264
287
|
switch (lastToken.value) {
|
|
288
|
+
case 'fields':
|
|
265
289
|
case 'information':
|
|
266
290
|
case 'form':
|
|
267
291
|
case 'table':
|
|
@@ -270,19 +294,17 @@ const tokenize = function (rawInput) {
|
|
|
270
294
|
case 'writable':
|
|
271
295
|
case 'required':
|
|
272
296
|
case 'properties': {
|
|
273
|
-
|
|
297
|
+
variableScope = true;
|
|
274
298
|
break;
|
|
275
299
|
}
|
|
276
|
-
default: {
|
|
277
|
-
state.inPropertiesStack.push(false);
|
|
278
|
-
}
|
|
279
300
|
}
|
|
280
301
|
}
|
|
302
|
+
state.variableScopeStack.push(variableScope);
|
|
281
303
|
break;
|
|
282
304
|
}
|
|
283
305
|
case token_js_1.TokenType.RightBracket: {
|
|
284
|
-
if (state.
|
|
285
|
-
state.
|
|
306
|
+
if (state.variableScopeStack.length > 0) {
|
|
307
|
+
state.variableScopeStack.pop();
|
|
286
308
|
}
|
|
287
309
|
break;
|
|
288
310
|
}
|
package/dist/lexer.mjs
CHANGED
|
@@ -6,6 +6,7 @@ export const COLLECTION_KEYWORDS = [
|
|
|
6
6
|
"additionalProperties",
|
|
7
7
|
"filters",
|
|
8
8
|
"form",
|
|
9
|
+
"formLayout",
|
|
9
10
|
"functions",
|
|
10
11
|
"icon",
|
|
11
12
|
"indexes",
|
|
@@ -54,6 +55,13 @@ export const COLLECTION_LAYOUT_OPTIONS_KEYWORDS = [
|
|
|
54
55
|
"active",
|
|
55
56
|
"translateBadge"
|
|
56
57
|
];
|
|
58
|
+
export const COLLECTION_FORM_LAYOUT_KEYWORDS = [
|
|
59
|
+
"fields",
|
|
60
|
+
"if",
|
|
61
|
+
"span",
|
|
62
|
+
"verticalSpacing",
|
|
63
|
+
"separator"
|
|
64
|
+
];
|
|
57
65
|
export const CONTRACT_KEYWORDS = [
|
|
58
66
|
"roles",
|
|
59
67
|
"payload",
|
|
@@ -72,10 +80,21 @@ export const KEYWORDS = [].concat(
|
|
|
72
80
|
COLLECTION_SEARCH_KEYWORDS,
|
|
73
81
|
COLLECTION_LAYOUT_KEYWORDS,
|
|
74
82
|
COLLECTION_LAYOUT_OPTIONS_KEYWORDS,
|
|
83
|
+
COLLECTION_FORM_LAYOUT_KEYWORDS,
|
|
75
84
|
CONTRACT_KEYWORDS,
|
|
76
85
|
TOPLEVEL_KEYWORDS,
|
|
77
86
|
MISC_KEYWORDS
|
|
78
87
|
);
|
|
88
|
+
export const OPERATORS = [
|
|
89
|
+
"&&",
|
|
90
|
+
"||",
|
|
91
|
+
"==",
|
|
92
|
+
"in",
|
|
93
|
+
">=",
|
|
94
|
+
"<=",
|
|
95
|
+
">",
|
|
96
|
+
"<"
|
|
97
|
+
];
|
|
79
98
|
const keywordsSet = /* @__PURE__ */ new Set();
|
|
80
99
|
for (const keyword of KEYWORDS) {
|
|
81
100
|
keywordsSet.add(keyword);
|
|
@@ -117,6 +136,10 @@ const TOKENS = [
|
|
|
117
136
|
type: TokenType.RightSquareBracket,
|
|
118
137
|
matcher: "]"
|
|
119
138
|
},
|
|
139
|
+
{
|
|
140
|
+
type: TokenType.Operator,
|
|
141
|
+
matcher: OPERATORS
|
|
142
|
+
},
|
|
120
143
|
{
|
|
121
144
|
type: TokenType.Pipe,
|
|
122
145
|
matcher: "|"
|
|
@@ -157,7 +180,7 @@ const TOKENS = [
|
|
|
157
180
|
type: TokenType.Keyword,
|
|
158
181
|
matcher: Array.from(keywordsSet),
|
|
159
182
|
condition: (state, lastToken) => {
|
|
160
|
-
if (state.
|
|
183
|
+
if (state.variableScopeStack.at(-1)) {
|
|
161
184
|
return false;
|
|
162
185
|
}
|
|
163
186
|
if (lastToken && lastToken.type === TokenType.Keyword) {
|
|
@@ -197,7 +220,7 @@ export const tokenize = function(rawInput) {
|
|
|
197
220
|
const tokens = [];
|
|
198
221
|
const errors = [];
|
|
199
222
|
const state = {
|
|
200
|
-
|
|
223
|
+
variableScopeStack: []
|
|
201
224
|
};
|
|
202
225
|
while (index < input.length) {
|
|
203
226
|
let hasMatch = false;
|
|
@@ -262,8 +285,10 @@ export const tokenize = function(rawInput) {
|
|
|
262
285
|
};
|
|
263
286
|
switch (type) {
|
|
264
287
|
case TokenType.LeftBracket: {
|
|
288
|
+
let variableScope = false;
|
|
265
289
|
if (lastToken && lastToken.type === TokenType.Keyword) {
|
|
266
290
|
switch (lastToken.value) {
|
|
291
|
+
case "fields":
|
|
267
292
|
case "information":
|
|
268
293
|
case "form":
|
|
269
294
|
case "table":
|
|
@@ -272,19 +297,17 @@ export const tokenize = function(rawInput) {
|
|
|
272
297
|
case "writable":
|
|
273
298
|
case "required":
|
|
274
299
|
case "properties": {
|
|
275
|
-
|
|
300
|
+
variableScope = true;
|
|
276
301
|
break;
|
|
277
302
|
}
|
|
278
|
-
default: {
|
|
279
|
-
state.inPropertiesStack.push(false);
|
|
280
|
-
}
|
|
281
303
|
}
|
|
282
304
|
}
|
|
305
|
+
state.variableScopeStack.push(variableScope);
|
|
283
306
|
break;
|
|
284
307
|
}
|
|
285
308
|
case TokenType.RightBracket: {
|
|
286
|
-
if (state.
|
|
287
|
-
state.
|
|
309
|
+
if (state.variableScopeStack.length > 0) {
|
|
310
|
+
state.variableScopeStack.pop();
|
|
288
311
|
}
|
|
289
312
|
break;
|
|
290
313
|
}
|
package/dist/parser.js
CHANGED
|
@@ -600,6 +600,7 @@ const parse = (tokens) => {
|
|
|
600
600
|
}
|
|
601
601
|
continue;
|
|
602
602
|
}
|
|
603
|
+
throw err;
|
|
603
604
|
}
|
|
604
605
|
}
|
|
605
606
|
consume(token_js_1.TokenType.RightBracket);
|
|
@@ -731,6 +732,10 @@ const parse = (tokens) => {
|
|
|
731
732
|
node[keyword] = parseLayoutBlock();
|
|
732
733
|
break;
|
|
733
734
|
}
|
|
735
|
+
case 'formLayout': {
|
|
736
|
+
node[keyword] = parseFormLayoutBlock();
|
|
737
|
+
break;
|
|
738
|
+
}
|
|
734
739
|
}
|
|
735
740
|
}
|
|
736
741
|
catch (err) {
|
|
@@ -739,6 +744,7 @@ const parse = (tokens) => {
|
|
|
739
744
|
recover(lexer.COLLECTION_KEYWORDS);
|
|
740
745
|
continue;
|
|
741
746
|
}
|
|
747
|
+
throw err;
|
|
742
748
|
}
|
|
743
749
|
}
|
|
744
750
|
consume(token_js_1.TokenType.RightBracket);
|
|
@@ -792,6 +798,7 @@ const parse = (tokens) => {
|
|
|
792
798
|
if (match(token_js_1.TokenType.MacroName)) {
|
|
793
799
|
const { value: macroName } = consume(token_js_1.TokenType.MacroName, ['include']);
|
|
794
800
|
switch (macroName) {
|
|
801
|
+
/* eslint-disable-next-line */
|
|
795
802
|
case 'include': {
|
|
796
803
|
const { value: functionSetName, location } = consume(token_js_1.TokenType.Identifier);
|
|
797
804
|
const functionset = ast.functionsets.find((node) => node.name === functionSetName);
|
|
@@ -835,6 +842,7 @@ const parse = (tokens) => {
|
|
|
835
842
|
errors.push(err);
|
|
836
843
|
continue;
|
|
837
844
|
}
|
|
845
|
+
throw err;
|
|
838
846
|
}
|
|
839
847
|
}
|
|
840
848
|
consume(token_js_1.TokenType.RightBracket);
|
|
@@ -1051,6 +1059,148 @@ const parse = (tokens) => {
|
|
|
1051
1059
|
},
|
|
1052
1060
|
};
|
|
1053
1061
|
};
|
|
1062
|
+
const parseFormLayoutBlock = () => {
|
|
1063
|
+
const fields = {};
|
|
1064
|
+
const node = {
|
|
1065
|
+
kind: 'formLayout',
|
|
1066
|
+
fields,
|
|
1067
|
+
[AST.LOCATION_SYMBOL]: {
|
|
1068
|
+
fields: {},
|
|
1069
|
+
},
|
|
1070
|
+
};
|
|
1071
|
+
consume(token_js_1.TokenType.LeftBracket);
|
|
1072
|
+
while (!match(token_js_1.TokenType.RightBracket)) {
|
|
1073
|
+
const { value: keyword, location: keywordLocation } = consume(token_js_1.TokenType.Keyword, lexer.COLLECTION_FORM_LAYOUT_KEYWORDS);
|
|
1074
|
+
switch (keyword) {
|
|
1075
|
+
case 'fields': {
|
|
1076
|
+
consume(token_js_1.TokenType.LeftBracket);
|
|
1077
|
+
while (!match(token_js_1.TokenType.RightBracket)) {
|
|
1078
|
+
const { value: identifier, location: identifierLocation } = consume(token_js_1.TokenType.Identifier);
|
|
1079
|
+
const identifierSymbol = Symbol();
|
|
1080
|
+
exports.locationMap.set(identifierSymbol, identifierLocation);
|
|
1081
|
+
fields[identifier] ??= {};
|
|
1082
|
+
node[AST.LOCATION_SYMBOL].fields[identifier] = {
|
|
1083
|
+
name: identifierSymbol,
|
|
1084
|
+
field: {},
|
|
1085
|
+
};
|
|
1086
|
+
consume(token_js_1.TokenType.LeftBracket);
|
|
1087
|
+
while (!match(token_js_1.TokenType.RightBracket)) {
|
|
1088
|
+
const { value: keyword, location: keywordLocation } = consume(token_js_1.TokenType.Keyword, lexer.COLLECTION_FORM_LAYOUT_KEYWORDS);
|
|
1089
|
+
switch (keyword) {
|
|
1090
|
+
case 'if': {
|
|
1091
|
+
fields[identifier].if = parseCondition();
|
|
1092
|
+
break;
|
|
1093
|
+
}
|
|
1094
|
+
case 'span':
|
|
1095
|
+
case 'verticalSpacing': {
|
|
1096
|
+
fields[identifier].span = consume(token_js_1.TokenType.Number).value;
|
|
1097
|
+
break;
|
|
1098
|
+
}
|
|
1099
|
+
case 'separator': {
|
|
1100
|
+
fields[identifier].separator = match(token_js_1.TokenType.Boolean)
|
|
1101
|
+
? consume(token_js_1.TokenType.Boolean).value
|
|
1102
|
+
: consume(token_js_1.TokenType.QuotedString, [
|
|
1103
|
+
'top',
|
|
1104
|
+
'bottom',
|
|
1105
|
+
]).value;
|
|
1106
|
+
break;
|
|
1107
|
+
}
|
|
1108
|
+
default: {
|
|
1109
|
+
throw new diagnostic_js_1.Diagnostic(`invalid keyword "${keyword}"`, keywordLocation);
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
consume(token_js_1.TokenType.RightBracket);
|
|
1114
|
+
}
|
|
1115
|
+
consume(token_js_1.TokenType.RightBracket);
|
|
1116
|
+
break;
|
|
1117
|
+
}
|
|
1118
|
+
default: {
|
|
1119
|
+
throw new diagnostic_js_1.Diagnostic(`invalid keyword "${keyword}"`, keywordLocation);
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
consume(token_js_1.TokenType.RightBracket);
|
|
1124
|
+
return node;
|
|
1125
|
+
};
|
|
1126
|
+
const parseCondition = () => {
|
|
1127
|
+
if (match(token_js_1.TokenType.LeftParens)) {
|
|
1128
|
+
consume(token_js_1.TokenType.LeftParens);
|
|
1129
|
+
let operatorType, newOp = operatorType;
|
|
1130
|
+
const conditions = [];
|
|
1131
|
+
while (!match(token_js_1.TokenType.RightParens)) {
|
|
1132
|
+
conditions.push(parseCondition());
|
|
1133
|
+
if (match(token_js_1.TokenType.RightParens)) {
|
|
1134
|
+
break;
|
|
1135
|
+
}
|
|
1136
|
+
const { value: operatorSymbol, location } = consume(token_js_1.TokenType.Operator);
|
|
1137
|
+
switch (operatorSymbol) {
|
|
1138
|
+
case '&&':
|
|
1139
|
+
newOp = 'and';
|
|
1140
|
+
break;
|
|
1141
|
+
case '||':
|
|
1142
|
+
newOp = 'or';
|
|
1143
|
+
break;
|
|
1144
|
+
default: {
|
|
1145
|
+
throw new diagnostic_js_1.Diagnostic(`unsupported operator: "${operatorSymbol}"`, location);
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
if (operatorType && operatorType !== newOp) {
|
|
1149
|
+
throw new diagnostic_js_1.Diagnostic('having "and" or "or" in the same expression is not supported, please use parenthesis', location);
|
|
1150
|
+
}
|
|
1151
|
+
operatorType = newOp;
|
|
1152
|
+
}
|
|
1153
|
+
consume(token_js_1.TokenType.RightParens);
|
|
1154
|
+
switch (operatorType) {
|
|
1155
|
+
case 'and': {
|
|
1156
|
+
return {
|
|
1157
|
+
and: conditions,
|
|
1158
|
+
};
|
|
1159
|
+
}
|
|
1160
|
+
case 'or': {
|
|
1161
|
+
return {
|
|
1162
|
+
or: conditions,
|
|
1163
|
+
};
|
|
1164
|
+
}
|
|
1165
|
+
default: {
|
|
1166
|
+
return conditions[0];
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
const { value: term1 } = consume(token_js_1.TokenType.Identifier);
|
|
1171
|
+
const { value: operatorSymbol, location } = consume(token_js_1.TokenType.Operator);
|
|
1172
|
+
const { value: term2 } = current();
|
|
1173
|
+
advance();
|
|
1174
|
+
let operator;
|
|
1175
|
+
switch (operatorSymbol) {
|
|
1176
|
+
case '==':
|
|
1177
|
+
operator = 'equal';
|
|
1178
|
+
break;
|
|
1179
|
+
case 'in':
|
|
1180
|
+
operator = 'in';
|
|
1181
|
+
break;
|
|
1182
|
+
case '>=':
|
|
1183
|
+
operator = 'gte';
|
|
1184
|
+
break;
|
|
1185
|
+
case '<=':
|
|
1186
|
+
operator = 'lte';
|
|
1187
|
+
break;
|
|
1188
|
+
case '>':
|
|
1189
|
+
operator = 'gt';
|
|
1190
|
+
break;
|
|
1191
|
+
case '<':
|
|
1192
|
+
operator = 'lt';
|
|
1193
|
+
break;
|
|
1194
|
+
default: {
|
|
1195
|
+
throw new diagnostic_js_1.Diagnostic(`unsuported operator: "${operatorSymbol}"`, location);
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
return {
|
|
1199
|
+
operator,
|
|
1200
|
+
term1,
|
|
1201
|
+
term2,
|
|
1202
|
+
};
|
|
1203
|
+
};
|
|
1054
1204
|
while (index < tokens.length) {
|
|
1055
1205
|
const { value: declType, location } = current();
|
|
1056
1206
|
try {
|
package/dist/parser.mjs
CHANGED
|
@@ -551,6 +551,7 @@ export const parse = (tokens) => {
|
|
|
551
551
|
}
|
|
552
552
|
continue;
|
|
553
553
|
}
|
|
554
|
+
throw err;
|
|
554
555
|
}
|
|
555
556
|
}
|
|
556
557
|
consume(TokenType.RightBracket);
|
|
@@ -676,6 +677,10 @@ export const parse = (tokens) => {
|
|
|
676
677
|
node[keyword] = parseLayoutBlock();
|
|
677
678
|
break;
|
|
678
679
|
}
|
|
680
|
+
case "formLayout": {
|
|
681
|
+
node[keyword] = parseFormLayoutBlock();
|
|
682
|
+
break;
|
|
683
|
+
}
|
|
679
684
|
}
|
|
680
685
|
} catch (err) {
|
|
681
686
|
if (err instanceof Diagnostic) {
|
|
@@ -683,6 +688,7 @@ export const parse = (tokens) => {
|
|
|
683
688
|
recover(lexer.COLLECTION_KEYWORDS);
|
|
684
689
|
continue;
|
|
685
690
|
}
|
|
691
|
+
throw err;
|
|
686
692
|
}
|
|
687
693
|
}
|
|
688
694
|
consume(TokenType.RightBracket);
|
|
@@ -777,6 +783,7 @@ export const parse = (tokens) => {
|
|
|
777
783
|
errors.push(err);
|
|
778
784
|
continue;
|
|
779
785
|
}
|
|
786
|
+
throw err;
|
|
780
787
|
}
|
|
781
788
|
}
|
|
782
789
|
consume(TokenType.RightBracket);
|
|
@@ -991,6 +998,146 @@ export const parse = (tokens) => {
|
|
|
991
998
|
}
|
|
992
999
|
};
|
|
993
1000
|
};
|
|
1001
|
+
const parseFormLayoutBlock = () => {
|
|
1002
|
+
const fields = {};
|
|
1003
|
+
const node = {
|
|
1004
|
+
kind: "formLayout",
|
|
1005
|
+
fields,
|
|
1006
|
+
[AST.LOCATION_SYMBOL]: {
|
|
1007
|
+
fields: {}
|
|
1008
|
+
}
|
|
1009
|
+
};
|
|
1010
|
+
consume(TokenType.LeftBracket);
|
|
1011
|
+
while (!match(TokenType.RightBracket)) {
|
|
1012
|
+
const { value: keyword, location: keywordLocation } = consume(TokenType.Keyword, lexer.COLLECTION_FORM_LAYOUT_KEYWORDS);
|
|
1013
|
+
switch (keyword) {
|
|
1014
|
+
case "fields": {
|
|
1015
|
+
consume(TokenType.LeftBracket);
|
|
1016
|
+
while (!match(TokenType.RightBracket)) {
|
|
1017
|
+
const { value: identifier, location: identifierLocation } = consume(TokenType.Identifier);
|
|
1018
|
+
const identifierSymbol = Symbol();
|
|
1019
|
+
locationMap.set(identifierSymbol, identifierLocation);
|
|
1020
|
+
fields[identifier] ??= {};
|
|
1021
|
+
node[AST.LOCATION_SYMBOL].fields[identifier] = {
|
|
1022
|
+
name: identifierSymbol,
|
|
1023
|
+
field: {}
|
|
1024
|
+
};
|
|
1025
|
+
consume(TokenType.LeftBracket);
|
|
1026
|
+
while (!match(TokenType.RightBracket)) {
|
|
1027
|
+
const { value: keyword2, location: keywordLocation2 } = consume(TokenType.Keyword, lexer.COLLECTION_FORM_LAYOUT_KEYWORDS);
|
|
1028
|
+
switch (keyword2) {
|
|
1029
|
+
case "if": {
|
|
1030
|
+
fields[identifier].if = parseCondition();
|
|
1031
|
+
break;
|
|
1032
|
+
}
|
|
1033
|
+
case "span":
|
|
1034
|
+
case "verticalSpacing": {
|
|
1035
|
+
fields[identifier].span = consume(TokenType.Number).value;
|
|
1036
|
+
break;
|
|
1037
|
+
}
|
|
1038
|
+
case "separator": {
|
|
1039
|
+
fields[identifier].separator = match(TokenType.Boolean) ? consume(TokenType.Boolean).value : consume(TokenType.QuotedString, [
|
|
1040
|
+
"top",
|
|
1041
|
+
"bottom"
|
|
1042
|
+
]).value;
|
|
1043
|
+
break;
|
|
1044
|
+
}
|
|
1045
|
+
default: {
|
|
1046
|
+
throw new Diagnostic(`invalid keyword "${keyword2}"`, keywordLocation2);
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
consume(TokenType.RightBracket);
|
|
1051
|
+
}
|
|
1052
|
+
consume(TokenType.RightBracket);
|
|
1053
|
+
break;
|
|
1054
|
+
}
|
|
1055
|
+
default: {
|
|
1056
|
+
throw new Diagnostic(`invalid keyword "${keyword}"`, keywordLocation);
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
consume(TokenType.RightBracket);
|
|
1061
|
+
return node;
|
|
1062
|
+
};
|
|
1063
|
+
const parseCondition = () => {
|
|
1064
|
+
if (match(TokenType.LeftParens)) {
|
|
1065
|
+
consume(TokenType.LeftParens);
|
|
1066
|
+
let operatorType, newOp = operatorType;
|
|
1067
|
+
const conditions = [];
|
|
1068
|
+
while (!match(TokenType.RightParens)) {
|
|
1069
|
+
conditions.push(parseCondition());
|
|
1070
|
+
if (match(TokenType.RightParens)) {
|
|
1071
|
+
break;
|
|
1072
|
+
}
|
|
1073
|
+
const { value: operatorSymbol2, location: location2 } = consume(TokenType.Operator);
|
|
1074
|
+
switch (operatorSymbol2) {
|
|
1075
|
+
case "&&":
|
|
1076
|
+
newOp = "and";
|
|
1077
|
+
break;
|
|
1078
|
+
case "||":
|
|
1079
|
+
newOp = "or";
|
|
1080
|
+
break;
|
|
1081
|
+
default: {
|
|
1082
|
+
throw new Diagnostic(`unsupported operator: "${operatorSymbol2}"`, location2);
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
if (operatorType && operatorType !== newOp) {
|
|
1086
|
+
throw new Diagnostic('having "and" or "or" in the same expression is not supported, please use parenthesis', location2);
|
|
1087
|
+
}
|
|
1088
|
+
operatorType = newOp;
|
|
1089
|
+
}
|
|
1090
|
+
consume(TokenType.RightParens);
|
|
1091
|
+
switch (operatorType) {
|
|
1092
|
+
case "and": {
|
|
1093
|
+
return {
|
|
1094
|
+
and: conditions
|
|
1095
|
+
};
|
|
1096
|
+
}
|
|
1097
|
+
case "or": {
|
|
1098
|
+
return {
|
|
1099
|
+
or: conditions
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
default: {
|
|
1103
|
+
return conditions[0];
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
const { value: term1 } = consume(TokenType.Identifier);
|
|
1108
|
+
const { value: operatorSymbol, location } = consume(TokenType.Operator);
|
|
1109
|
+
const { value: term2 } = current();
|
|
1110
|
+
advance();
|
|
1111
|
+
let operator;
|
|
1112
|
+
switch (operatorSymbol) {
|
|
1113
|
+
case "==":
|
|
1114
|
+
operator = "equal";
|
|
1115
|
+
break;
|
|
1116
|
+
case "in":
|
|
1117
|
+
operator = "in";
|
|
1118
|
+
break;
|
|
1119
|
+
case ">=":
|
|
1120
|
+
operator = "gte";
|
|
1121
|
+
break;
|
|
1122
|
+
case "<=":
|
|
1123
|
+
operator = "lte";
|
|
1124
|
+
break;
|
|
1125
|
+
case ">":
|
|
1126
|
+
operator = "gt";
|
|
1127
|
+
break;
|
|
1128
|
+
case "<":
|
|
1129
|
+
operator = "lt";
|
|
1130
|
+
break;
|
|
1131
|
+
default: {
|
|
1132
|
+
throw new Diagnostic(`unsuported operator: "${operatorSymbol}"`, location);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
return {
|
|
1136
|
+
operator,
|
|
1137
|
+
term1,
|
|
1138
|
+
term2
|
|
1139
|
+
};
|
|
1140
|
+
};
|
|
994
1141
|
while (index < tokens.length) {
|
|
995
1142
|
const { value: declType, location } = current();
|
|
996
1143
|
try {
|
package/dist/semantic.js
CHANGED
|
@@ -160,6 +160,16 @@ const analyze = async (ast, options, errors = []) => {
|
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
|
+
if (node.formLayout) {
|
|
164
|
+
if (node.formLayout.fields) {
|
|
165
|
+
for (const [name, value] of Object.entries(node.formLayout[AST.LOCATION_SYMBOL].fields)) {
|
|
166
|
+
if (!(name in node.properties)) {
|
|
167
|
+
const location = parser_js_1.locationMap.get(value.name);
|
|
168
|
+
errors.push(new diagnostic_js_1.Diagnostic(`invalid property "${name}"`, location));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
163
173
|
}
|
|
164
174
|
for (const node of ast.contracts) {
|
|
165
175
|
if (node.payload) {
|
package/dist/semantic.mjs
CHANGED
|
@@ -122,6 +122,16 @@ export const analyze = async (ast, options, errors = []) => {
|
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
|
+
if (node.formLayout) {
|
|
126
|
+
if (node.formLayout.fields) {
|
|
127
|
+
for (const [name, value] of Object.entries(node.formLayout[AST.LOCATION_SYMBOL].fields)) {
|
|
128
|
+
if (!(name in node.properties)) {
|
|
129
|
+
const location = locationMap.get(value.name);
|
|
130
|
+
errors.push(new Diagnostic(`invalid property "${name}"`, location));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
125
135
|
}
|
|
126
136
|
for (const node of ast.contracts) {
|
|
127
137
|
if (node.payload) {
|
package/dist/token.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ export declare const TokenType: {
|
|
|
19
19
|
readonly AttributeName: "ATTRIBUTE_NAME";
|
|
20
20
|
readonly MacroName: "MACRO_NAME";
|
|
21
21
|
readonly Range: "RANGE";
|
|
22
|
+
readonly Operator: "OPERATOR";
|
|
22
23
|
};
|
|
23
24
|
export type TokenType = typeof TokenType[keyof typeof TokenType];
|
|
24
25
|
export type TypeMap = {
|
package/dist/token.js
CHANGED
package/dist/token.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aeriajs/compiler",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.27",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
"dist"
|
|
22
22
|
],
|
|
23
23
|
"peerDependencies": {
|
|
24
|
-
"@aeriajs/common": "^0.0.
|
|
25
|
-
"@aeriajs/types": "^0.0.
|
|
24
|
+
"@aeriajs/common": "^0.0.142",
|
|
25
|
+
"@aeriajs/types": "^0.0.124"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@aeriajs/common": "link:../common",
|