@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 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?: 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) => !state.inPropertiesStack.at(-1),
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
- inPropertiesStack: [],
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
- const lastToken = tokens.at(-1);
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
- state.inPropertiesStack.push(true);
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.inPropertiesStack.length > 0) {
271
- state.inPropertiesStack.pop();
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) => !state.inPropertiesStack.at(-1)
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
- inPropertiesStack: []
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
- const lastToken = tokens.at(-1);
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
- state.inPropertiesStack.push(true);
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.inPropertiesStack.length > 0) {
273
- state.inPropertiesStack.pop();
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.QuotedString);
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
- options[optionsKeyword] = parseArrayBlock().value;
1016
+ const { value, symbols } = parseArrayBlock();
1017
+ options[optionsKeyword] = value;
1018
+ optionsSymbols[optionsKeyword] = symbols;
1013
1019
  }
1014
1020
  else {
1015
- options[optionsKeyword] = consume(token_js_1.TokenType.QuotedString).value;
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.QuotedString);
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
- options[optionsKeyword] = parseArrayBlock().value;
957
+ const { value, symbols } = parseArrayBlock();
958
+ options[optionsKeyword] = value;
959
+ optionsSymbols[optionsKeyword] = symbols;
954
960
  } else {
955
- options[optionsKeyword] = consume(TokenType.QuotedString).value;
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 "xxx" hasn't such property "${propName}"`, location));
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 "xxx" hasn't such property "${propName}"`, location));
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) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aeriajs/compiler",
3
- "version": "0.0.24",
3
+ "version": "0.0.26",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",