@aeriajs/compiler 0.0.30 → 0.0.32

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, LayoutOptions, FormLayout, Description, FormLayoutField } from '@aeriajs/types';
1
+ import type { Property, AccessCondition, CollectionActions, SearchOptions, DescriptionPreset, Icon, OwnershipMode, Layout, LayoutOptions, FormLayout, Description, FormLayoutField, RequiredProperties } 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: {
@@ -34,7 +34,7 @@ export type FormLayoutNode = NodeBase<'formLayout'> & FormLayout<Description> &
34
34
  field: FormLayoutField<Description>;
35
35
  };
36
36
  };
37
- terms?: [string, symbol][];
37
+ terms?: readonly [string, symbol][];
38
38
  };
39
39
  };
40
40
  export type PropertyNode = NodeBase<'property'> & {
@@ -56,6 +56,7 @@ export type PropertyNode = NodeBase<'property'> & {
56
56
  export type CollectionNode = NodeBase<'collection'> & {
57
57
  name: string;
58
58
  extends?: ExportSymbol;
59
+ middlewares?: readonly string[];
59
60
  owned?: OwnershipMode;
60
61
  icon?: Icon;
61
62
  actions?: CollectionActions;
@@ -64,13 +65,13 @@ export type CollectionNode = NodeBase<'collection'> & {
64
65
  functions?: Record<string, {
65
66
  accessCondition: AccessCondition;
66
67
  }>;
67
- required?: Record<string, unknown> | string[];
68
- indexes?: string[];
68
+ required?: RequiredProperties;
69
+ indexes?: readonly string[];
69
70
  presets?: DescriptionPreset[];
70
- form?: string[];
71
- table?: string[];
72
- tableMeta?: string[];
73
- filters?: string[];
71
+ form?: readonly string[];
72
+ table?: readonly string[];
73
+ tableMeta?: readonly string[];
74
+ filters?: readonly string[];
74
75
  search?: SearchOptions<any>;
75
76
  layout?: LayoutNode;
76
77
  formLayout?: FormLayoutNode;
@@ -78,6 +79,7 @@ export type CollectionNode = NodeBase<'collection'> & {
78
79
  arrays: {
79
80
  [P in ArrayProperties<CollectionNode>]?: symbol[];
80
81
  };
82
+ requiredTerms?: readonly [string, symbol][];
81
83
  };
82
84
  };
83
85
  export type ContractNode = NodeBase<'contract'> & {
@@ -11,7 +11,7 @@ const generateJSCollections = (ast) => {
11
11
  const importsResult = (0, utils_js_1.makeASTImports)(ast, {
12
12
  [utils_js_1.PACKAGE_NAME]: new Set(initialImportedFunctions),
13
13
  });
14
- javascriptCode += importsResult.code + '\n\n';
14
+ javascriptCode += importsResult.code.join('\n') + '\n\n';
15
15
  javascriptCode += makeJSCollections(ast, importsResult.modifiedSymbols) + '\n\n';
16
16
  return javascriptCode;
17
17
  };
@@ -37,8 +37,10 @@ const makeJSCollections = (ast, modifiedSymbols) => {
37
37
  };
38
38
  const makeJSCollectionSchema = (collectionNode, collectionId) => {
39
39
  const collectionSchema = {
40
+ item: {},
40
41
  description: {
41
42
  $id: collectionId,
43
+ properties: {},
42
44
  },
43
45
  };
44
46
  for (const key of Object.keys(collectionNode)) {
@@ -52,6 +54,11 @@ const makeJSCollectionSchema = (collectionNode, collectionId) => {
52
54
  case 'owned':
53
55
  collectionSchema.description[key] = collectionNode[key];
54
56
  break;
57
+ case 'middlewares':
58
+ collectionSchema.middlewares = {
59
+ [utils_js_1.UnquotedSymbol]: `[ ${collectionNode[key].join(', ')} ]`,
60
+ };
61
+ break;
55
62
  case 'functions':
56
63
  collectionSchema.functions = {
57
64
  [utils_js_1.UnquotedSymbol]: `{ ${makeJSFunctions(collectionNode[key])} }`,
@@ -9,7 +9,7 @@ export const generateJSCollections = (ast) => {
9
9
  const importsResult = makeASTImports(ast, {
10
10
  [PACKAGE_NAME]: new Set(initialImportedFunctions)
11
11
  });
12
- javascriptCode += importsResult.code + "\n\n";
12
+ javascriptCode += importsResult.code.join("\n") + "\n\n";
13
13
  javascriptCode += makeJSCollections(ast, importsResult.modifiedSymbols) + "\n\n";
14
14
  return javascriptCode;
15
15
  };
@@ -30,8 +30,10 @@ const makeJSCollections = (ast, modifiedSymbols) => {
30
30
  };
31
31
  const makeJSCollectionSchema = (collectionNode, collectionId) => {
32
32
  const collectionSchema = {
33
+ item: {},
33
34
  description: {
34
- $id: collectionId
35
+ $id: collectionId,
36
+ properties: {}
35
37
  }
36
38
  };
37
39
  for (const key of Object.keys(collectionNode)) {
@@ -45,6 +47,11 @@ const makeJSCollectionSchema = (collectionNode, collectionId) => {
45
47
  case "owned":
46
48
  collectionSchema.description[key] = collectionNode[key];
47
49
  break;
50
+ case "middlewares":
51
+ collectionSchema.middlewares = {
52
+ [UnquotedSymbol]: `[ ${collectionNode[key].join(", ")} ]`
53
+ };
54
+ break;
48
55
  case "functions":
49
56
  collectionSchema.functions = {
50
57
  [UnquotedSymbol]: `{ ${makeJSFunctions(collectionNode[key])} }`
@@ -12,7 +12,7 @@ const generateTSCollections = (ast) => {
12
12
  let code = '';
13
13
  code += `import type { ${initialImportedTypes.join(', ')} } from '${utils_js_1.PACKAGE_NAME}'\n`; //Used types
14
14
  const importsResult = (0, utils_js_1.makeASTImports)(ast);
15
- code += importsResult.code + '\n\n';
15
+ code += importsResult.code.join('\n') + '\n\n';
16
16
  code += makeTSCollections(ast, importsResult.modifiedSymbols) + '\n';
17
17
  return code;
18
18
  };
@@ -49,8 +49,10 @@ const makeTSCollections = (ast, modifiedSymbols) => {
49
49
  };
50
50
  const makeTSCollectionSchema = (collectionNode, collectionId) => {
51
51
  const collectionSchema = {
52
+ item: {},
52
53
  description: {
53
54
  $id: collectionId,
55
+ properties: {},
54
56
  },
55
57
  };
56
58
  for (const key of Object.keys(collectionNode)) {
@@ -11,7 +11,7 @@ export const generateTSCollections = (ast) => {
11
11
  code += `import type { ${initialImportedTypes.join(", ")} } from '${PACKAGE_NAME}'
12
12
  `;
13
13
  const importsResult = makeASTImports(ast);
14
- code += importsResult.code + "\n\n";
14
+ code += importsResult.code.join("\n") + "\n\n";
15
15
  code += makeTSCollections(ast, importsResult.modifiedSymbols) + "\n";
16
16
  return code;
17
17
  };
@@ -44,8 +44,10 @@ const makeTSCollections = (ast, modifiedSymbols) => {
44
44
  };
45
45
  const makeTSCollectionSchema = (collectionNode, collectionId) => {
46
46
  const collectionSchema = {
47
+ item: {},
47
48
  description: {
48
- $id: collectionId
49
+ $id: collectionId,
50
+ properties: {}
49
51
  }
50
52
  };
51
53
  for (const key of Object.keys(collectionNode)) {
@@ -1,6 +1,7 @@
1
1
  import type * as AST from '../ast.js';
2
2
  import type { Property } from '@aeriajs/types';
3
3
  export declare const PACKAGE_NAME = "aeria";
4
+ export declare const MIDDLEWARES_RUNTIME_PATH = "../../../dist/middlewares/index.js";
4
5
  export declare const DEFAULT_FUNCTIONS: string[];
5
6
  export declare const ArraySymbol: unique symbol;
6
7
  export declare const getExposedFunctions: (astFunctions: NonNullable<AST.CollectionNode["functions"]>) => {
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getExtendName = exports.getCollectionId = exports.resizeFirstChar = exports.stringify = exports.UnquotedSymbol = exports.recursivelyUnwrapPropertyNodes = exports.unwrapPropertyNode = exports.unwrapNode = exports.makeASTImports = exports.getExposedFunctions = exports.ArraySymbol = exports.DEFAULT_FUNCTIONS = exports.PACKAGE_NAME = void 0;
3
+ exports.getExtendName = exports.getCollectionId = exports.resizeFirstChar = exports.stringify = exports.UnquotedSymbol = exports.recursivelyUnwrapPropertyNodes = exports.unwrapPropertyNode = exports.unwrapNode = exports.makeASTImports = exports.getExposedFunctions = exports.ArraySymbol = exports.DEFAULT_FUNCTIONS = exports.MIDDLEWARES_RUNTIME_PATH = exports.PACKAGE_NAME = void 0;
4
4
  exports.PACKAGE_NAME = 'aeria';
5
+ exports.MIDDLEWARES_RUNTIME_PATH = '../../../dist/middlewares/index.js';
5
6
  exports.DEFAULT_FUNCTIONS = [
6
7
  'count',
7
8
  'get',
@@ -39,14 +40,18 @@ const makeASTImports = (ast, initialImports) => {
39
40
  if (node.functions) {
40
41
  const functionsToImport = Object.keys(node.functions).filter((key) => exports.DEFAULT_FUNCTIONS.includes(key));
41
42
  if (functionsToImport.length > 0) {
42
- if (!(exports.PACKAGE_NAME in imports)) {
43
- imports[exports.PACKAGE_NAME] = new Set();
44
- }
43
+ imports[exports.PACKAGE_NAME] ??= new Set();
45
44
  for (const key of functionsToImport) {
46
45
  imports[exports.PACKAGE_NAME].add(key);
47
46
  }
48
47
  }
49
48
  }
49
+ if (node.middlewares) {
50
+ imports[exports.MIDDLEWARES_RUNTIME_PATH] ??= new Set();
51
+ for (const middleware of node.middlewares) {
52
+ imports[exports.MIDDLEWARES_RUNTIME_PATH].add(middleware);
53
+ }
54
+ }
50
55
  }
51
56
  return imports;
52
57
  }, initialImports ?? {});
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  export const PACKAGE_NAME = "aeria";
3
+ export const MIDDLEWARES_RUNTIME_PATH = "../../../dist/middlewares/index.mjs";
3
4
  export const DEFAULT_FUNCTIONS = [
4
5
  "count",
5
6
  "get",
@@ -33,14 +34,18 @@ export const makeASTImports = (ast, initialImports) => {
33
34
  if (node.functions) {
34
35
  const functionsToImport = Object.keys(node.functions).filter((key) => DEFAULT_FUNCTIONS.includes(key));
35
36
  if (functionsToImport.length > 0) {
36
- if (!(PACKAGE_NAME in imports)) {
37
- imports[PACKAGE_NAME] = /* @__PURE__ */ new Set();
38
- }
37
+ imports[PACKAGE_NAME] ??= /* @__PURE__ */ new Set();
39
38
  for (const key of functionsToImport) {
40
39
  imports[PACKAGE_NAME].add(key);
41
40
  }
42
41
  }
43
42
  }
43
+ if (node.middlewares) {
44
+ imports[MIDDLEWARES_RUNTIME_PATH] ??= /* @__PURE__ */ new Set();
45
+ for (const middleware of node.middlewares) {
46
+ imports[MIDDLEWARES_RUNTIME_PATH].add(middleware);
47
+ }
48
+ }
44
49
  }
45
50
  return imports;
46
51
  }, initialImports ?? {});
package/dist/lexer.d.ts CHANGED
@@ -1,6 +1,6 @@
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", "formLayout", "functions", "icon", "indexes", "individualActions", "layout", "owned", "presets", "properties", "required", "search", "table", "tableMeta"];
3
+ export declare const COLLECTION_KEYWORDS: readonly ["actions", "additionalProperties", "filters", "form", "formLayout", "functions", "icon", "indexes", "individualActions", "layout", "middlewares", "owned", "presets", "properties", "required", "search", "table", "tableMeta"];
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"];
package/dist/lexer.js CHANGED
@@ -14,6 +14,7 @@ exports.COLLECTION_KEYWORDS = [
14
14
  'indexes',
15
15
  'individualActions',
16
16
  'layout',
17
+ 'middlewares',
17
18
  'owned',
18
19
  'presets',
19
20
  'properties',
@@ -176,11 +177,12 @@ const TOKENS = [
176
177
  type: token_js_1.TokenType.Keyword,
177
178
  matcher: Array.from(keywordsSet),
178
179
  condition: (state, lastToken) => {
179
- if (state.variableScopeStack.at(-1)) {
180
+ if (state.variableScopeStack.at(-1) || state.variableExpressionStack.at(-1)) {
180
181
  return false;
181
182
  }
182
183
  if (lastToken && lastToken.type === token_js_1.TokenType.Keyword) {
183
184
  switch (lastToken.value) {
185
+ case 'if':
184
186
  case 'badge':
185
187
  case 'title': {
186
188
  return false;
@@ -217,6 +219,7 @@ const tokenize = function (rawInput) {
217
219
  const errors = [];
218
220
  const state = {
219
221
  variableScopeStack: [],
222
+ variableExpressionStack: [],
220
223
  };
221
224
  while (index < input.length) {
222
225
  let hasMatch = false;
@@ -307,12 +310,40 @@ const tokenize = function (rawInput) {
307
310
  state.variableScopeStack.push(variableScope);
308
311
  break;
309
312
  }
313
+ case token_js_1.TokenType.LeftParens: {
314
+ let variableExpression = false;
315
+ if (lastToken) {
316
+ switch (lastToken.type) {
317
+ case token_js_1.TokenType.Keyword: {
318
+ switch (lastToken.value) {
319
+ case 'if': {
320
+ variableExpression = true;
321
+ break;
322
+ }
323
+ }
324
+ break;
325
+ }
326
+ case token_js_1.TokenType.Operator: {
327
+ variableExpression = true;
328
+ break;
329
+ }
330
+ }
331
+ }
332
+ state.variableExpressionStack.push(variableExpression);
333
+ break;
334
+ }
310
335
  case token_js_1.TokenType.RightBracket: {
311
336
  if (state.variableScopeStack.length > 0) {
312
337
  state.variableScopeStack.pop();
313
338
  }
314
339
  break;
315
340
  }
341
+ case token_js_1.TokenType.RightParens: {
342
+ if (state.variableExpressionStack.length > 0) {
343
+ state.variableExpressionStack.pop();
344
+ }
345
+ break;
346
+ }
316
347
  }
317
348
  tokens.push(token);
318
349
  }
package/dist/lexer.mjs CHANGED
@@ -12,6 +12,7 @@ export const COLLECTION_KEYWORDS = [
12
12
  "indexes",
13
13
  "individualActions",
14
14
  "layout",
15
+ "middlewares",
15
16
  "owned",
16
17
  "presets",
17
18
  "properties",
@@ -184,11 +185,12 @@ const TOKENS = [
184
185
  type: TokenType.Keyword,
185
186
  matcher: Array.from(keywordsSet),
186
187
  condition: (state, lastToken) => {
187
- if (state.variableScopeStack.at(-1)) {
188
+ if (state.variableScopeStack.at(-1) || state.variableExpressionStack.at(-1)) {
188
189
  return false;
189
190
  }
190
191
  if (lastToken && lastToken.type === TokenType.Keyword) {
191
192
  switch (lastToken.value) {
193
+ case "if":
192
194
  case "badge":
193
195
  case "title": {
194
196
  return false;
@@ -224,7 +226,8 @@ export const tokenize = function(rawInput) {
224
226
  const tokens = [];
225
227
  const errors = [];
226
228
  const state = {
227
- variableScopeStack: []
229
+ variableScopeStack: [],
230
+ variableExpressionStack: []
228
231
  };
229
232
  while (index < input.length) {
230
233
  let hasMatch = false;
@@ -310,12 +313,40 @@ export const tokenize = function(rawInput) {
310
313
  state.variableScopeStack.push(variableScope);
311
314
  break;
312
315
  }
316
+ case TokenType.LeftParens: {
317
+ let variableExpression = false;
318
+ if (lastToken) {
319
+ switch (lastToken.type) {
320
+ case TokenType.Keyword: {
321
+ switch (lastToken.value) {
322
+ case "if": {
323
+ variableExpression = true;
324
+ break;
325
+ }
326
+ }
327
+ break;
328
+ }
329
+ case TokenType.Operator: {
330
+ variableExpression = true;
331
+ break;
332
+ }
333
+ }
334
+ }
335
+ state.variableExpressionStack.push(variableExpression);
336
+ break;
337
+ }
313
338
  case TokenType.RightBracket: {
314
339
  if (state.variableScopeStack.length > 0) {
315
340
  state.variableScopeStack.pop();
316
341
  }
317
342
  break;
318
343
  }
344
+ case TokenType.RightParens: {
345
+ if (state.variableExpressionStack.length > 0) {
346
+ state.variableExpressionStack.pop();
347
+ }
348
+ break;
349
+ }
319
350
  }
320
351
  tokens.push(token);
321
352
  }
package/dist/parser.d.ts CHANGED
@@ -3,7 +3,7 @@ import { Diagnostic } from './diagnostic.js';
3
3
  import * as AST from './ast.js';
4
4
  export declare const locationMap: WeakMap<symbol, Location>;
5
5
  export declare const memoTable: {
6
- roles?: string[];
6
+ roles?: readonly string[];
7
7
  };
8
8
  export declare const parse: (tokens: (Token | undefined)[]) => {
9
9
  ast: AST.ProgramNode;
package/dist/parser.js CHANGED
@@ -189,23 +189,20 @@ const parse = (tokens) => {
189
189
  symbols,
190
190
  };
191
191
  };
192
- const parseArrayBlockWithAttributes = () => {
192
+ const parseArrayBlockWithAttributes = (allowedAttributes, cb) => {
193
193
  const array = {};
194
194
  let hasAttributes = false;
195
195
  consume(token_js_1.TokenType.LeftBracket);
196
196
  while (!match(token_js_1.TokenType.RightBracket)) {
197
197
  const { value: identifier } = consume(token_js_1.TokenType.Identifier);
198
- array[identifier] = {};
199
- while (match(token_js_1.TokenType.AttributeName)) {
198
+ array[identifier] = true;
199
+ if (match(token_js_1.TokenType.AttributeName)) {
200
200
  hasAttributes = true;
201
- const { value: attributeName } = consume(token_js_1.TokenType.AttributeName);
202
- if (match(token_js_1.TokenType.LeftParens)) {
203
- consume(token_js_1.TokenType.LeftParens);
204
- consume(token_js_1.TokenType.RightParens);
205
- }
206
- else {
207
- array[identifier][attributeName] = true;
208
- }
201
+ }
202
+ while (match(token_js_1.TokenType.AttributeName)) {
203
+ array[identifier] = {};
204
+ const { value: attributeName } = consume(token_js_1.TokenType.AttributeName, allowedAttributes);
205
+ cb(attributeName, array, identifier);
209
206
  }
210
207
  }
211
208
  consume(token_js_1.TokenType.RightBracket);
@@ -679,6 +676,10 @@ const parse = (tokens) => {
679
676
  const { value: keyword } = consume(token_js_1.TokenType.Keyword, lexer.COLLECTION_KEYWORDS);
680
677
  try {
681
678
  switch (keyword) {
679
+ case 'middlewares': {
680
+ node.middlewares = parseArrayBlock().value;
681
+ break;
682
+ }
682
683
  case 'owned': {
683
684
  if (match(token_js_1.TokenType.Boolean)) {
684
685
  node.owned = consume(token_js_1.TokenType.Boolean).value;
@@ -710,7 +711,19 @@ const parse = (tokens) => {
710
711
  break;
711
712
  }
712
713
  case 'required': {
713
- node.required = parseArrayBlockWithAttributes();
714
+ node.required = parseArrayBlockWithAttributes(['if'], (attributeName, array, identifier) => {
715
+ switch (attributeName) {
716
+ /* eslint-disable-next-line */
717
+ case 'if': {
718
+ consume(token_js_1.TokenType.LeftParens);
719
+ const ifTerms = [];
720
+ array[identifier] = parseCondition(ifTerms);
721
+ node[AST.LOCATION_SYMBOL].requiredTerms = ifTerms;
722
+ consume(token_js_1.TokenType.RightParens);
723
+ break;
724
+ }
725
+ }
726
+ });
714
727
  break;
715
728
  }
716
729
  case 'presets': {
@@ -812,6 +825,7 @@ const parse = (tokens) => {
812
825
  }
813
826
  Object.assign(functions, functionset.functions);
814
827
  consume(token_js_1.TokenType.RightParens);
828
+ break;
815
829
  }
816
830
  }
817
831
  continue;
@@ -1223,7 +1237,7 @@ const parse = (tokens) => {
1223
1237
  operator = 'lt';
1224
1238
  break;
1225
1239
  default: {
1226
- throw new diagnostic_js_1.Diagnostic(`unsuported operator: "${operatorSymbol}"`, location);
1240
+ throw new diagnostic_js_1.Diagnostic(`unsupported operator: "${operatorSymbol}"`, location);
1227
1241
  }
1228
1242
  }
1229
1243
  return {
package/dist/parser.mjs CHANGED
@@ -151,22 +151,20 @@ export const parse = (tokens) => {
151
151
  symbols
152
152
  };
153
153
  };
154
- const parseArrayBlockWithAttributes = () => {
154
+ const parseArrayBlockWithAttributes = (allowedAttributes, cb) => {
155
155
  const array = {};
156
156
  let hasAttributes = false;
157
157
  consume(TokenType.LeftBracket);
158
158
  while (!match(TokenType.RightBracket)) {
159
159
  const { value: identifier } = consume(TokenType.Identifier);
160
- array[identifier] = {};
161
- while (match(TokenType.AttributeName)) {
160
+ array[identifier] = true;
161
+ if (match(TokenType.AttributeName)) {
162
162
  hasAttributes = true;
163
- const { value: attributeName } = consume(TokenType.AttributeName);
164
- if (match(TokenType.LeftParens)) {
165
- consume(TokenType.LeftParens);
166
- consume(TokenType.RightParens);
167
- } else {
168
- array[identifier][attributeName] = true;
169
- }
163
+ }
164
+ while (match(TokenType.AttributeName)) {
165
+ array[identifier] = {};
166
+ const { value: attributeName } = consume(TokenType.AttributeName, allowedAttributes);
167
+ cb(attributeName, array, identifier);
170
168
  }
171
169
  }
172
170
  consume(TokenType.RightBracket);
@@ -625,6 +623,10 @@ export const parse = (tokens) => {
625
623
  const { value: keyword } = consume(TokenType.Keyword, lexer.COLLECTION_KEYWORDS);
626
624
  try {
627
625
  switch (keyword) {
626
+ case "middlewares": {
627
+ node.middlewares = parseArrayBlock().value;
628
+ break;
629
+ }
628
630
  case "owned": {
629
631
  if (match(TokenType.Boolean)) {
630
632
  node.owned = consume(TokenType.Boolean).value;
@@ -655,7 +657,18 @@ export const parse = (tokens) => {
655
657
  break;
656
658
  }
657
659
  case "required": {
658
- node.required = parseArrayBlockWithAttributes();
660
+ node.required = parseArrayBlockWithAttributes(["if"], (attributeName, array, identifier) => {
661
+ switch (attributeName) {
662
+ case "if": {
663
+ consume(TokenType.LeftParens);
664
+ const ifTerms = [];
665
+ array[identifier] = parseCondition(ifTerms);
666
+ node[AST.LOCATION_SYMBOL].requiredTerms = ifTerms;
667
+ consume(TokenType.RightParens);
668
+ break;
669
+ }
670
+ }
671
+ });
659
672
  break;
660
673
  }
661
674
  case "presets": {
@@ -755,6 +768,7 @@ export const parse = (tokens) => {
755
768
  }
756
769
  Object.assign(functions, functionset.functions);
757
770
  consume(TokenType.RightParens);
771
+ break;
758
772
  }
759
773
  }
760
774
  continue;
@@ -1159,7 +1173,7 @@ export const parse = (tokens) => {
1159
1173
  operator = "lt";
1160
1174
  break;
1161
1175
  default: {
1162
- throw new Diagnostic(`unsuported operator: "${operatorSymbol}"`, location);
1176
+ throw new Diagnostic(`unsupported operator: "${operatorSymbol}"`, location);
1163
1177
  }
1164
1178
  }
1165
1179
  return {
package/dist/semantic.js CHANGED
@@ -135,10 +135,19 @@ const analyze = async (ast, options, errors = []) => {
135
135
  await checkCollectionLocalProperties(node, 'filters');
136
136
  await checkCollectionLocalProperties(node, 'form');
137
137
  await checkCollectionLocalProperties(node, 'table');
138
+ await checkCollectionLocalProperties(node, 'tableMeta');
138
139
  for (const propName in node.properties) {
139
140
  const subNode = node.properties[propName];
140
141
  await recurseProperty(subNode);
141
142
  }
143
+ if (node[AST.LOCATION_SYMBOL].requiredTerms) {
144
+ for (const [name, symbol] of node[AST.LOCATION_SYMBOL].requiredTerms) {
145
+ if (!(name in node.properties)) {
146
+ const location = parser_js_1.locationMap.get(symbol);
147
+ errors.push(new diagnostic_js_1.Diagnostic(`invalid left operand "${name}"`, location));
148
+ }
149
+ }
150
+ }
142
151
  if (node.layout) {
143
152
  if (node.layout.options) {
144
153
  for (const [name, value] of Object.entries(node.layout[AST.LOCATION_SYMBOL].options)) {
package/dist/semantic.mjs CHANGED
@@ -98,10 +98,19 @@ export const analyze = async (ast, options, errors = []) => {
98
98
  await checkCollectionLocalProperties(node, "filters");
99
99
  await checkCollectionLocalProperties(node, "form");
100
100
  await checkCollectionLocalProperties(node, "table");
101
+ await checkCollectionLocalProperties(node, "tableMeta");
101
102
  for (const propName in node.properties) {
102
103
  const subNode = node.properties[propName];
103
104
  await recurseProperty(subNode);
104
105
  }
106
+ if (node[AST.LOCATION_SYMBOL].requiredTerms) {
107
+ for (const [name, symbol] of node[AST.LOCATION_SYMBOL].requiredTerms) {
108
+ if (!(name in node.properties)) {
109
+ const location = locationMap.get(symbol);
110
+ errors.push(new Diagnostic(`invalid left operand "${name}"`, location));
111
+ }
112
+ }
113
+ }
105
114
  if (node.layout) {
106
115
  if (node.layout.options) {
107
116
  for (const [name, value] of Object.entries(node.layout[AST.LOCATION_SYMBOL].options)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aeriajs/compiler",
3
- "version": "0.0.30",
3
+ "version": "0.0.32",
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.142",
25
- "@aeriajs/types": "^0.0.124"
24
+ "@aeriajs/common": "^0.0.143",
25
+ "@aeriajs/types": "^0.0.125"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@aeriajs/common": "link:../common",