@aeriajs/compiler 0.0.24 → 0.0.26
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 +9 -2
- package/dist/codegen/generateTSCollections.js +3 -0
- package/dist/codegen/generateTSCollections.mjs +3 -0
- package/dist/lexer.js +23 -10
- package/dist/lexer.mjs +23 -10
- package/dist/parser.js +17 -3
- package/dist/parser.mjs +18 -4
- package/dist/semantic.js +22 -1
- package/dist/semantic.mjs +21 -1
- package/package.json +1 -1
package/dist/ast.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Property, AccessCondition, CollectionActions, SearchOptions, DescriptionPreset, Icon, OwnershipMode, Layout } from '@aeriajs/types';
|
|
1
|
+
import type { Property, AccessCondition, CollectionActions, SearchOptions, DescriptionPreset, Icon, OwnershipMode, Layout, LayoutOptions } 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: {
|
|
@@ -19,6 +19,13 @@ export type ExportSymbol = {
|
|
|
19
19
|
export type NodeBase<TType> = {
|
|
20
20
|
kind: TType;
|
|
21
21
|
};
|
|
22
|
+
export type LayoutNode = NodeBase<'layout'> & Layout & {
|
|
23
|
+
[LOCATION_SYMBOL]: {
|
|
24
|
+
options: {
|
|
25
|
+
[P in keyof LayoutOptions]?: readonly string[] extends LayoutOptions[P] ? symbol | symbol[] : symbol;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
};
|
|
22
29
|
export type PropertyNode = NodeBase<'property'> & {
|
|
23
30
|
modifier?: keyof typeof PropertyModifiers;
|
|
24
31
|
property: Property & {
|
|
@@ -53,7 +60,7 @@ export type CollectionNode = NodeBase<'collection'> & {
|
|
|
53
60
|
table?: string[];
|
|
54
61
|
filters?: string[];
|
|
55
62
|
search?: SearchOptions<any>;
|
|
56
|
-
layout?:
|
|
63
|
+
layout?: LayoutNode;
|
|
57
64
|
[LOCATION_SYMBOL]: {
|
|
58
65
|
arrays: {
|
|
59
66
|
[P in ArrayProperties<CollectionNode>]?: symbol[];
|
|
@@ -87,6 +87,9 @@ 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;
|
|
90
93
|
case 'required':
|
|
91
94
|
collectionSchema.description[key] = collectionNode[key];
|
|
92
95
|
break;
|
|
@@ -82,6 +82,9 @@ 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;
|
|
85
88
|
case "required":
|
|
86
89
|
collectionSchema.description[key] = collectionNode[key];
|
|
87
90
|
break;
|
package/dist/lexer.js
CHANGED
|
@@ -149,7 +149,20 @@ const TOKENS = [
|
|
|
149
149
|
{
|
|
150
150
|
type: token_js_1.TokenType.Keyword,
|
|
151
151
|
matcher: Array.from(keywordsSet),
|
|
152
|
-
condition: (state) =>
|
|
152
|
+
condition: (state, lastToken) => {
|
|
153
|
+
if (state.variableScopeStack.at(-1)) {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
if (lastToken && lastToken.type === token_js_1.TokenType.Keyword) {
|
|
157
|
+
switch (lastToken.value) {
|
|
158
|
+
case 'badge':
|
|
159
|
+
case 'title': {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return true;
|
|
165
|
+
},
|
|
153
166
|
},
|
|
154
167
|
{
|
|
155
168
|
type: token_js_1.TokenType.MacroName,
|
|
@@ -177,15 +190,16 @@ const tokenize = function (rawInput) {
|
|
|
177
190
|
const tokens = [];
|
|
178
191
|
const errors = [];
|
|
179
192
|
const state = {
|
|
180
|
-
|
|
193
|
+
variableScopeStack: [],
|
|
181
194
|
};
|
|
182
195
|
while (index < input.length) {
|
|
183
196
|
let hasMatch = false;
|
|
184
197
|
for (const { type, matcher, valueExtractor, construct, condition } of TOKENS) {
|
|
185
198
|
let value;
|
|
186
199
|
let token;
|
|
200
|
+
const lastToken = tokens.at(-1);
|
|
187
201
|
if (condition) {
|
|
188
|
-
if (!condition(state)) {
|
|
202
|
+
if (!condition(state, lastToken)) {
|
|
189
203
|
continue;
|
|
190
204
|
}
|
|
191
205
|
}
|
|
@@ -246,9 +260,10 @@ const tokenize = function (rawInput) {
|
|
|
246
260
|
};
|
|
247
261
|
switch (type) {
|
|
248
262
|
case token_js_1.TokenType.LeftBracket: {
|
|
249
|
-
|
|
263
|
+
let variableScope = false;
|
|
250
264
|
if (lastToken && lastToken.type === token_js_1.TokenType.Keyword) {
|
|
251
265
|
switch (lastToken.value) {
|
|
266
|
+
case 'information':
|
|
252
267
|
case 'form':
|
|
253
268
|
case 'table':
|
|
254
269
|
case 'indexes':
|
|
@@ -256,19 +271,17 @@ const tokenize = function (rawInput) {
|
|
|
256
271
|
case 'writable':
|
|
257
272
|
case 'required':
|
|
258
273
|
case 'properties': {
|
|
259
|
-
|
|
274
|
+
variableScope = true;
|
|
260
275
|
break;
|
|
261
276
|
}
|
|
262
|
-
default: {
|
|
263
|
-
state.inPropertiesStack.push(false);
|
|
264
|
-
}
|
|
265
277
|
}
|
|
266
278
|
}
|
|
279
|
+
state.variableScopeStack.push(variableScope);
|
|
267
280
|
break;
|
|
268
281
|
}
|
|
269
282
|
case token_js_1.TokenType.RightBracket: {
|
|
270
|
-
if (state.
|
|
271
|
-
state.
|
|
283
|
+
if (state.variableScopeStack.length > 0) {
|
|
284
|
+
state.variableScopeStack.pop();
|
|
272
285
|
}
|
|
273
286
|
break;
|
|
274
287
|
}
|
package/dist/lexer.mjs
CHANGED
|
@@ -156,7 +156,20 @@ const TOKENS = [
|
|
|
156
156
|
{
|
|
157
157
|
type: TokenType.Keyword,
|
|
158
158
|
matcher: Array.from(keywordsSet),
|
|
159
|
-
condition: (state) =>
|
|
159
|
+
condition: (state, lastToken) => {
|
|
160
|
+
if (state.variableScopeStack.at(-1)) {
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
if (lastToken && lastToken.type === TokenType.Keyword) {
|
|
164
|
+
switch (lastToken.value) {
|
|
165
|
+
case "badge":
|
|
166
|
+
case "title": {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
160
173
|
},
|
|
161
174
|
{
|
|
162
175
|
type: TokenType.MacroName,
|
|
@@ -184,15 +197,16 @@ export const tokenize = function(rawInput) {
|
|
|
184
197
|
const tokens = [];
|
|
185
198
|
const errors = [];
|
|
186
199
|
const state = {
|
|
187
|
-
|
|
200
|
+
variableScopeStack: []
|
|
188
201
|
};
|
|
189
202
|
while (index < input.length) {
|
|
190
203
|
let hasMatch = false;
|
|
191
204
|
for (const { type, matcher, valueExtractor, construct, condition } of TOKENS) {
|
|
192
205
|
let value;
|
|
193
206
|
let token;
|
|
207
|
+
const lastToken = tokens.at(-1);
|
|
194
208
|
if (condition) {
|
|
195
|
-
if (!condition(state)) {
|
|
209
|
+
if (!condition(state, lastToken)) {
|
|
196
210
|
continue;
|
|
197
211
|
}
|
|
198
212
|
}
|
|
@@ -248,9 +262,10 @@ export const tokenize = function(rawInput) {
|
|
|
248
262
|
};
|
|
249
263
|
switch (type) {
|
|
250
264
|
case TokenType.LeftBracket: {
|
|
251
|
-
|
|
265
|
+
let variableScope = false;
|
|
252
266
|
if (lastToken && lastToken.type === TokenType.Keyword) {
|
|
253
267
|
switch (lastToken.value) {
|
|
268
|
+
case "information":
|
|
254
269
|
case "form":
|
|
255
270
|
case "table":
|
|
256
271
|
case "indexes":
|
|
@@ -258,19 +273,17 @@ export const tokenize = function(rawInput) {
|
|
|
258
273
|
case "writable":
|
|
259
274
|
case "required":
|
|
260
275
|
case "properties": {
|
|
261
|
-
|
|
276
|
+
variableScope = true;
|
|
262
277
|
break;
|
|
263
278
|
}
|
|
264
|
-
default: {
|
|
265
|
-
state.inPropertiesStack.push(false);
|
|
266
|
-
}
|
|
267
279
|
}
|
|
268
280
|
}
|
|
281
|
+
state.variableScopeStack.push(variableScope);
|
|
269
282
|
break;
|
|
270
283
|
}
|
|
271
284
|
case TokenType.RightBracket: {
|
|
272
|
-
if (state.
|
|
273
|
-
state.
|
|
285
|
+
if (state.variableScopeStack.length > 0) {
|
|
286
|
+
state.variableScopeStack.pop();
|
|
274
287
|
}
|
|
275
288
|
break;
|
|
276
289
|
}
|
package/dist/parser.js
CHANGED
|
@@ -985,6 +985,7 @@ const parse = (tokens) => {
|
|
|
985
985
|
const parseLayoutBlock = () => {
|
|
986
986
|
let name;
|
|
987
987
|
const options = {};
|
|
988
|
+
const optionsSymbols = {};
|
|
988
989
|
const { location } = consume(token_js_1.TokenType.LeftBracket);
|
|
989
990
|
while (!match(token_js_1.TokenType.RightBracket)) {
|
|
990
991
|
const { value: keyword } = consume(token_js_1.TokenType.Keyword, lexer.COLLECTION_LAYOUT_KEYWORDS);
|
|
@@ -1003,16 +1004,25 @@ const parse = (tokens) => {
|
|
|
1003
1004
|
case 'title':
|
|
1004
1005
|
case 'picture':
|
|
1005
1006
|
case 'badge': {
|
|
1006
|
-
const { value } = consume(token_js_1.TokenType.
|
|
1007
|
+
const { value, location } = consume(token_js_1.TokenType.Identifier);
|
|
1008
|
+
const symbol = Symbol();
|
|
1007
1009
|
options[optionsKeyword] = value;
|
|
1010
|
+
optionsSymbols[optionsKeyword] = symbol;
|
|
1011
|
+
exports.locationMap.set(symbol, location);
|
|
1008
1012
|
break;
|
|
1009
1013
|
}
|
|
1010
1014
|
case 'information': {
|
|
1011
1015
|
if (match(token_js_1.TokenType.LeftBracket)) {
|
|
1012
|
-
|
|
1016
|
+
const { value, symbols } = parseArrayBlock();
|
|
1017
|
+
options[optionsKeyword] = value;
|
|
1018
|
+
optionsSymbols[optionsKeyword] = symbols;
|
|
1013
1019
|
}
|
|
1014
1020
|
else {
|
|
1015
|
-
|
|
1021
|
+
const { value, location } = consume(token_js_1.TokenType.Identifier);
|
|
1022
|
+
const symbol = Symbol();
|
|
1023
|
+
options[optionsKeyword] = value;
|
|
1024
|
+
optionsSymbols[optionsKeyword] = symbol;
|
|
1025
|
+
exports.locationMap.set(symbol, location);
|
|
1016
1026
|
}
|
|
1017
1027
|
break;
|
|
1018
1028
|
}
|
|
@@ -1033,8 +1043,12 @@ const parse = (tokens) => {
|
|
|
1033
1043
|
}
|
|
1034
1044
|
consume(token_js_1.TokenType.RightBracket);
|
|
1035
1045
|
return {
|
|
1046
|
+
kind: 'layout',
|
|
1036
1047
|
name,
|
|
1037
1048
|
options,
|
|
1049
|
+
[AST.LOCATION_SYMBOL]: {
|
|
1050
|
+
options: optionsSymbols,
|
|
1051
|
+
},
|
|
1038
1052
|
};
|
|
1039
1053
|
};
|
|
1040
1054
|
while (index < tokens.length) {
|
package/dist/parser.mjs
CHANGED
|
@@ -926,6 +926,7 @@ export const parse = (tokens) => {
|
|
|
926
926
|
const parseLayoutBlock = () => {
|
|
927
927
|
let name;
|
|
928
928
|
const options = {};
|
|
929
|
+
const optionsSymbols = {};
|
|
929
930
|
const { location } = consume(TokenType.LeftBracket);
|
|
930
931
|
while (!match(TokenType.RightBracket)) {
|
|
931
932
|
const { value: keyword } = consume(TokenType.Keyword, lexer.COLLECTION_LAYOUT_KEYWORDS);
|
|
@@ -944,15 +945,24 @@ export const parse = (tokens) => {
|
|
|
944
945
|
case "title":
|
|
945
946
|
case "picture":
|
|
946
947
|
case "badge": {
|
|
947
|
-
const { value } = consume(TokenType.
|
|
948
|
+
const { value, location: location2 } = consume(TokenType.Identifier);
|
|
949
|
+
const symbol = Symbol();
|
|
948
950
|
options[optionsKeyword] = value;
|
|
951
|
+
optionsSymbols[optionsKeyword] = symbol;
|
|
952
|
+
locationMap.set(symbol, location2);
|
|
949
953
|
break;
|
|
950
954
|
}
|
|
951
955
|
case "information": {
|
|
952
956
|
if (match(TokenType.LeftBracket)) {
|
|
953
|
-
|
|
957
|
+
const { value, symbols } = parseArrayBlock();
|
|
958
|
+
options[optionsKeyword] = value;
|
|
959
|
+
optionsSymbols[optionsKeyword] = symbols;
|
|
954
960
|
} else {
|
|
955
|
-
|
|
961
|
+
const { value, location: location2 } = consume(TokenType.Identifier);
|
|
962
|
+
const symbol = Symbol();
|
|
963
|
+
options[optionsKeyword] = value;
|
|
964
|
+
optionsSymbols[optionsKeyword] = symbol;
|
|
965
|
+
locationMap.set(symbol, location2);
|
|
956
966
|
}
|
|
957
967
|
break;
|
|
958
968
|
}
|
|
@@ -973,8 +983,12 @@ export const parse = (tokens) => {
|
|
|
973
983
|
}
|
|
974
984
|
consume(TokenType.RightBracket);
|
|
975
985
|
return {
|
|
986
|
+
kind: "layout",
|
|
976
987
|
name,
|
|
977
|
-
options
|
|
988
|
+
options,
|
|
989
|
+
[AST.LOCATION_SYMBOL]: {
|
|
990
|
+
options: optionsSymbols
|
|
991
|
+
}
|
|
978
992
|
};
|
|
979
993
|
};
|
|
980
994
|
while (index < tokens.length) {
|
package/dist/semantic.js
CHANGED
|
@@ -92,7 +92,7 @@ const analyze = async (ast, options, errors = []) => {
|
|
|
92
92
|
const symbol = node.property[AST.LOCATION_SYMBOL].arrays[attributeName][index];
|
|
93
93
|
if (!(propName in node.property.properties)) {
|
|
94
94
|
const location = parser_js_1.locationMap.get(symbol);
|
|
95
|
-
errors.push(new diagnostic_js_1.Diagnostic(`object
|
|
95
|
+
errors.push(new diagnostic_js_1.Diagnostic(`object hasn't such property "${propName}"`, location));
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
};
|
|
@@ -139,6 +139,27 @@ const analyze = async (ast, options, errors = []) => {
|
|
|
139
139
|
const subNode = node.properties[propName];
|
|
140
140
|
await recurseProperty(subNode);
|
|
141
141
|
}
|
|
142
|
+
if (node.layout) {
|
|
143
|
+
if (node.layout.options) {
|
|
144
|
+
for (const [name, value] of Object.entries(node.layout[AST.LOCATION_SYMBOL].options)) {
|
|
145
|
+
const option = node.layout.options[name];
|
|
146
|
+
if (Array.isArray(option)) {
|
|
147
|
+
for (const [i, propName] of option.entries()) {
|
|
148
|
+
if (!(propName in node.properties)) {
|
|
149
|
+
const location = parser_js_1.locationMap.get(value[i]);
|
|
150
|
+
errors.push(new diagnostic_js_1.Diagnostic(`invalid property "${propName}"`, location));
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
if (!(option in node.properties)) {
|
|
156
|
+
const location = parser_js_1.locationMap.get(value);
|
|
157
|
+
errors.push(new diagnostic_js_1.Diagnostic(`invalid property "${option}"`, location));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
142
163
|
}
|
|
143
164
|
for (const node of ast.contracts) {
|
|
144
165
|
if (node.payload) {
|
package/dist/semantic.mjs
CHANGED
|
@@ -57,7 +57,7 @@ export const analyze = async (ast, options, errors = []) => {
|
|
|
57
57
|
const symbol = node.property[AST.LOCATION_SYMBOL].arrays[attributeName][index];
|
|
58
58
|
if (!(propName in node.property.properties)) {
|
|
59
59
|
const location = locationMap.get(symbol);
|
|
60
|
-
errors.push(new Diagnostic(`object
|
|
60
|
+
errors.push(new Diagnostic(`object hasn't such property "${propName}"`, location));
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
};
|
|
@@ -102,6 +102,26 @@ export const analyze = async (ast, options, errors = []) => {
|
|
|
102
102
|
const subNode = node.properties[propName];
|
|
103
103
|
await recurseProperty(subNode);
|
|
104
104
|
}
|
|
105
|
+
if (node.layout) {
|
|
106
|
+
if (node.layout.options) {
|
|
107
|
+
for (const [name, value] of Object.entries(node.layout[AST.LOCATION_SYMBOL].options)) {
|
|
108
|
+
const option = node.layout.options[name];
|
|
109
|
+
if (Array.isArray(option)) {
|
|
110
|
+
for (const [i, propName] of option.entries()) {
|
|
111
|
+
if (!(propName in node.properties)) {
|
|
112
|
+
const location = locationMap.get(value[i]);
|
|
113
|
+
errors.push(new Diagnostic(`invalid property "${propName}"`, location));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
} else {
|
|
117
|
+
if (!(option in node.properties)) {
|
|
118
|
+
const location = locationMap.get(value);
|
|
119
|
+
errors.push(new Diagnostic(`invalid property "${option}"`, location));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
105
125
|
}
|
|
106
126
|
for (const node of ast.contracts) {
|
|
107
127
|
if (node.payload) {
|