@aeriajs/compiler 0.0.16 → 0.0.18

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
@@ -33,6 +33,7 @@ export type PropertyNode = NodeBase<'property'> & {
33
33
  };
34
34
  };
35
35
  nestedProperties?: Record<string, PropertyNode>;
36
+ nestedAdditionalProperties?: PropertyNode | boolean;
36
37
  };
37
38
  export type CollectionNode = NodeBase<'collection'> & {
38
39
  name: string;
@@ -19,7 +19,7 @@ const makeJSContractsCode = (contractAst) => {
19
19
  const getCodeForResponse = (responseProperty) => {
20
20
  const { kind, modifier, ...propertyNode } = responseProperty;
21
21
  if (!modifier) {
22
- return (0, utils_js_1.stringify)((0, utils_js_1.propertyToSchema)(propertyNode));
22
+ return (0, utils_js_1.stringify)((0, utils_js_1.unwrapPropertyNode)(propertyNode));
23
23
  }
24
24
  const modifierSymbol = responseProperty.modifier === 'Result'
25
25
  ? 'resultSchema'
@@ -27,7 +27,7 @@ const makeJSContractsCode = (contractAst) => {
27
27
  if (!imports.has(modifierSymbol)) {
28
28
  imports.add(modifierSymbol);
29
29
  }
30
- return `${modifierSymbol}(${(0, utils_js_1.stringify)((0, utils_js_1.propertyToSchema)(propertyNode))})`;
30
+ return `${modifierSymbol}(${(0, utils_js_1.stringify)((0, utils_js_1.unwrapPropertyNode)(propertyNode))})`;
31
31
  };
32
32
  const declarations = contractAst.map((contractNode) => {
33
33
  const { name, kind, roles, response, ...contractProperty } = contractNode;
@@ -47,7 +47,7 @@ const makeJSContractsCode = (contractAst) => {
47
47
  responseString = (0, utils_js_1.stringify)(getCodeForResponse(response));
48
48
  }
49
49
  }
50
- const contractSchema = (0, utils_js_1.getProperties)(contractProperty);
50
+ const contractSchema = (0, utils_js_1.recursivelyUnwrapPropertyNodes)(contractProperty);
51
51
  if (responseString) {
52
52
  contractSchema.response = {
53
53
  [utils_js_1.UnquotedSymbol]: responseString,
@@ -61,7 +61,7 @@ const makeJSContractsCode = (contractAst) => {
61
61
  return `import { ${Array.from(imports).join(', ')} } from \'aeria\'\n\n` + declarations;
62
62
  };
63
63
  const getResponseSchema = (response) => {
64
- const responseSchema = (0, utils_js_1.propertyToSchema)(response);
64
+ const responseSchema = (0, utils_js_1.unwrapPropertyNode)(response);
65
65
  if (!response.modifier) {
66
66
  return responseSchema;
67
67
  }
@@ -81,7 +81,7 @@ const makeTSContractsCode = (contractAst) => {
81
81
  responseSchema = getResponseSchema(contractSchema.response);
82
82
  }
83
83
  }
84
- const contractProperties = (0, utils_js_1.getProperties)(contractSchema);
84
+ const contractProperties = (0, utils_js_1.recursivelyUnwrapPropertyNodes)(contractSchema);
85
85
  if (responseSchema) {
86
86
  contractProperties.response = responseSchema;
87
87
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  import { errorSchema, resultSchema } from "@aeriajs/types";
3
- import { getProperties, propertyToSchema, stringify, UnquotedSymbol } from "./utils.mjs";
3
+ import { recursivelyUnwrapPropertyNodes, unwrapPropertyNode, stringify, UnquotedSymbol } from "./utils.mjs";
4
4
  export const generateContracts = (ast) => {
5
5
  const contractNodes = ast.filter((node) => node.kind === "contract");
6
6
  if (contractNodes.length === 0) {
@@ -16,13 +16,13 @@ const makeJSContractsCode = (contractAst) => {
16
16
  const getCodeForResponse = (responseProperty) => {
17
17
  const { kind, modifier, ...propertyNode } = responseProperty;
18
18
  if (!modifier) {
19
- return stringify(propertyToSchema(propertyNode));
19
+ return stringify(unwrapPropertyNode(propertyNode));
20
20
  }
21
21
  const modifierSymbol = responseProperty.modifier === "Result" ? "resultSchema" : "errorSchema";
22
22
  if (!imports.has(modifierSymbol)) {
23
23
  imports.add(modifierSymbol);
24
24
  }
25
- return `${modifierSymbol}(${stringify(propertyToSchema(propertyNode))})`;
25
+ return `${modifierSymbol}(${stringify(unwrapPropertyNode(propertyNode))})`;
26
26
  };
27
27
  const declarations = contractAst.map((contractNode) => {
28
28
  const { name, kind, roles, response, ...contractProperty } = contractNode;
@@ -41,7 +41,7 @@ const makeJSContractsCode = (contractAst) => {
41
41
  responseString = stringify(getCodeForResponse(response));
42
42
  }
43
43
  }
44
- const contractSchema = getProperties(contractProperty);
44
+ const contractSchema = recursivelyUnwrapPropertyNodes(contractProperty);
45
45
  if (responseString) {
46
46
  contractSchema.response = {
47
47
  [UnquotedSymbol]: responseString
@@ -57,7 +57,7 @@ const makeJSContractsCode = (contractAst) => {
57
57
  ` + declarations;
58
58
  };
59
59
  const getResponseSchema = (response) => {
60
- const responseSchema = propertyToSchema(response);
60
+ const responseSchema = unwrapPropertyNode(response);
61
61
  if (!response.modifier) {
62
62
  return responseSchema;
63
63
  }
@@ -74,7 +74,7 @@ const makeTSContractsCode = (contractAst) => {
74
74
  responseSchema = getResponseSchema(contractSchema.response);
75
75
  }
76
76
  }
77
- const contractProperties = getProperties(contractSchema);
77
+ const contractProperties = recursivelyUnwrapPropertyNodes(contractSchema);
78
78
  if (responseSchema) {
79
79
  contractProperties.response = responseSchema;
80
80
  }
@@ -47,7 +47,7 @@ const makeJSCollectionSchema = (collectionNode, collectionId) => {
47
47
  }
48
48
  switch (key) {
49
49
  case 'properties':
50
- collectionSchema.description[key] = (0, utils_js_1.getProperties)(collectionNode[key]);
50
+ collectionSchema.description[key] = (0, utils_js_1.recursivelyUnwrapPropertyNodes)(collectionNode[key]);
51
51
  break;
52
52
  case 'owned':
53
53
  collectionSchema.description[key] = collectionNode[key];
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- import { makeASTImports, getProperties, stringify, getExtendName, getCollectionId, UnquotedSymbol, getExposedFunctions, PACKAGE_NAME, DEFAULT_FUNCTIONS } from "./utils.mjs";
2
+ import { makeASTImports, recursivelyUnwrapPropertyNodes, stringify, getExtendName, getCollectionId, UnquotedSymbol, getExposedFunctions, PACKAGE_NAME, DEFAULT_FUNCTIONS } from "./utils.mjs";
3
3
  const initialImportedFunctions = [
4
4
  "extendCollection",
5
5
  "defineCollection"
@@ -40,7 +40,7 @@ const makeJSCollectionSchema = (collectionNode, collectionId) => {
40
40
  }
41
41
  switch (key) {
42
42
  case "properties":
43
- collectionSchema.description[key] = getProperties(collectionNode[key]);
43
+ collectionSchema.description[key] = recursivelyUnwrapPropertyNodes(collectionNode[key]);
44
44
  break;
45
45
  case "owned":
46
46
  collectionSchema.description[key] = collectionNode[key];
@@ -59,7 +59,7 @@ const makeTSCollectionSchema = (collectionNode, collectionId) => {
59
59
  }
60
60
  switch (key) {
61
61
  case 'properties':
62
- collectionSchema.description.properties = (0, utils_js_1.getProperties)(collectionNode[key]);
62
+ collectionSchema.description.properties = (0, utils_js_1.recursivelyUnwrapPropertyNodes)(collectionNode[key]);
63
63
  break;
64
64
  case 'owned':
65
65
  collectionSchema.description.owned = collectionNode[key];
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- import { getProperties, stringify, makeASTImports, resizeFirstChar, getCollectionId, UnquotedSymbol, getExposedFunctions, PACKAGE_NAME, DEFAULT_FUNCTIONS } from "./utils.mjs";
2
+ import { recursivelyUnwrapPropertyNodes, stringify, makeASTImports, resizeFirstChar, getCollectionId, UnquotedSymbol, getExposedFunctions, PACKAGE_NAME, DEFAULT_FUNCTIONS } from "./utils.mjs";
3
3
  const initialImportedTypes = [
4
4
  "Collection",
5
5
  "SchemaWithId",
@@ -54,7 +54,7 @@ const makeTSCollectionSchema = (collectionNode, collectionId) => {
54
54
  }
55
55
  switch (key) {
56
56
  case "properties":
57
- collectionSchema.description.properties = getProperties(collectionNode[key]);
57
+ collectionSchema.description.properties = recursivelyUnwrapPropertyNodes(collectionNode[key]);
58
58
  break;
59
59
  case "owned":
60
60
  collectionSchema.description.owned = collectionNode[key];
@@ -13,9 +13,9 @@ 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: ({ property, nestedProperties }: Pick<AST.PropertyNode, "property" | "nestedProperties">) => Property;
16
+ export declare const unwrapPropertyNode: ({ property, nestedProperties, nestedAdditionalProperties }: Pick<AST.PropertyNode, "property" | "nestedProperties" | "nestedAdditionalProperties">) => Property;
17
17
  /** Transforms the AST properties to the format of aeria schema properties */
18
- export declare const getProperties: <TProperties extends Record<string, AST.PropertyNode | AST.PropertyNode[]>, TReturnType = TProperties[keyof TProperties] extends Array<unknown> ? Record<string, Property[]> : Record<string, Property>>(properties: TProperties) => TReturnType;
18
+ export declare const recursivelyUnwrapPropertyNodes: <TProperties extends Record<string, AST.PropertyNode | AST.PropertyNode[]>, TReturnType = TProperties[keyof TProperties] extends Array<unknown> ? Record<string, Property[]> : Record<string, Property>>(properties: TProperties) => TReturnType;
19
19
  export declare const UnquotedSymbol: unique symbol;
20
20
  /** Serves to know if the value must be unquoted on strinfigy function */
21
21
  export type StringifyProperty = unknown | {
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getExtendName = exports.getCollectionId = exports.resizeFirstChar = exports.stringify = exports.UnquotedSymbol = exports.getProperties = exports.propertyToSchema = 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.makeASTImports = exports.getExposedFunctions = exports.ArraySymbol = exports.DEFAULT_FUNCTIONS = exports.PACKAGE_NAME = void 0;
4
4
  exports.PACKAGE_NAME = 'aeria';
5
5
  exports.DEFAULT_FUNCTIONS = [
6
6
  'count',
@@ -55,41 +55,70 @@ const makeASTImports = (ast, initialImports) => {
55
55
  };
56
56
  };
57
57
  exports.makeASTImports = makeASTImports;
58
- const propertyToSchema = ({ property, nestedProperties }) => {
59
- const propertySchema = property;
60
- if ('$ref' in propertySchema) {
61
- propertySchema.$ref = (0, exports.getCollectionId)(propertySchema.$ref);
58
+ const unwrapPropertyNode = ({ property, nestedProperties, nestedAdditionalProperties }) => {
59
+ const propertyOrPropertyItems = 'items' in property
60
+ ? property.items
61
+ : property;
62
+ let unwrappedProperty = propertyOrPropertyItems;
63
+ if ('$ref' in propertyOrPropertyItems) {
64
+ unwrappedProperty = {
65
+ ...propertyOrPropertyItems,
66
+ $ref: (0, exports.getCollectionId)(propertyOrPropertyItems.$ref),
67
+ };
62
68
  }
63
- else if ('items' in propertySchema && '$ref' in propertySchema.items) {
64
- propertySchema.items.$ref = (0, exports.getCollectionId)(propertySchema.items.$ref);
65
- }
66
- if (nestedProperties && 'type' in propertySchema) {
67
- if (propertySchema.type === 'object' && 'properties' in propertySchema) {
68
- propertySchema.properties = (0, exports.getProperties)(nestedProperties);
69
+ else if ('type' in propertyOrPropertyItems && propertyOrPropertyItems.type === 'object') {
70
+ let properties;
71
+ let additionalProperties;
72
+ if (nestedProperties) {
73
+ properties = (0, exports.recursivelyUnwrapPropertyNodes)(nestedProperties);
74
+ }
75
+ if (nestedAdditionalProperties) {
76
+ additionalProperties = typeof nestedAdditionalProperties === 'boolean'
77
+ ? nestedAdditionalProperties
78
+ : (0, exports.unwrapPropertyNode)(nestedAdditionalProperties);
79
+ }
80
+ if (properties && additionalProperties) {
81
+ unwrappedProperty = {
82
+ ...propertyOrPropertyItems,
83
+ properties,
84
+ additionalProperties,
85
+ };
69
86
  }
70
- else if (propertySchema.type === 'array') {
71
- propertySchema.items = {
72
- type: 'object',
73
- properties: (0, exports.getProperties)(nestedProperties),
87
+ else if (properties) {
88
+ unwrappedProperty = {
89
+ ...propertyOrPropertyItems,
90
+ properties,
74
91
  };
75
92
  }
93
+ else if (additionalProperties) {
94
+ unwrappedProperty = {
95
+ ...propertyOrPropertyItems,
96
+ additionalProperties,
97
+ };
98
+ }
99
+ }
100
+ if ('items' in property) {
101
+ return {
102
+ ...property,
103
+ items: unwrappedProperty,
104
+ };
76
105
  }
77
- return propertySchema;
106
+ return unwrappedProperty;
78
107
  };
79
- exports.propertyToSchema = propertyToSchema;
108
+ exports.unwrapPropertyNode = unwrapPropertyNode;
80
109
  /** Transforms the AST properties to the format of aeria schema properties */
81
- const getProperties = (properties) => {
110
+ const recursivelyUnwrapPropertyNodes = (properties) => {
82
111
  return Object.entries(properties).reduce((acc, [key, value]) => {
83
112
  if (Array.isArray(value)) {
84
- acc[key] = value.map((propertyNode) => (0, exports.propertyToSchema)(propertyNode));
113
+ acc[key] = value.map((propertyNode) => (0, exports.unwrapPropertyNode)(propertyNode));
85
114
  }
86
115
  else {
87
- acc[key] = (0, exports.propertyToSchema)(value);
116
+ acc[key] = (0, exports.unwrapPropertyNode)(value);
88
117
  }
89
118
  return acc;
90
119
  }, {});
91
120
  };
92
- exports.getProperties = getProperties;
121
+ exports.recursivelyUnwrapPropertyNodes = recursivelyUnwrapPropertyNodes;
93
122
  exports.UnquotedSymbol = Symbol('unquoted');
94
123
  const isRecord = (value) => typeof value === 'object';
95
124
  /** Assure if specific fields needs to be between quotes or not */
@@ -48,31 +48,55 @@ export const makeASTImports = (ast, initialImports) => {
48
48
  modifiedSymbols
49
49
  };
50
50
  };
51
- export const propertyToSchema = ({ property, nestedProperties }) => {
52
- const propertySchema = property;
53
- if ("$ref" in propertySchema) {
54
- propertySchema.$ref = getCollectionId(propertySchema.$ref);
55
- } else if ("items" in propertySchema && "$ref" in propertySchema.items) {
56
- propertySchema.items.$ref = getCollectionId(propertySchema.items.$ref);
57
- }
58
- if (nestedProperties && "type" in propertySchema) {
59
- if (propertySchema.type === "object" && "properties" in propertySchema) {
60
- propertySchema.properties = getProperties(nestedProperties);
61
- } else if (propertySchema.type === "array") {
62
- propertySchema.items = {
63
- type: "object",
64
- properties: getProperties(nestedProperties)
51
+ export const unwrapPropertyNode = ({ property, nestedProperties, nestedAdditionalProperties }) => {
52
+ const propertyOrPropertyItems = "items" in property ? property.items : property;
53
+ let unwrappedProperty = propertyOrPropertyItems;
54
+ if ("$ref" in propertyOrPropertyItems) {
55
+ unwrappedProperty = {
56
+ ...propertyOrPropertyItems,
57
+ $ref: getCollectionId(propertyOrPropertyItems.$ref)
58
+ };
59
+ } else if ("type" in propertyOrPropertyItems && propertyOrPropertyItems.type === "object") {
60
+ let properties;
61
+ let additionalProperties;
62
+ if (nestedProperties) {
63
+ properties = recursivelyUnwrapPropertyNodes(nestedProperties);
64
+ }
65
+ if (nestedAdditionalProperties) {
66
+ additionalProperties = typeof nestedAdditionalProperties === "boolean" ? nestedAdditionalProperties : unwrapPropertyNode(nestedAdditionalProperties);
67
+ }
68
+ if (properties && additionalProperties) {
69
+ unwrappedProperty = {
70
+ ...propertyOrPropertyItems,
71
+ properties,
72
+ additionalProperties
73
+ };
74
+ } else if (properties) {
75
+ unwrappedProperty = {
76
+ ...propertyOrPropertyItems,
77
+ properties
78
+ };
79
+ } else if (additionalProperties) {
80
+ unwrappedProperty = {
81
+ ...propertyOrPropertyItems,
82
+ additionalProperties
65
83
  };
66
84
  }
67
85
  }
68
- return propertySchema;
86
+ if ("items" in property) {
87
+ return {
88
+ ...property,
89
+ items: unwrappedProperty
90
+ };
91
+ }
92
+ return unwrappedProperty;
69
93
  };
70
- export const getProperties = (properties) => {
94
+ export const recursivelyUnwrapPropertyNodes = (properties) => {
71
95
  return Object.entries(properties).reduce((acc, [key, value]) => {
72
96
  if (Array.isArray(value)) {
73
- acc[key] = value.map((propertyNode) => propertyToSchema(propertyNode));
97
+ acc[key] = value.map((propertyNode) => unwrapPropertyNode(propertyNode));
74
98
  } else {
75
- acc[key] = propertyToSchema(value);
99
+ acc[key] = unwrapPropertyNode(value);
76
100
  }
77
101
  return acc;
78
102
  }, {});
package/dist/codegen.js CHANGED
@@ -51,7 +51,7 @@ const path = __importStar(require("node:path"));
51
51
  * ['outDir/folderX/folderY/file']: ...
52
52
  * }
53
53
  */
54
- const generateFileMap = async (fileTree, outDir) => {
54
+ const generateFileMap = async (fileTree, outDir = '.') => {
55
55
  const mappedPaths = {};
56
56
  const mapPathTree = async (tree, previousPath) => {
57
57
  for (const treePath in tree) {
package/dist/codegen.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  import { generateContracts, generateExports, generateJSCollections, generateTSCollections } from "./codegen/index.mjs";
3
3
  import * as fsPromises from "node:fs/promises";
4
4
  import * as path from "node:path";
5
- const generateFileMap = async (fileTree, outDir) => {
5
+ const generateFileMap = async (fileTree, outDir = ".") => {
6
6
  const mappedPaths = {};
7
7
  const mapPathTree = async (tree, previousPath) => {
8
8
  for (const treePath in tree) {
package/dist/compile.d.ts CHANGED
@@ -1,9 +1,8 @@
1
1
  import type { CompilationOptions, CompilationResult } from './types.js';
2
2
  import { Diagnostic } from './diagnostic.js';
3
- export declare const FILE_PRECEDENCE: string[];
3
+ export declare const GLOB_PATTERN = "**/*.aeria";
4
4
  export declare const parseAndCheck: (sources: Record<string, string>, options?: Pick<CompilationOptions, "languageServer">) => Promise<CompilationResult>;
5
- export declare const generateScaffolding: (options: CompilationOptions) => Promise<string[]>;
6
- export declare const compileFromFiles: (globPattern: string, options: CompilationOptions) => Promise<CompilationResult | {
5
+ export declare const compileFromFiles: (options: CompilationOptions) => Promise<CompilationResult | {
7
6
  emittedFiles: Record<string, string>;
8
7
  success: boolean;
9
8
  ast?: import("./ast.js").ProgramNode;
package/dist/compile.js CHANGED
@@ -33,18 +33,16 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.compileFromFiles = exports.generateScaffolding = exports.parseAndCheck = exports.FILE_PRECEDENCE = void 0;
36
+ exports.compileFromFiles = exports.parseAndCheck = exports.GLOB_PATTERN = void 0;
37
37
  const diagnostic_js_1 = require("./diagnostic.js");
38
38
  const lexer_js_1 = require("./lexer.js");
39
39
  const parser_js_1 = require("./parser.js");
40
40
  const semantic_js_1 = require("./semantic.js");
41
41
  const codegen_js_1 = require("./codegen.js");
42
- const path = __importStar(require("node:path"));
43
42
  const fs = __importStar(require("node:fs"));
44
- exports.FILE_PRECEDENCE = ['contract'];
43
+ exports.GLOB_PATTERN = '**/*.aeria';
45
44
  const parseAndCheck = async (sources, options = {}) => {
46
45
  const errors = [];
47
- let ast;
48
46
  const allTokens = [];
49
47
  for (const fileName in sources) {
50
48
  diagnostic_js_1.Diagnostic.currentFile = fileName;
@@ -54,8 +52,8 @@ const parseAndCheck = async (sources, options = {}) => {
54
52
  }
55
53
  allTokens.push(...tokens);
56
54
  }
57
- const { errors: parserErrors, ast: currentAst } = (0, parser_js_1.parse)(allTokens);
58
- const { errors: semanticErrors } = await (0, semantic_js_1.analyze)(currentAst, options);
55
+ const { errors: parserErrors, ast } = (0, parser_js_1.parse)(allTokens);
56
+ const { errors: semanticErrors } = await (0, semantic_js_1.analyze)(ast, options);
59
57
  errors.push(...parserErrors.concat(semanticErrors));
60
58
  return {
61
59
  success: errors.length === 0,
@@ -65,31 +63,11 @@ const parseAndCheck = async (sources, options = {}) => {
65
63
  };
66
64
  };
67
65
  exports.parseAndCheck = parseAndCheck;
68
- const generateScaffolding = async (options) => {
69
- const directories = [path.join(options.outDir, 'collections')];
70
- for (const dir of directories) {
71
- await fs.promises.mkdir(dir, {
72
- recursive: true,
73
- });
74
- }
75
- return directories;
76
- };
77
- exports.generateScaffolding = generateScaffolding;
78
- const compileFromFiles = async (globPattern, options) => {
79
- const fileList = await Array.fromAsync(fs.promises.glob(globPattern));
80
- const sortedFileList = fileList.sort((a, b) => {
81
- const aIndex = exports.FILE_PRECEDENCE.findIndex((file) => a.split('/').at(-1).startsWith(file));
82
- const bIndex = exports.FILE_PRECEDENCE.findIndex((file) => b.split('/').at(-1).startsWith(file));
83
- if (!~aIndex && !~bIndex) {
84
- return 1;
85
- }
86
- return aIndex > bIndex
87
- ? 1
88
- : -1;
89
- });
66
+ const compileFromFiles = async (options) => {
67
+ const fileList = await Array.fromAsync(fs.promises.glob(exports.GLOB_PATTERN));
90
68
  const sources = {};
91
- for (const file of sortedFileList) {
92
- sources[file] = await fs.promises.readFile(file, {
69
+ for (const fileName of fileList) {
70
+ sources[fileName] = await fs.promises.readFile(fileName, {
93
71
  encoding: 'utf-8',
94
72
  });
95
73
  }
@@ -97,10 +75,13 @@ const compileFromFiles = async (globPattern, options) => {
97
75
  if (!result.ast || result.errorCount > 0) {
98
76
  return result;
99
77
  }
100
- const emittedFiles = await (0, codegen_js_1.generateCode)(result.ast, options);
101
- return {
102
- ...result,
103
- emittedFiles,
104
- };
78
+ if (options.outDir) {
79
+ const emittedFiles = await (0, codegen_js_1.generateCode)(result.ast, options);
80
+ return {
81
+ ...result,
82
+ emittedFiles,
83
+ };
84
+ }
85
+ return result;
105
86
  };
106
87
  exports.compileFromFiles = compileFromFiles;
package/dist/compile.mjs CHANGED
@@ -4,12 +4,10 @@ import { tokenize } from "./lexer.mjs";
4
4
  import { parse } from "./parser.mjs";
5
5
  import { analyze } from "./semantic.mjs";
6
6
  import { generateCode } from "./codegen.mjs";
7
- import * as path from "node:path";
8
7
  import * as fs from "node:fs";
9
- export const FILE_PRECEDENCE = ["contract"];
8
+ export const GLOB_PATTERN = "**/*.aeria";
10
9
  export const parseAndCheck = async (sources, options = {}) => {
11
10
  const errors = [];
12
- let ast;
13
11
  const allTokens = [];
14
12
  for (const fileName in sources) {
15
13
  Diagnostic.currentFile = fileName;
@@ -19,8 +17,8 @@ export const parseAndCheck = async (sources, options = {}) => {
19
17
  }
20
18
  allTokens.push(...tokens);
21
19
  }
22
- const { errors: parserErrors, ast: currentAst } = parse(allTokens);
23
- const { errors: semanticErrors } = await analyze(currentAst, options);
20
+ const { errors: parserErrors, ast } = parse(allTokens);
21
+ const { errors: semanticErrors } = await analyze(ast, options);
24
22
  errors.push(...parserErrors.concat(semanticErrors));
25
23
  return {
26
24
  success: errors.length === 0,
@@ -29,28 +27,11 @@ export const parseAndCheck = async (sources, options = {}) => {
29
27
  ast
30
28
  };
31
29
  };
32
- export const generateScaffolding = async (options) => {
33
- const directories = [path.join(options.outDir, "collections")];
34
- for (const dir of directories) {
35
- await fs.promises.mkdir(dir, {
36
- recursive: true
37
- });
38
- }
39
- return directories;
40
- };
41
- export const compileFromFiles = async (globPattern, options) => {
42
- const fileList = await Array.fromAsync(fs.promises.glob(globPattern));
43
- const sortedFileList = fileList.sort((a, b) => {
44
- const aIndex = FILE_PRECEDENCE.findIndex((file) => a.split("/").at(-1).startsWith(file));
45
- const bIndex = FILE_PRECEDENCE.findIndex((file) => b.split("/").at(-1).startsWith(file));
46
- if (!~aIndex && !~bIndex) {
47
- return 1;
48
- }
49
- return aIndex > bIndex ? 1 : -1;
50
- });
30
+ export const compileFromFiles = async (options) => {
31
+ const fileList = await Array.fromAsync(fs.promises.glob(GLOB_PATTERN));
51
32
  const sources = {};
52
- for (const file of sortedFileList) {
53
- sources[file] = await fs.promises.readFile(file, {
33
+ for (const fileName of fileList) {
34
+ sources[fileName] = await fs.promises.readFile(fileName, {
54
35
  encoding: "utf-8"
55
36
  });
56
37
  }
@@ -58,9 +39,12 @@ export const compileFromFiles = async (globPattern, options) => {
58
39
  if (!result.ast || result.errorCount > 0) {
59
40
  return result;
60
41
  }
61
- const emittedFiles = await generateCode(result.ast, options);
62
- return {
63
- ...result,
64
- emittedFiles
65
- };
42
+ if (options.outDir) {
43
+ const emittedFiles = await generateCode(result.ast, options);
44
+ return {
45
+ ...result,
46
+ emittedFiles
47
+ };
48
+ }
49
+ return result;
66
50
  };
package/dist/lexer.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { type Token } from './token.js';
2
2
  import { Diagnostic } from './diagnostic.js';
3
3
  export type Keyword = typeof COLLECTION_KEYWORDS[number] | typeof COLLECTION_ACTIONS_KEYWORDS[number] | typeof COLLECTION_SEARCH_KEYWORDS[number] | typeof CONTRACT_KEYWORDS[number] | typeof TOPLEVEL_KEYWORDS[number] | typeof MISC_KEYWORDS[number];
4
- export declare const COLLECTION_KEYWORDS: readonly ["actions", "filters", "form", "functions", "icon", "indexes", "individualActions", "owned", "presets", "properties", "required", "search", "table"];
4
+ export declare const COLLECTION_KEYWORDS: readonly ["actions", "additionalProperties", "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
7
  export declare const CONTRACT_KEYWORDS: readonly ["roles", "payload", "query", "response"];
package/dist/lexer.js CHANGED
@@ -5,6 +5,7 @@ const token_js_1 = require("./token.js");
5
5
  const diagnostic_js_1 = require("./diagnostic.js");
6
6
  exports.COLLECTION_KEYWORDS = [
7
7
  'actions',
8
+ 'additionalProperties',
8
9
  'filters',
9
10
  'form',
10
11
  'functions',
package/dist/lexer.mjs CHANGED
@@ -3,6 +3,7 @@ import { TokenType } from "./token.mjs";
3
3
  import { Diagnostic } from "./diagnostic.mjs";
4
4
  export const COLLECTION_KEYWORDS = [
5
5
  "actions",
6
+ "additionalProperties",
6
7
  "filters",
7
8
  "form",
8
9
  "functions",
package/dist/parser.js CHANGED
@@ -378,9 +378,9 @@ const parse = (tokens) => {
378
378
  }) => {
379
379
  let property;
380
380
  let nestedProperties;
381
+ let nestedAdditionalProperties;
381
382
  let modifierToken;
382
383
  const typeSymbol = Symbol();
383
- exports.locationMap.set(typeSymbol, next().location);
384
384
  if (match(token_js_1.TokenType.LeftSquareBracket)) {
385
385
  consume(token_js_1.TokenType.LeftSquareBracket);
386
386
  const arrayProperty = {
@@ -428,6 +428,7 @@ const parse = (tokens) => {
428
428
  ...arrayProperty,
429
429
  items,
430
430
  };
431
+ exports.locationMap.set(typeSymbol, current().location);
431
432
  return {
432
433
  kind: 'property',
433
434
  property,
@@ -441,6 +442,7 @@ const parse = (tokens) => {
441
442
  modifierToken = consume(token_js_1.TokenType.Identifier);
442
443
  }
443
444
  }
445
+ exports.locationMap.set(typeSymbol, current().location);
444
446
  if (match(token_js_1.TokenType.LeftBracket)) {
445
447
  consume(token_js_1.TokenType.LeftBracket);
446
448
  property = {
@@ -468,6 +470,16 @@ const parse = (tokens) => {
468
470
  nestedProperties = parsePropertiesBlock(options);
469
471
  break;
470
472
  }
473
+ case 'additionalProperties': {
474
+ consume(token_js_1.TokenType.Keyword);
475
+ if (match(token_js_1.TokenType.Boolean)) {
476
+ nestedAdditionalProperties = consume(token_js_1.TokenType.Boolean).value;
477
+ }
478
+ else {
479
+ nestedAdditionalProperties = parsePropertyType();
480
+ }
481
+ break;
482
+ }
471
483
  default:
472
484
  throw new diagnostic_js_1.Diagnostic(`invalid keyword "${keyword}"`, location);
473
485
  }
@@ -544,6 +556,7 @@ const parse = (tokens) => {
544
556
  kind: 'property',
545
557
  property,
546
558
  nestedProperties,
559
+ nestedAdditionalProperties,
547
560
  };
548
561
  if (modifierToken) {
549
562
  node.modifier = modifierToken.value;
@@ -662,11 +675,14 @@ const parse = (tokens) => {
662
675
  try {
663
676
  switch (keyword) {
664
677
  case 'owned': {
665
- if (match(token_js_1.TokenType.QuotedString, [
666
- 'always',
667
- 'on-write',
668
- ])) {
669
- node.owned = consume(token_js_1.TokenType.QuotedString).value;
678
+ if (match(token_js_1.TokenType.Boolean)) {
679
+ node.owned = consume(token_js_1.TokenType.Boolean).value;
680
+ }
681
+ else {
682
+ node.owned = consume(token_js_1.TokenType.QuotedString, [
683
+ 'always',
684
+ 'on-write',
685
+ ]).value;
670
686
  }
671
687
  break;
672
688
  }
package/dist/parser.mjs CHANGED
@@ -336,9 +336,9 @@ export const parse = (tokens) => {
336
336
  }) => {
337
337
  let property;
338
338
  let nestedProperties;
339
+ let nestedAdditionalProperties;
339
340
  let modifierToken;
340
341
  const typeSymbol = Symbol();
341
- locationMap.set(typeSymbol, next().location);
342
342
  if (match(TokenType.LeftSquareBracket)) {
343
343
  consume(TokenType.LeftSquareBracket);
344
344
  const arrayProperty = {
@@ -384,6 +384,7 @@ export const parse = (tokens) => {
384
384
  ...arrayProperty,
385
385
  items
386
386
  };
387
+ locationMap.set(typeSymbol, current().location);
387
388
  return {
388
389
  kind: "property",
389
390
  property,
@@ -397,6 +398,7 @@ export const parse = (tokens) => {
397
398
  modifierToken = consume(TokenType.Identifier);
398
399
  }
399
400
  }
401
+ locationMap.set(typeSymbol, current().location);
400
402
  if (match(TokenType.LeftBracket)) {
401
403
  consume(TokenType.LeftBracket);
402
404
  property = {
@@ -424,6 +426,15 @@ export const parse = (tokens) => {
424
426
  nestedProperties = parsePropertiesBlock(options);
425
427
  break;
426
428
  }
429
+ case "additionalProperties": {
430
+ consume(TokenType.Keyword);
431
+ if (match(TokenType.Boolean)) {
432
+ nestedAdditionalProperties = consume(TokenType.Boolean).value;
433
+ } else {
434
+ nestedAdditionalProperties = parsePropertyType();
435
+ }
436
+ break;
437
+ }
427
438
  default:
428
439
  throw new Diagnostic(`invalid keyword "${keyword}"`, location);
429
440
  }
@@ -496,7 +507,8 @@ export const parse = (tokens) => {
496
507
  const node = {
497
508
  kind: "property",
498
509
  property,
499
- nestedProperties
510
+ nestedProperties,
511
+ nestedAdditionalProperties
500
512
  };
501
513
  if (modifierToken) {
502
514
  node.modifier = modifierToken.value;
@@ -609,11 +621,13 @@ export const parse = (tokens) => {
609
621
  try {
610
622
  switch (keyword) {
611
623
  case "owned": {
612
- if (match(TokenType.QuotedString, [
613
- "always",
614
- "on-write"
615
- ])) {
616
- node.owned = consume(TokenType.QuotedString).value;
624
+ if (match(TokenType.Boolean)) {
625
+ node.owned = consume(TokenType.Boolean).value;
626
+ } else {
627
+ node.owned = consume(TokenType.QuotedString, [
628
+ "always",
629
+ "on-write"
630
+ ]).value;
617
631
  }
618
632
  break;
619
633
  }
package/dist/semantic.js CHANGED
@@ -97,13 +97,18 @@ const analyze = async (ast, options, errors = []) => {
97
97
  }
98
98
  };
99
99
  const recurseProperty = async (node) => {
100
- if (node.nestedProperties && 'nestedProperties' in node) {
101
- await checkObjectLocalProperties(node, 'required');
102
- await checkObjectLocalProperties(node, 'writable');
103
- await checkObjectLocalProperties(node, 'form');
104
- for (const propName in node.nestedProperties) {
105
- const subProperty = node.nestedProperties[propName];
106
- await recurseProperty(subProperty);
100
+ if ('type' in node.property && node.property.type === 'object') {
101
+ if (typeof node.nestedAdditionalProperties === 'object') {
102
+ await recurseProperty(node.nestedAdditionalProperties);
103
+ }
104
+ if (node.nestedProperties) {
105
+ await checkObjectLocalProperties(node, 'required');
106
+ await checkObjectLocalProperties(node, 'writable');
107
+ await checkObjectLocalProperties(node, 'form');
108
+ for (const propName in node.nestedProperties) {
109
+ const subProperty = node.nestedProperties[propName];
110
+ await recurseProperty(subProperty);
111
+ }
107
112
  }
108
113
  }
109
114
  else if ('$ref' in node.property) {
@@ -118,6 +123,12 @@ const analyze = async (ast, options, errors = []) => {
118
123
  await checkCollectionForeignProperties(foreignCollection, node.property, 'populate');
119
124
  await checkCollectionForeignProperties(foreignCollection, node.property, 'form');
120
125
  }
126
+ else if ('items' in node.property) {
127
+ await recurseProperty({
128
+ kind: 'property',
129
+ property: node.property.items,
130
+ });
131
+ }
121
132
  };
122
133
  for (const node of ast.collections) {
123
134
  await checkCollectionLocalProperties(node, 'indexes');
package/dist/semantic.mjs CHANGED
@@ -62,13 +62,18 @@ export const analyze = async (ast, options, errors = []) => {
62
62
  }
63
63
  };
64
64
  const recurseProperty = async (node) => {
65
- if (node.nestedProperties && "nestedProperties" in node) {
66
- await checkObjectLocalProperties(node, "required");
67
- await checkObjectLocalProperties(node, "writable");
68
- await checkObjectLocalProperties(node, "form");
69
- for (const propName in node.nestedProperties) {
70
- const subProperty = node.nestedProperties[propName];
71
- await recurseProperty(subProperty);
65
+ if ("type" in node.property && node.property.type === "object") {
66
+ if (typeof node.nestedAdditionalProperties === "object") {
67
+ await recurseProperty(node.nestedAdditionalProperties);
68
+ }
69
+ if (node.nestedProperties) {
70
+ await checkObjectLocalProperties(node, "required");
71
+ await checkObjectLocalProperties(node, "writable");
72
+ await checkObjectLocalProperties(node, "form");
73
+ for (const propName in node.nestedProperties) {
74
+ const subProperty = node.nestedProperties[propName];
75
+ await recurseProperty(subProperty);
76
+ }
72
77
  }
73
78
  } else if ("$ref" in node.property) {
74
79
  const refName = node.property.$ref;
@@ -81,6 +86,11 @@ export const analyze = async (ast, options, errors = []) => {
81
86
  await checkCollectionForeignProperties(foreignCollection, node.property, "indexes");
82
87
  await checkCollectionForeignProperties(foreignCollection, node.property, "populate");
83
88
  await checkCollectionForeignProperties(foreignCollection, node.property, "form");
89
+ } else if ("items" in node.property) {
90
+ await recurseProperty({
91
+ kind: "property",
92
+ property: node.property.items
93
+ });
84
94
  }
85
95
  };
86
96
  for (const node of ast.collections) {
package/dist/types.d.ts CHANGED
@@ -7,7 +7,7 @@ export type CompilationResult = {
7
7
  errorCount: number;
8
8
  };
9
9
  export type CompilationOptions = {
10
- outDir: string;
10
+ outDir?: string;
11
11
  dryRun?: boolean;
12
12
  languageServer?: boolean;
13
13
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aeriajs/compiler",
3
- "version": "0.0.16",
3
+ "version": "0.0.18",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -10,8 +10,8 @@
10
10
  },
11
11
  "exports": {
12
12
  ".": {
13
- "import": "./dist/index.js",
14
- "types": "./dist/index.d.ts"
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
15
  }
16
16
  },
17
17
  "keywords": [],