@aeriajs/compiler 0.0.62 → 0.0.64

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.
@@ -1,161 +0,0 @@
1
- "use strict";
2
- export const PACKAGE_NAME = "aeria";
3
- export const MIDDLEWARES_RUNTIME_PATH = "../../../dist/middlewares/index.mjs";
4
- export const UnquotedSymbol = Symbol("unquoted");
5
- export const ArraySymbol = Symbol("array");
6
- export const getExposedFunctions = (functionNodes) => {
7
- return Object.fromEntries(functionNodes.map((node) => [
8
- node.name,
9
- node.accessCondition
10
- ]));
11
- };
12
- export const makeASTImports = (ast, initialImports = {}, options = {
13
- includeRuntimeOnlyImports: false
14
- }) => {
15
- const modifiedSymbols = {};
16
- const toImport = ast.reduce((imports, node) => {
17
- if (node.kind === "collection") {
18
- if (node.extends) {
19
- const modifiedSymbol = `${node.extends.packageName}${resizeFirstChar(node.extends.symbolName, true)}`;
20
- modifiedSymbols[node.extends.symbolName] = modifiedSymbol;
21
- imports[node.extends.importPath] ??= /* @__PURE__ */ new Set();
22
- imports[node.extends.importPath].add(`${node.extends.symbolName} as ${modifiedSymbol}`);
23
- }
24
- if (node.functions) {
25
- for (const functionNode of node.functions) {
26
- if (functionNode.exportSymbol) {
27
- const { importPath, symbolName } = functionNode.exportSymbol;
28
- imports[importPath] ??= /* @__PURE__ */ new Set();
29
- imports[importPath].add(symbolName);
30
- }
31
- }
32
- }
33
- if (options.includeRuntimeOnlyImports) {
34
- if (node.middlewares) {
35
- imports[MIDDLEWARES_RUNTIME_PATH] ??= /* @__PURE__ */ new Set();
36
- for (const middleware of node.middlewares) {
37
- imports[MIDDLEWARES_RUNTIME_PATH].add(middleware);
38
- }
39
- }
40
- }
41
- }
42
- return imports;
43
- }, initialImports);
44
- return {
45
- code: Object.keys(toImport).map((key) => `import { ${Array.from(toImport[key]).join(", ")} } from '${key}'`),
46
- modifiedSymbols
47
- };
48
- };
49
- export const unwrapNode = (node) => {
50
- const { kind, ...unwrappedNode } = Object.fromEntries(Object.entries(node).filter(([key]) => typeof key === "string"));
51
- return unwrappedNode;
52
- };
53
- export const unwrapPropertyNode = ({ property, nestedProperties, nestedAdditionalProperties }) => {
54
- const propertyOrPropertyItems = "items" in property ? property.items : property;
55
- let unwrappedProperty = propertyOrPropertyItems;
56
- if ("$ref" in propertyOrPropertyItems) {
57
- unwrappedProperty = {
58
- ...propertyOrPropertyItems,
59
- $ref: getCollectionId(propertyOrPropertyItems.$ref)
60
- };
61
- } else if ("type" in propertyOrPropertyItems && propertyOrPropertyItems.type === "object") {
62
- let properties;
63
- let additionalProperties;
64
- if (nestedProperties) {
65
- properties = recursivelyUnwrapPropertyNodes(nestedProperties);
66
- }
67
- if (nestedAdditionalProperties) {
68
- additionalProperties = typeof nestedAdditionalProperties === "boolean" ? nestedAdditionalProperties : unwrapPropertyNode(nestedAdditionalProperties);
69
- }
70
- if (properties && additionalProperties) {
71
- unwrappedProperty = {
72
- ...propertyOrPropertyItems,
73
- properties,
74
- additionalProperties
75
- };
76
- } else if (properties) {
77
- unwrappedProperty = {
78
- ...propertyOrPropertyItems,
79
- properties
80
- };
81
- } else if (additionalProperties) {
82
- unwrappedProperty = {
83
- ...propertyOrPropertyItems,
84
- additionalProperties
85
- };
86
- }
87
- }
88
- if ("items" in property) {
89
- return {
90
- ...property,
91
- items: unwrappedProperty
92
- };
93
- }
94
- return unwrappedProperty;
95
- };
96
- export const recursivelyUnwrapPropertyNodes = (properties) => {
97
- return Object.entries(properties).reduce((acc, [key, value]) => {
98
- if (Array.isArray(value)) {
99
- acc[key] = value.map((propertyNode) => unwrapPropertyNode(propertyNode));
100
- } else {
101
- acc[key] = unwrapPropertyNode(value);
102
- }
103
- return acc;
104
- }, {});
105
- };
106
- const isRecord = (value) => {
107
- return !!(value && typeof value === "object");
108
- };
109
- export const stringify = (value, parents = []) => {
110
- if (Array.isArray(value)) {
111
- let arrayString = "[\n";
112
- value.map((element) => {
113
- const currentParents = [
114
- ...parents,
115
- ArraySymbol
116
- ];
117
- arrayString += " ".repeat(currentParents.length) + checkQuotes(currentParents, element) + ",\n";
118
- });
119
- return arrayString + `${" ".repeat(parents.length)}]`;
120
- }
121
- if (isRecord(value)) {
122
- const objectString = Object.keys(value).map((key) => {
123
- const currentParents = [
124
- ...parents,
125
- key
126
- ];
127
- const indentation = " ".repeat(currentParents.length);
128
- return `${indentation}${key}: ${checkQuotes(currentParents, value[key])}`;
129
- }).join(",\n");
130
- return `{
131
- ${objectString}
132
- ${" ".repeat(parents.length)}}`;
133
- }
134
- switch (typeof value) {
135
- case "undefined":
136
- case "number":
137
- case "boolean": {
138
- return String(value);
139
- }
140
- default: {
141
- if (value === null) {
142
- return String(value);
143
- }
144
- return `"${String(value)}"`;
145
- }
146
- }
147
- };
148
- const checkQuotes = (parents, value) => {
149
- if (value && typeof value === "object" && UnquotedSymbol in value) {
150
- return value[UnquotedSymbol];
151
- }
152
- return stringify(value, parents);
153
- };
154
- export const resizeFirstChar = (text, capitalize) => {
155
- if (capitalize === true) {
156
- return text.charAt(0).toUpperCase() + text.slice(1);
157
- }
158
- return text.charAt(0).toLowerCase() + text.slice(1);
159
- };
160
- export const getCollectionId = (name) => resizeFirstChar(name, false);
161
- export const getExtendName = (name) => `extend${resizeFirstChar(name, true)}Collection`;
package/dist/codegen.mjs DELETED
@@ -1,54 +0,0 @@
1
- "use strict";
2
- import { generateContracts, generateExports, generateJSCollections, generateTSCollections } from "./codegen/index.mjs";
3
- import * as fsPromises from "node:fs/promises";
4
- import * as path from "node:path";
5
- const generateFileMap = async (fileTree, outDir = ".") => {
6
- const mappedPaths = {};
7
- const mapPathTree = async (tree, previousPath) => {
8
- for (const treePath in tree) {
9
- const currentPath = path.join(previousPath, treePath);
10
- if (typeof tree[treePath] === "object") {
11
- await mapPathTree(tree[treePath], currentPath);
12
- continue;
13
- }
14
- await fsPromises.mkdir(previousPath, {
15
- recursive: true
16
- });
17
- mappedPaths[currentPath] = tree[treePath];
18
- }
19
- return;
20
- };
21
- await mapPathTree(fileTree, outDir);
22
- return mappedPaths;
23
- };
24
- export const generateCode = async (ast, options) => {
25
- const contracts = generateContracts(ast);
26
- const exports = generateExports(ast, {
27
- hasContracts: !!contracts
28
- });
29
- const fileTree = {
30
- ["collections"]: {
31
- ["collections.d.ts"]: generateTSCollections(ast),
32
- ["collections.mjs"]: generateJSCollections(ast),
33
- ["index.d.ts"]: exports.collections.dts,
34
- ["index.mjs"]: exports.collections.js
35
- },
36
- ["index.d.ts"]: exports.index.dts,
37
- ["index.mjs"]: exports.index.js
38
- };
39
- if (contracts) {
40
- fileTree.contracts = {
41
- ["contracts.mjs"]: contracts.js,
42
- ["contracts.d.ts"]: contracts.dts,
43
- ["index.d.ts"]: exports.contracts.dts,
44
- ["index.mjs"]: exports.contracts.js
45
- };
46
- }
47
- const fileStructure = await generateFileMap(fileTree, options.outDir);
48
- if (!options.dryRun) {
49
- for (const path2 in fileStructure) {
50
- await fsPromises.writeFile(path2, fileStructure[path2]);
51
- }
52
- }
53
- return fileStructure;
54
- };
package/dist/compile.mjs DELETED
@@ -1,69 +0,0 @@
1
- "use strict";
2
- import { Diagnostic } from "./diagnostic.mjs";
3
- import { tokenize } from "./lexer.mjs";
4
- import { parse, locationMap } from "./parser.mjs";
5
- import { analyze } from "./semantic.mjs";
6
- import { generateCode } from "./codegen.mjs";
7
- import * as fs from "node:fs";
8
- export const GLOB_PATTERN = "**/*.aeria";
9
- export const postflight = (ast) => {
10
- const errors = [];
11
- for (const node of ast.collections) {
12
- if (node.functionSets?.length) {
13
- for (const [functionSetName, locationSymbol] of node.functionSets) {
14
- const functionSet = ast.functionsets.find(({ name }) => name === functionSetName);
15
- if (!functionSet) {
16
- const location = locationMap.get(locationSymbol);
17
- errors.push(new Diagnostic(`invalid function set "${functionSetName}"`, location));
18
- continue;
19
- }
20
- node.functions.push(...functionSet.functions);
21
- }
22
- }
23
- }
24
- return {
25
- errors
26
- };
27
- };
28
- export const parseAndCheck = async (sources, options = {}) => {
29
- const errors = [];
30
- const allTokens = [];
31
- for (const fileName in sources) {
32
- const { errors: lexerErrors, tokens } = tokenize(sources[fileName], fileName);
33
- if (lexerErrors.length > 0) {
34
- errors.push(...lexerErrors);
35
- }
36
- allTokens.push(...tokens);
37
- }
38
- const { errors: parserErrors, ast } = parse(allTokens);
39
- const { errors: semanticErrors } = await analyze(ast, options);
40
- const { errors: postflightErrors } = postflight(ast);
41
- errors.push(...parserErrors.concat(semanticErrors, postflightErrors));
42
- return {
43
- success: errors.length === 0,
44
- errors,
45
- errorCount: errors.length,
46
- ast
47
- };
48
- };
49
- export const compileFromFiles = async (options) => {
50
- const fileList = await Array.fromAsync(fs.promises.glob(GLOB_PATTERN));
51
- const sources = {};
52
- for (const fileName of fileList) {
53
- sources[fileName] = await fs.promises.readFile(fileName, {
54
- encoding: "utf-8"
55
- });
56
- }
57
- const result = await parseAndCheck(sources, options);
58
- if (!result.ast || result.errorCount > 0) {
59
- return result;
60
- }
61
- if (options.outDir) {
62
- const emittedFiles = await generateCode(result.ast, options);
63
- return {
64
- ...result,
65
- emittedFiles
66
- };
67
- }
68
- return result;
69
- };
@@ -1,18 +0,0 @@
1
- "use strict";
2
- const emptyLocation = {
3
- file: "",
4
- index: 0,
5
- line: 0,
6
- start: 0,
7
- end: 0
8
- };
9
- export class Diagnostic extends Error {
10
- constructor(message, location = emptyLocation) {
11
- super();
12
- this.message = message;
13
- this.location = location;
14
- if (false) {
15
- console.error(message, location);
16
- }
17
- }
18
- }
package/dist/guards.mjs DELETED
@@ -1,8 +0,0 @@
1
- "use strict";
2
- import * as AST from "./ast.mjs";
3
- export const isNativePropertyType = (value) => {
4
- return value in AST.PropertyType;
5
- };
6
- export const isValidPropertyModifier = (value) => {
7
- return value in AST.PropertyModifiers;
8
- };
package/dist/index.mjs DELETED
@@ -1,8 +0,0 @@
1
- "use strict";
2
- export * from "./ast.mjs";
3
- export * from "./compile.mjs";
4
- export * from "./parser.mjs";
5
- export * from "./lexer.mjs";
6
- export * from "./semantic.mjs";
7
- export * from "./token.mjs";
8
- export * from "./diagnostic.mjs";
package/dist/lexer.mjs DELETED
@@ -1,375 +0,0 @@
1
- "use strict";
2
- import { TokenType } from "./token.mjs";
3
- import { Diagnostic } from "./diagnostic.mjs";
4
- export const COLLECTION_KEYWORDS = [
5
- "actions",
6
- "additionalProperties",
7
- "filters",
8
- "form",
9
- "formLayout",
10
- "functions",
11
- "icon",
12
- "indexes",
13
- "individualActions",
14
- "layout",
15
- "middlewares",
16
- "owned",
17
- "presets",
18
- "properties",
19
- "required",
20
- "search",
21
- "table",
22
- "tableMeta",
23
- "unique",
24
- "writable"
25
- ];
26
- export const COLLECTION_ACTIONS_KEYWORDS = [
27
- "ask",
28
- "button",
29
- "clearItem",
30
- "effect",
31
- "event",
32
- "fetchItem",
33
- "function",
34
- "icon",
35
- "label",
36
- "params",
37
- "query",
38
- "requires",
39
- "roles",
40
- "route",
41
- "selection",
42
- "setItem",
43
- "translate"
44
- ];
45
- export const COLLECTION_SEARCH_KEYWORDS = [
46
- "indexes",
47
- "placeholder",
48
- "exactMatches"
49
- ];
50
- export const COLLECTION_LAYOUT_KEYWORDS = [
51
- "name",
52
- "options"
53
- ];
54
- export const COLLECTION_LAYOUT_OPTIONS_KEYWORDS = [
55
- "title",
56
- "picture",
57
- "badge",
58
- "information",
59
- "active",
60
- "translateBadge"
61
- ];
62
- export const COLLECTION_FORM_LAYOUT_KEYWORDS = [
63
- "fields",
64
- "if",
65
- "span",
66
- "verticalSpacing",
67
- "separator"
68
- ];
69
- export const CONTRACT_KEYWORDS = [
70
- "roles",
71
- "payload",
72
- "query",
73
- "response"
74
- ];
75
- export const TOPLEVEL_KEYWORDS = [
76
- "collection",
77
- "contract",
78
- "functionset"
79
- ];
80
- export const MISC_KEYWORDS = ["extends"];
81
- export const KEYWORDS = [].concat(
82
- COLLECTION_KEYWORDS,
83
- COLLECTION_ACTIONS_KEYWORDS,
84
- COLLECTION_SEARCH_KEYWORDS,
85
- COLLECTION_LAYOUT_KEYWORDS,
86
- COLLECTION_LAYOUT_OPTIONS_KEYWORDS,
87
- COLLECTION_FORM_LAYOUT_KEYWORDS,
88
- CONTRACT_KEYWORDS,
89
- TOPLEVEL_KEYWORDS,
90
- MISC_KEYWORDS
91
- );
92
- export const FINAL_OPERATORS = [
93
- "==",
94
- "in",
95
- ">=",
96
- "<=",
97
- ">",
98
- "<",
99
- "!"
100
- ];
101
- export const LOGICAL_OPERATORS = [
102
- "&&",
103
- "||"
104
- ];
105
- const keywordsSet = /* @__PURE__ */ new Set();
106
- for (const keyword of KEYWORDS) {
107
- keywordsSet.add(keyword);
108
- }
109
- const TOKENS = [
110
- {
111
- type: null,
112
- matcher: /\r?[ \t]+/
113
- },
114
- {
115
- type: TokenType.LineBreak,
116
- matcher: "\n"
117
- },
118
- {
119
- type: TokenType.Comment,
120
- matcher: "//"
121
- },
122
- {
123
- type: TokenType.LeftBracket,
124
- matcher: "{"
125
- },
126
- {
127
- type: TokenType.RightBracket,
128
- matcher: "}"
129
- },
130
- {
131
- type: TokenType.LeftParens,
132
- matcher: "("
133
- },
134
- {
135
- type: TokenType.RightParens,
136
- matcher: ")"
137
- },
138
- {
139
- type: TokenType.LeftSquareBracket,
140
- matcher: "["
141
- },
142
- {
143
- type: TokenType.RightSquareBracket,
144
- matcher: "]"
145
- },
146
- {
147
- type: TokenType.Operator,
148
- matcher: [].concat(FINAL_OPERATORS, LOGICAL_OPERATORS)
149
- },
150
- {
151
- type: TokenType.Pipe,
152
- matcher: "|"
153
- },
154
- {
155
- type: TokenType.Comma,
156
- matcher: ","
157
- },
158
- {
159
- type: TokenType.Range,
160
- matcher: /(\d+\.\.\d*|\d*\.\.\d+)/g,
161
- valueExtractor: (value) => {
162
- const [, left, right] = value.match(/(\d*)\.\.(\d*)/);
163
- return [
164
- parseInt(left),
165
- parseInt(right)
166
- ];
167
- }
168
- },
169
- {
170
- type: TokenType.Dot,
171
- matcher: "."
172
- },
173
- {
174
- type: TokenType.Number,
175
- matcher: /[0-9]+(\.[0-9]+)?/,
176
- construct: Number
177
- },
178
- {
179
- type: TokenType.Boolean,
180
- matcher: [
181
- "true",
182
- "false"
183
- ],
184
- construct: Boolean
185
- },
186
- {
187
- type: TokenType.Keyword,
188
- matcher: Array.from(keywordsSet),
189
- condition: (state, lastToken) => {
190
- if (state.variableScopeStack.at(-1) || state.variableExpressionStack.at(-1)) {
191
- return false;
192
- }
193
- if (lastToken && lastToken.type === TokenType.Keyword) {
194
- switch (lastToken.value) {
195
- case "if":
196
- case "badge":
197
- case "title": {
198
- return false;
199
- }
200
- }
201
- }
202
- return true;
203
- }
204
- },
205
- {
206
- type: TokenType.MacroName,
207
- matcher: /[a-zA-Z]([a-zA-Z0-9]|_)+\(/,
208
- valueExtractor: (value) => value.slice(0, -1)
209
- },
210
- {
211
- type: TokenType.Identifier,
212
- matcher: /([a-zA-Z0-9]|_)+/
213
- },
214
- {
215
- type: TokenType.QuotedString,
216
- matcher: /"([^"]+)"/,
217
- valueExtractor: (value) => value.slice(1, -1)
218
- },
219
- {
220
- type: TokenType.AttributeName,
221
- matcher: /@[a-zA-Z0-9]+/,
222
- valueExtractor: (value) => value.slice(1)
223
- }
224
- ];
225
- export const tokenize = function(rawInput, fileLocation) {
226
- const input = rawInput.replace(/\r\n/g, "\n");
227
- let index = 0, line = 1, start = 0, end = 0;
228
- const tokens = [];
229
- const errors = [];
230
- const state = {
231
- variableScopeStack: [],
232
- variableExpressionStack: []
233
- };
234
- while (index < input.length) {
235
- let hasMatch = false;
236
- for (const { type, matcher, valueExtractor, construct, condition } of TOKENS) {
237
- let value;
238
- let token;
239
- const lastToken = tokens.at(-1);
240
- if (condition) {
241
- if (!condition(state, lastToken)) {
242
- continue;
243
- }
244
- }
245
- if (typeof matcher === "string") {
246
- if (input.slice(index).startsWith(matcher)) {
247
- value = matcher;
248
- }
249
- } else if (matcher instanceof RegExp) {
250
- const currentMatcher = new RegExp(matcher.source, "y");
251
- currentMatcher.lastIndex = index;
252
- const matched = currentMatcher.exec(input);
253
- if (matched) {
254
- [value] = matched;
255
- }
256
- } else {
257
- const segment = input.slice(index, index + input.slice(index).search(/[ \t\n\{\}\(\)\[\]]/));
258
- if (segment && matcher.includes(segment)) {
259
- value = segment;
260
- }
261
- }
262
- if (value) {
263
- let tokenValue;
264
- const location = {
265
- file: fileLocation,
266
- index: index += value.length,
267
- line,
268
- end: end += value.length,
269
- start: start = end - value.length
270
- };
271
- switch (type) {
272
- case null:
273
- break;
274
- case TokenType.LineBreak:
275
- line++;
276
- end = 0;
277
- start = 0;
278
- break;
279
- case TokenType.Comment: {
280
- while (input[index++] !== "\n") {
281
- }
282
- line++;
283
- break;
284
- }
285
- default: {
286
- if (valueExtractor) {
287
- tokenValue = construct ? construct(valueExtractor(value)) : valueExtractor(value);
288
- } else {
289
- tokenValue = construct ? construct(value) : value;
290
- }
291
- token = {
292
- type,
293
- location,
294
- value: tokenValue
295
- };
296
- switch (type) {
297
- case TokenType.LeftBracket: {
298
- let variableScope = false;
299
- if (lastToken && lastToken.type === TokenType.Keyword) {
300
- switch (lastToken.value) {
301
- case "fields":
302
- case "information":
303
- case "form":
304
- case "table":
305
- case "tableMeta":
306
- case "indexes":
307
- case "filters":
308
- case "writable":
309
- case "required":
310
- case "properties": {
311
- variableScope = true;
312
- break;
313
- }
314
- }
315
- }
316
- state.variableScopeStack.push(variableScope);
317
- break;
318
- }
319
- case TokenType.LeftParens: {
320
- let variableExpression = false;
321
- if (lastToken) {
322
- switch (lastToken.type) {
323
- case TokenType.Keyword: {
324
- switch (lastToken.value) {
325
- case "if": {
326
- variableExpression = true;
327
- break;
328
- }
329
- }
330
- break;
331
- }
332
- case TokenType.Operator: {
333
- variableExpression = true;
334
- break;
335
- }
336
- }
337
- }
338
- state.variableExpressionStack.push(variableExpression);
339
- break;
340
- }
341
- case TokenType.RightBracket: {
342
- if (state.variableScopeStack.length > 0) {
343
- state.variableScopeStack.pop();
344
- }
345
- break;
346
- }
347
- case TokenType.RightParens: {
348
- if (state.variableExpressionStack.length > 0) {
349
- state.variableExpressionStack.pop();
350
- }
351
- break;
352
- }
353
- }
354
- tokens.push(token);
355
- }
356
- }
357
- hasMatch = true;
358
- }
359
- }
360
- if (!hasMatch) {
361
- index += input.slice(index).search(/[ \t\n\{\}\(\)\[\]]/);
362
- errors.push(new Diagnostic("unexpected token", {
363
- file: fileLocation,
364
- index,
365
- line,
366
- start,
367
- end
368
- }));
369
- }
370
- }
371
- return {
372
- tokens,
373
- errors
374
- };
375
- };