@vasp-framework/parser 0.1.0
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/README.md +69 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/lexer/Lexer.d.ts +21 -0
- package/dist/lexer/Lexer.d.ts.map +1 -0
- package/dist/lexer/Lexer.js +219 -0
- package/dist/lexer/Lexer.js.map +1 -0
- package/dist/lexer/Token.d.ts +8 -0
- package/dist/lexer/Token.d.ts.map +1 -0
- package/dist/lexer/Token.js +2 -0
- package/dist/lexer/Token.js.map +1 -0
- package/dist/lexer/TokenType.d.ts +29 -0
- package/dist/lexer/TokenType.d.ts.map +1 -0
- package/dist/lexer/TokenType.js +49 -0
- package/dist/lexer/TokenType.js.map +1 -0
- package/dist/parser/Parser.d.ts +3 -0
- package/dist/parser/Parser.d.ts.map +1 -0
- package/dist/parser/Parser.js +408 -0
- package/dist/parser/Parser.js.map +1 -0
- package/dist/validator/SemanticValidator.d.ts +13 -0
- package/dist/validator/SemanticValidator.d.ts.map +1 -0
- package/dist/validator/SemanticValidator.js +145 -0
- package/dist/validator/SemanticValidator.js.map +1 -0
- package/package.json +35 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export var TokenType;
|
|
2
|
+
(function (TokenType) {
|
|
3
|
+
// Keywords (top-level block starters)
|
|
4
|
+
TokenType["KW_APP"] = "app";
|
|
5
|
+
TokenType["KW_AUTH"] = "auth";
|
|
6
|
+
TokenType["KW_ROUTE"] = "route";
|
|
7
|
+
TokenType["KW_PAGE"] = "page";
|
|
8
|
+
TokenType["KW_QUERY"] = "query";
|
|
9
|
+
TokenType["KW_ACTION"] = "action";
|
|
10
|
+
TokenType["KW_CRUD"] = "crud";
|
|
11
|
+
TokenType["KW_REALTIME"] = "realtime";
|
|
12
|
+
TokenType["KW_JOB"] = "job";
|
|
13
|
+
// Value-position keywords
|
|
14
|
+
TokenType["KW_IMPORT"] = "import";
|
|
15
|
+
TokenType["KW_FROM"] = "from";
|
|
16
|
+
// Literals
|
|
17
|
+
TokenType["IDENTIFIER"] = "IDENTIFIER";
|
|
18
|
+
TokenType["STRING"] = "STRING";
|
|
19
|
+
TokenType["BOOLEAN"] = "BOOLEAN";
|
|
20
|
+
TokenType["NUMBER"] = "NUMBER";
|
|
21
|
+
// Punctuation
|
|
22
|
+
TokenType["LBRACE"] = "{";
|
|
23
|
+
TokenType["RBRACE"] = "}";
|
|
24
|
+
TokenType["LBRACKET"] = "[";
|
|
25
|
+
TokenType["RBRACKET"] = "]";
|
|
26
|
+
TokenType["COLON"] = ":";
|
|
27
|
+
TokenType["COMMA"] = ",";
|
|
28
|
+
// Meta
|
|
29
|
+
TokenType["EOF"] = "EOF";
|
|
30
|
+
})(TokenType || (TokenType = {}));
|
|
31
|
+
/** Keywords that start a top-level declaration block */
|
|
32
|
+
export const BLOCK_KEYWORDS = new Set([
|
|
33
|
+
TokenType.KW_APP,
|
|
34
|
+
TokenType.KW_AUTH,
|
|
35
|
+
TokenType.KW_ROUTE,
|
|
36
|
+
TokenType.KW_PAGE,
|
|
37
|
+
TokenType.KW_QUERY,
|
|
38
|
+
TokenType.KW_ACTION,
|
|
39
|
+
TokenType.KW_CRUD,
|
|
40
|
+
TokenType.KW_REALTIME,
|
|
41
|
+
TokenType.KW_JOB,
|
|
42
|
+
]);
|
|
43
|
+
/** All reserved keywords (cannot be used as identifiers in value position) */
|
|
44
|
+
export const ALL_KEYWORDS = new Set([
|
|
45
|
+
...BLOCK_KEYWORDS,
|
|
46
|
+
TokenType.KW_IMPORT,
|
|
47
|
+
TokenType.KW_FROM,
|
|
48
|
+
]);
|
|
49
|
+
//# sourceMappingURL=TokenType.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TokenType.js","sourceRoot":"","sources":["../../src/lexer/TokenType.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,SAgCX;AAhCD,WAAY,SAAS;IACnB,sCAAsC;IACtC,2BAAc,CAAA;IACd,6BAAgB,CAAA;IAChB,+BAAkB,CAAA;IAClB,6BAAgB,CAAA;IAChB,+BAAkB,CAAA;IAClB,iCAAoB,CAAA;IACpB,6BAAgB,CAAA;IAChB,qCAAwB,CAAA;IACxB,2BAAc,CAAA;IAEd,0BAA0B;IAC1B,iCAAoB,CAAA;IACpB,6BAAgB,CAAA;IAEhB,WAAW;IACX,sCAAyB,CAAA;IACzB,8BAAiB,CAAA;IACjB,gCAAmB,CAAA;IACnB,8BAAiB,CAAA;IAEjB,cAAc;IACd,yBAAY,CAAA;IACZ,yBAAY,CAAA;IACZ,2BAAc,CAAA;IACd,2BAAc,CAAA;IACd,wBAAW,CAAA;IACX,wBAAW,CAAA;IAEX,OAAO;IACP,wBAAW,CAAA;AACb,CAAC,EAhCW,SAAS,KAAT,SAAS,QAgCpB;AAED,wDAAwD;AACxD,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,GAAG,CAAS;IAC5C,SAAS,CAAC,MAAM;IAChB,SAAS,CAAC,OAAO;IACjB,SAAS,CAAC,QAAQ;IAClB,SAAS,CAAC,OAAO;IACjB,SAAS,CAAC,QAAQ;IAClB,SAAS,CAAC,SAAS;IACnB,SAAS,CAAC,OAAO;IACjB,SAAS,CAAC,WAAW;IACrB,SAAS,CAAC,MAAM;CACjB,CAAC,CAAA;AAEF,8EAA8E;AAC9E,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,GAAG,CAAS;IAC1C,GAAG,cAAc;IACjB,SAAS,CAAC,SAAS;IACnB,SAAS,CAAC,OAAO;CAClB,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Parser.d.ts","sourceRoot":"","sources":["../../src/parser/Parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAeV,OAAO,EACR,MAAM,sBAAsB,CAAA;AAM7B,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,SAAc,GAAG,OAAO,CAGrE"}
|
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
import { ParseError } from '@vasp-framework/core';
|
|
2
|
+
import { Lexer } from '../lexer/Lexer.js';
|
|
3
|
+
import { TokenType } from '../lexer/TokenType.js';
|
|
4
|
+
export function parse(source, filename = 'main.vasp') {
|
|
5
|
+
const tokens = new Lexer(source, filename).tokenize();
|
|
6
|
+
return new Parser(tokens, filename).parse();
|
|
7
|
+
}
|
|
8
|
+
class Parser {
|
|
9
|
+
tokens;
|
|
10
|
+
filename;
|
|
11
|
+
pos = 0;
|
|
12
|
+
constructor(tokens, filename) {
|
|
13
|
+
this.tokens = tokens;
|
|
14
|
+
this.filename = filename;
|
|
15
|
+
}
|
|
16
|
+
// ---- Public ----
|
|
17
|
+
parse() {
|
|
18
|
+
const ast = {
|
|
19
|
+
app: null, // validated by SemanticValidator
|
|
20
|
+
routes: [],
|
|
21
|
+
pages: [],
|
|
22
|
+
queries: [],
|
|
23
|
+
actions: [],
|
|
24
|
+
cruds: [],
|
|
25
|
+
realtimes: [],
|
|
26
|
+
jobs: [],
|
|
27
|
+
};
|
|
28
|
+
while (!this.isEOF()) {
|
|
29
|
+
const kw = this.peek();
|
|
30
|
+
switch (kw.type) {
|
|
31
|
+
case TokenType.KW_APP:
|
|
32
|
+
ast.app = this.parseApp();
|
|
33
|
+
break;
|
|
34
|
+
case TokenType.KW_AUTH:
|
|
35
|
+
ast.auth = this.parseAuth();
|
|
36
|
+
break;
|
|
37
|
+
case TokenType.KW_ROUTE:
|
|
38
|
+
ast.routes.push(this.parseRoute());
|
|
39
|
+
break;
|
|
40
|
+
case TokenType.KW_PAGE:
|
|
41
|
+
ast.pages.push(this.parsePage());
|
|
42
|
+
break;
|
|
43
|
+
case TokenType.KW_QUERY:
|
|
44
|
+
ast.queries.push(this.parseQuery());
|
|
45
|
+
break;
|
|
46
|
+
case TokenType.KW_ACTION:
|
|
47
|
+
ast.actions.push(this.parseAction());
|
|
48
|
+
break;
|
|
49
|
+
case TokenType.KW_CRUD:
|
|
50
|
+
ast.cruds.push(this.parseCrud());
|
|
51
|
+
break;
|
|
52
|
+
case TokenType.KW_REALTIME:
|
|
53
|
+
ast.realtimes.push(this.parseRealtime());
|
|
54
|
+
break;
|
|
55
|
+
case TokenType.KW_JOB:
|
|
56
|
+
ast.jobs.push(this.parseJob());
|
|
57
|
+
break;
|
|
58
|
+
default:
|
|
59
|
+
throw this.error('E010_UNEXPECTED_TOKEN', `Unexpected token '${kw.value}' at top level`, 'Expected a declaration keyword: app, auth, route, page, query, action, crud, realtime, or job', kw.loc);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return ast;
|
|
63
|
+
}
|
|
64
|
+
// ---- Block parsers ----
|
|
65
|
+
parseApp() {
|
|
66
|
+
const loc = this.consume(TokenType.KW_APP).loc;
|
|
67
|
+
const name = this.consumeIdentifier();
|
|
68
|
+
this.consume(TokenType.LBRACE);
|
|
69
|
+
let title = '';
|
|
70
|
+
let db = 'Drizzle';
|
|
71
|
+
let ssr = false;
|
|
72
|
+
let typescript = false;
|
|
73
|
+
while (!this.check(TokenType.RBRACE)) {
|
|
74
|
+
const key = this.consumeIdentifier();
|
|
75
|
+
this.consume(TokenType.COLON);
|
|
76
|
+
switch (key.value) {
|
|
77
|
+
case 'title':
|
|
78
|
+
title = this.consumeString();
|
|
79
|
+
break;
|
|
80
|
+
case 'db':
|
|
81
|
+
db = this.consumeIdentifier().value;
|
|
82
|
+
break;
|
|
83
|
+
case 'ssr': {
|
|
84
|
+
const val = this.peek();
|
|
85
|
+
if (val.type === TokenType.BOOLEAN) {
|
|
86
|
+
ssr = this.consume(TokenType.BOOLEAN).value === 'true';
|
|
87
|
+
}
|
|
88
|
+
else if (val.type === TokenType.STRING) {
|
|
89
|
+
const s = this.consumeString();
|
|
90
|
+
if (s !== 'ssg') {
|
|
91
|
+
throw this.error('E011_INVALID_SSR', `Invalid ssr value "${s}"`, 'Use: false, true, or "ssg"', val.loc);
|
|
92
|
+
}
|
|
93
|
+
ssr = 'ssg';
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
throw this.error('E011_INVALID_SSR', 'Invalid ssr value', 'Use: false, true, or "ssg"', val.loc);
|
|
97
|
+
}
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
case 'typescript':
|
|
101
|
+
typescript = this.consume(TokenType.BOOLEAN).value === 'true';
|
|
102
|
+
break;
|
|
103
|
+
default:
|
|
104
|
+
throw this.error('E012_UNKNOWN_PROP', `Unknown app property '${key.value}'`, 'Valid properties: title, db, ssr, typescript', key.loc);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
this.consume(TokenType.RBRACE);
|
|
108
|
+
return { type: 'App', name: name.value, loc, title, db, ssr, typescript };
|
|
109
|
+
}
|
|
110
|
+
parseAuth() {
|
|
111
|
+
const loc = this.consume(TokenType.KW_AUTH).loc;
|
|
112
|
+
const name = this.consumeIdentifier();
|
|
113
|
+
this.consume(TokenType.LBRACE);
|
|
114
|
+
let userEntity = '';
|
|
115
|
+
let methods = [];
|
|
116
|
+
while (!this.check(TokenType.RBRACE)) {
|
|
117
|
+
const key = this.consumeIdentifier();
|
|
118
|
+
this.consume(TokenType.COLON);
|
|
119
|
+
switch (key.value) {
|
|
120
|
+
case 'userEntity':
|
|
121
|
+
userEntity = this.consumeIdentifier().value;
|
|
122
|
+
break;
|
|
123
|
+
case 'methods':
|
|
124
|
+
methods = this.parseIdentifierArray();
|
|
125
|
+
break;
|
|
126
|
+
default:
|
|
127
|
+
throw this.error('E013_UNKNOWN_PROP', `Unknown auth property '${key.value}'`, 'Valid properties: userEntity, methods', key.loc);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
this.consume(TokenType.RBRACE);
|
|
131
|
+
return { type: 'Auth', name: name.value, loc, userEntity, methods };
|
|
132
|
+
}
|
|
133
|
+
parseRoute() {
|
|
134
|
+
const loc = this.consume(TokenType.KW_ROUTE).loc;
|
|
135
|
+
const name = this.consumeIdentifier();
|
|
136
|
+
this.consume(TokenType.LBRACE);
|
|
137
|
+
let path = '';
|
|
138
|
+
let to = '';
|
|
139
|
+
while (!this.check(TokenType.RBRACE)) {
|
|
140
|
+
const key = this.consumeIdentifier();
|
|
141
|
+
this.consume(TokenType.COLON);
|
|
142
|
+
switch (key.value) {
|
|
143
|
+
case 'path':
|
|
144
|
+
path = this.consumeString();
|
|
145
|
+
break;
|
|
146
|
+
case 'to':
|
|
147
|
+
to = this.consumeIdentifier().value;
|
|
148
|
+
break;
|
|
149
|
+
default:
|
|
150
|
+
throw this.error('E014_UNKNOWN_PROP', `Unknown route property '${key.value}'`, 'Valid properties: path, to', key.loc);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
this.consume(TokenType.RBRACE);
|
|
154
|
+
return { type: 'Route', name: name.value, loc, path, to };
|
|
155
|
+
}
|
|
156
|
+
parsePage() {
|
|
157
|
+
const loc = this.consume(TokenType.KW_PAGE).loc;
|
|
158
|
+
const name = this.consumeIdentifier();
|
|
159
|
+
this.consume(TokenType.LBRACE);
|
|
160
|
+
let component = null;
|
|
161
|
+
while (!this.check(TokenType.RBRACE)) {
|
|
162
|
+
const key = this.consumeIdentifier();
|
|
163
|
+
this.consume(TokenType.COLON);
|
|
164
|
+
switch (key.value) {
|
|
165
|
+
case 'component':
|
|
166
|
+
component = this.parseImportExpression();
|
|
167
|
+
break;
|
|
168
|
+
default:
|
|
169
|
+
throw this.error('E015_UNKNOWN_PROP', `Unknown page property '${key.value}'`, 'Valid properties: component', key.loc);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
this.consume(TokenType.RBRACE);
|
|
173
|
+
if (!component) {
|
|
174
|
+
throw this.error('E016_MISSING_COMPONENT', `Page '${name.value}' is missing a component`, 'Add: component: import Foo from "@src/pages/Foo.vue"', loc);
|
|
175
|
+
}
|
|
176
|
+
return { type: 'Page', name: name.value, loc, component };
|
|
177
|
+
}
|
|
178
|
+
parseQuery() {
|
|
179
|
+
const loc = this.consume(TokenType.KW_QUERY).loc;
|
|
180
|
+
const name = this.consumeIdentifier();
|
|
181
|
+
this.consume(TokenType.LBRACE);
|
|
182
|
+
let fn = null;
|
|
183
|
+
let entities = [];
|
|
184
|
+
let auth = false;
|
|
185
|
+
while (!this.check(TokenType.RBRACE)) {
|
|
186
|
+
const key = this.consumeIdentifier();
|
|
187
|
+
this.consume(TokenType.COLON);
|
|
188
|
+
switch (key.value) {
|
|
189
|
+
case 'fn':
|
|
190
|
+
fn = this.parseImportExpression();
|
|
191
|
+
break;
|
|
192
|
+
case 'entities':
|
|
193
|
+
entities = this.parseIdentifierArray();
|
|
194
|
+
break;
|
|
195
|
+
case 'auth':
|
|
196
|
+
auth = this.consume(TokenType.BOOLEAN).value === 'true';
|
|
197
|
+
break;
|
|
198
|
+
default:
|
|
199
|
+
throw this.error('E017_UNKNOWN_PROP', `Unknown query property '${key.value}'`, 'Valid properties: fn, entities, auth', key.loc);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
this.consume(TokenType.RBRACE);
|
|
203
|
+
if (!fn) {
|
|
204
|
+
throw this.error('E018_MISSING_FN', `Query '${name.value}' is missing fn`, 'Add: fn: import { myFn } from "@src/queries.js"', loc);
|
|
205
|
+
}
|
|
206
|
+
return { type: 'Query', name: name.value, loc, fn, entities, auth };
|
|
207
|
+
}
|
|
208
|
+
parseAction() {
|
|
209
|
+
const loc = this.consume(TokenType.KW_ACTION).loc;
|
|
210
|
+
const name = this.consumeIdentifier();
|
|
211
|
+
this.consume(TokenType.LBRACE);
|
|
212
|
+
let fn = null;
|
|
213
|
+
let entities = [];
|
|
214
|
+
let auth = false;
|
|
215
|
+
while (!this.check(TokenType.RBRACE)) {
|
|
216
|
+
const key = this.consumeIdentifier();
|
|
217
|
+
this.consume(TokenType.COLON);
|
|
218
|
+
switch (key.value) {
|
|
219
|
+
case 'fn':
|
|
220
|
+
fn = this.parseImportExpression();
|
|
221
|
+
break;
|
|
222
|
+
case 'entities':
|
|
223
|
+
entities = this.parseIdentifierArray();
|
|
224
|
+
break;
|
|
225
|
+
case 'auth':
|
|
226
|
+
auth = this.consume(TokenType.BOOLEAN).value === 'true';
|
|
227
|
+
break;
|
|
228
|
+
default:
|
|
229
|
+
throw this.error('E019_UNKNOWN_PROP', `Unknown action property '${key.value}'`, 'Valid properties: fn, entities, auth', key.loc);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
this.consume(TokenType.RBRACE);
|
|
233
|
+
if (!fn) {
|
|
234
|
+
throw this.error('E020_MISSING_FN', `Action '${name.value}' is missing fn`, 'Add: fn: import { myFn } from "@src/actions.js"', loc);
|
|
235
|
+
}
|
|
236
|
+
return { type: 'Action', name: name.value, loc, fn, entities, auth };
|
|
237
|
+
}
|
|
238
|
+
parseCrud() {
|
|
239
|
+
const loc = this.consume(TokenType.KW_CRUD).loc;
|
|
240
|
+
const name = this.consumeIdentifier();
|
|
241
|
+
this.consume(TokenType.LBRACE);
|
|
242
|
+
let entity = '';
|
|
243
|
+
let operations = [];
|
|
244
|
+
while (!this.check(TokenType.RBRACE)) {
|
|
245
|
+
const key = this.consumeIdentifier();
|
|
246
|
+
this.consume(TokenType.COLON);
|
|
247
|
+
switch (key.value) {
|
|
248
|
+
case 'entity':
|
|
249
|
+
entity = this.consumeIdentifier().value;
|
|
250
|
+
break;
|
|
251
|
+
case 'operations':
|
|
252
|
+
operations = this.parseIdentifierArray();
|
|
253
|
+
break;
|
|
254
|
+
default:
|
|
255
|
+
throw this.error('E021_UNKNOWN_PROP', `Unknown crud property '${key.value}'`, 'Valid properties: entity, operations', key.loc);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
this.consume(TokenType.RBRACE);
|
|
259
|
+
return { type: 'Crud', name: name.value, loc, entity, operations };
|
|
260
|
+
}
|
|
261
|
+
parseRealtime() {
|
|
262
|
+
const loc = this.consume(TokenType.KW_REALTIME).loc;
|
|
263
|
+
const name = this.consumeIdentifier();
|
|
264
|
+
this.consume(TokenType.LBRACE);
|
|
265
|
+
let entity = '';
|
|
266
|
+
let events = [];
|
|
267
|
+
while (!this.check(TokenType.RBRACE)) {
|
|
268
|
+
const key = this.consumeIdentifier();
|
|
269
|
+
this.consume(TokenType.COLON);
|
|
270
|
+
switch (key.value) {
|
|
271
|
+
case 'entity':
|
|
272
|
+
entity = this.consumeIdentifier().value;
|
|
273
|
+
break;
|
|
274
|
+
case 'events':
|
|
275
|
+
events = this.parseIdentifierArray();
|
|
276
|
+
break;
|
|
277
|
+
default:
|
|
278
|
+
throw this.error('E022_UNKNOWN_PROP', `Unknown realtime property '${key.value}'`, 'Valid properties: entity, events', key.loc);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
this.consume(TokenType.RBRACE);
|
|
282
|
+
return { type: 'Realtime', name: name.value, loc, entity, events };
|
|
283
|
+
}
|
|
284
|
+
parseJob() {
|
|
285
|
+
const loc = this.consume(TokenType.KW_JOB).loc;
|
|
286
|
+
const name = this.consumeIdentifier();
|
|
287
|
+
this.consume(TokenType.LBRACE);
|
|
288
|
+
let executor = 'PgBoss';
|
|
289
|
+
let performFn = null;
|
|
290
|
+
let schedule;
|
|
291
|
+
while (!this.check(TokenType.RBRACE)) {
|
|
292
|
+
const key = this.consumeIdentifier();
|
|
293
|
+
this.consume(TokenType.COLON);
|
|
294
|
+
switch (key.value) {
|
|
295
|
+
case 'executor':
|
|
296
|
+
executor = this.consumeIdentifier().value;
|
|
297
|
+
break;
|
|
298
|
+
case 'perform': {
|
|
299
|
+
// Nested block: perform: { fn: import ... }
|
|
300
|
+
this.consume(TokenType.LBRACE);
|
|
301
|
+
while (!this.check(TokenType.RBRACE)) {
|
|
302
|
+
const innerKey = this.consumeIdentifier();
|
|
303
|
+
this.consume(TokenType.COLON);
|
|
304
|
+
if (innerKey.value === 'fn') {
|
|
305
|
+
performFn = this.parseImportExpression();
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
throw this.error('E023_UNKNOWN_PROP', `Unknown perform property '${innerKey.value}'`, 'Valid properties: fn', innerKey.loc);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
this.consume(TokenType.RBRACE);
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
case 'schedule':
|
|
315
|
+
schedule = this.consumeString();
|
|
316
|
+
break;
|
|
317
|
+
default:
|
|
318
|
+
throw this.error('E024_UNKNOWN_PROP', `Unknown job property '${key.value}'`, 'Valid properties: executor, perform, schedule', key.loc);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
this.consume(TokenType.RBRACE);
|
|
322
|
+
if (!performFn) {
|
|
323
|
+
throw this.error('E025_MISSING_PERFORM', `Job '${name.value}' is missing perform.fn`, 'Add: perform: { fn: import { myJob } from "@src/jobs.js" }', loc);
|
|
324
|
+
}
|
|
325
|
+
return {
|
|
326
|
+
type: 'Job',
|
|
327
|
+
name: name.value,
|
|
328
|
+
loc,
|
|
329
|
+
executor,
|
|
330
|
+
perform: { fn: performFn },
|
|
331
|
+
...(schedule !== undefined ? { schedule } : {}),
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
// ---- Value parsers ----
|
|
335
|
+
/**
|
|
336
|
+
* Parses both import forms:
|
|
337
|
+
* import Foo from "@src/..." → DefaultImportExpression
|
|
338
|
+
* import { foo } from "@src/..." → NamedImportExpression
|
|
339
|
+
*/
|
|
340
|
+
parseImportExpression() {
|
|
341
|
+
const loc = this.consume(TokenType.KW_IMPORT).loc;
|
|
342
|
+
// Named import: import { foo } from "..."
|
|
343
|
+
if (this.check(TokenType.LBRACE)) {
|
|
344
|
+
this.consume(TokenType.LBRACE);
|
|
345
|
+
const namedExport = this.consumeIdentifier().value;
|
|
346
|
+
this.consume(TokenType.RBRACE);
|
|
347
|
+
this.consume(TokenType.KW_FROM);
|
|
348
|
+
const source = this.consumeString();
|
|
349
|
+
return { kind: 'named', namedExport, source };
|
|
350
|
+
}
|
|
351
|
+
// Default import: import Foo from "..."
|
|
352
|
+
const defaultExport = this.consumeIdentifier().value;
|
|
353
|
+
this.consume(TokenType.KW_FROM);
|
|
354
|
+
const source = this.consumeString();
|
|
355
|
+
return { kind: 'default', defaultExport, source };
|
|
356
|
+
}
|
|
357
|
+
/** Parses: [ Foo, Bar, Baz ] */
|
|
358
|
+
parseIdentifierArray() {
|
|
359
|
+
this.consume(TokenType.LBRACKET);
|
|
360
|
+
const items = [];
|
|
361
|
+
while (!this.check(TokenType.RBRACKET)) {
|
|
362
|
+
items.push(this.consumeIdentifier().value);
|
|
363
|
+
if (this.check(TokenType.COMMA)) {
|
|
364
|
+
this.consume(TokenType.COMMA);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
this.consume(TokenType.RBRACKET);
|
|
368
|
+
return items;
|
|
369
|
+
}
|
|
370
|
+
// ---- Token cursor helpers ----
|
|
371
|
+
peek() {
|
|
372
|
+
return this.tokens[this.pos] ?? { type: TokenType.EOF, value: '', loc: { line: 0, col: 0, offset: 0 } };
|
|
373
|
+
}
|
|
374
|
+
check(type) {
|
|
375
|
+
return this.peek().type === type;
|
|
376
|
+
}
|
|
377
|
+
isEOF() {
|
|
378
|
+
return this.check(TokenType.EOF);
|
|
379
|
+
}
|
|
380
|
+
consume(type) {
|
|
381
|
+
const tok = this.peek();
|
|
382
|
+
if (tok.type !== type) {
|
|
383
|
+
throw this.error('E030_EXPECTED_TOKEN', `Expected '${type}' but got '${tok.value || tok.type}'`, `Add the missing '${type}'`, tok.loc);
|
|
384
|
+
}
|
|
385
|
+
this.pos++;
|
|
386
|
+
return tok;
|
|
387
|
+
}
|
|
388
|
+
consumeIdentifier() {
|
|
389
|
+
const tok = this.peek();
|
|
390
|
+
if (tok.type !== TokenType.IDENTIFIER) {
|
|
391
|
+
throw this.error('E031_EXPECTED_IDENTIFIER', `Expected an identifier but got '${tok.value || tok.type}'`, 'Provide a valid name (letters, digits, underscores)', tok.loc);
|
|
392
|
+
}
|
|
393
|
+
this.pos++;
|
|
394
|
+
return tok;
|
|
395
|
+
}
|
|
396
|
+
consumeString() {
|
|
397
|
+
const tok = this.peek();
|
|
398
|
+
if (tok.type !== TokenType.STRING) {
|
|
399
|
+
throw this.error('E032_EXPECTED_STRING', `Expected a string but got '${tok.value || tok.type}'`, 'Wrap the value in double quotes: "value"', tok.loc);
|
|
400
|
+
}
|
|
401
|
+
this.pos++;
|
|
402
|
+
return tok.value;
|
|
403
|
+
}
|
|
404
|
+
error(code, message, hint, loc) {
|
|
405
|
+
return new ParseError([{ code, message, hint, ...(loc !== undefined ? { loc } : {}) }]);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
//# sourceMappingURL=Parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Parser.js","sourceRoot":"","sources":["../../src/parser/Parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { VaspAST } from '@vasp-framework/core';
|
|
2
|
+
export declare class SemanticValidator {
|
|
3
|
+
private readonly diagnostics;
|
|
4
|
+
validate(ast: VaspAST): void;
|
|
5
|
+
private checkAppExists;
|
|
6
|
+
private checkRouteTargets;
|
|
7
|
+
private checkCrudOperations;
|
|
8
|
+
private checkRealtimeEntities;
|
|
9
|
+
private checkAuthMethods;
|
|
10
|
+
private checkQueryActionEntities;
|
|
11
|
+
private checkJobExecutors;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=SemanticValidator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SemanticValidator.d.ts","sourceRoot":"","sources":["../../src/validator/SemanticValidator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmB,OAAO,EAAE,MAAM,sBAAsB,CAAA;AAGpE,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAwB;IAEpD,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI;IAc5B,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,iBAAiB;IAczB,OAAO,CAAC,mBAAmB;IAuB3B,OAAO,CAAC,qBAAqB;IAwB7B,OAAO,CAAC,gBAAgB;IAsBxB,OAAO,CAAC,wBAAwB;IA4BhC,OAAO,CAAC,iBAAiB;CAY1B"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { ParseError, SUPPORTED_AUTH_METHODS, SUPPORTED_CRUD_OPERATIONS, SUPPORTED_REALTIME_EVENTS } from '@vasp-framework/core';
|
|
2
|
+
export class SemanticValidator {
|
|
3
|
+
diagnostics = [];
|
|
4
|
+
validate(ast) {
|
|
5
|
+
this.checkAppExists(ast);
|
|
6
|
+
this.checkRouteTargets(ast);
|
|
7
|
+
this.checkCrudOperations(ast);
|
|
8
|
+
this.checkRealtimeEntities(ast);
|
|
9
|
+
this.checkAuthMethods(ast);
|
|
10
|
+
this.checkQueryActionEntities(ast);
|
|
11
|
+
this.checkJobExecutors(ast);
|
|
12
|
+
if (this.diagnostics.length > 0) {
|
|
13
|
+
throw new ParseError(this.diagnostics);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
checkAppExists(ast) {
|
|
17
|
+
if (!ast.app) {
|
|
18
|
+
this.diagnostics.push({
|
|
19
|
+
code: 'E100_MISSING_APP_BLOCK',
|
|
20
|
+
message: 'No app block found in main.vasp',
|
|
21
|
+
hint: 'Every Vasp project requires exactly one app { } block',
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
checkRouteTargets(ast) {
|
|
26
|
+
const pageNames = new Set(ast.pages.map((p) => p.name));
|
|
27
|
+
for (const route of ast.routes) {
|
|
28
|
+
if (!pageNames.has(route.to)) {
|
|
29
|
+
this.diagnostics.push({
|
|
30
|
+
code: 'E101_UNKNOWN_PAGE_REF',
|
|
31
|
+
message: `Route '${route.name}' references unknown page '${route.to}'`,
|
|
32
|
+
hint: `Add a page block named '${route.to}', or fix the 'to' value in route '${route.name}'`,
|
|
33
|
+
loc: route.loc,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
checkCrudOperations(ast) {
|
|
39
|
+
for (const crud of ast.cruds) {
|
|
40
|
+
if (crud.operations.length === 0) {
|
|
41
|
+
this.diagnostics.push({
|
|
42
|
+
code: 'E102_EMPTY_CRUD_OPERATIONS',
|
|
43
|
+
message: `crud '${crud.name}' has no operations`,
|
|
44
|
+
hint: 'Add at least one operation: operations: [list, create, update, delete]',
|
|
45
|
+
loc: crud.loc,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
for (const op of crud.operations) {
|
|
49
|
+
if (!SUPPORTED_CRUD_OPERATIONS.includes(op)) {
|
|
50
|
+
this.diagnostics.push({
|
|
51
|
+
code: 'E103_UNKNOWN_CRUD_OPERATION',
|
|
52
|
+
message: `Unknown crud operation '${op}' in '${crud.name}'`,
|
|
53
|
+
hint: `Supported operations: ${SUPPORTED_CRUD_OPERATIONS.join(', ')}`,
|
|
54
|
+
loc: crud.loc,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
checkRealtimeEntities(ast) {
|
|
61
|
+
const crudEntities = new Set(ast.cruds.map((c) => c.entity));
|
|
62
|
+
for (const rt of ast.realtimes) {
|
|
63
|
+
if (!crudEntities.has(rt.entity)) {
|
|
64
|
+
this.diagnostics.push({
|
|
65
|
+
code: 'E104_REALTIME_ENTITY_NOT_CRUD',
|
|
66
|
+
message: `realtime '${rt.name}' references entity '${rt.entity}' which has no crud block`,
|
|
67
|
+
hint: `Add a crud block for entity '${rt.entity}', or remove the realtime block`,
|
|
68
|
+
loc: rt.loc,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
for (const event of rt.events) {
|
|
72
|
+
if (!SUPPORTED_REALTIME_EVENTS.includes(event)) {
|
|
73
|
+
this.diagnostics.push({
|
|
74
|
+
code: 'E105_UNKNOWN_REALTIME_EVENT',
|
|
75
|
+
message: `Unknown realtime event '${event}' in '${rt.name}'`,
|
|
76
|
+
hint: `Supported events: ${SUPPORTED_REALTIME_EVENTS.join(', ')}`,
|
|
77
|
+
loc: rt.loc,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
checkAuthMethods(ast) {
|
|
84
|
+
if (!ast.auth)
|
|
85
|
+
return;
|
|
86
|
+
if (ast.auth.methods.length === 0) {
|
|
87
|
+
this.diagnostics.push({
|
|
88
|
+
code: 'E106_EMPTY_AUTH_METHODS',
|
|
89
|
+
message: `auth '${ast.auth.name}' has no methods`,
|
|
90
|
+
hint: `Add at least one method: methods: [usernameAndPassword]`,
|
|
91
|
+
loc: ast.auth.loc,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
for (const method of ast.auth.methods) {
|
|
95
|
+
if (!SUPPORTED_AUTH_METHODS.includes(method)) {
|
|
96
|
+
this.diagnostics.push({
|
|
97
|
+
code: 'E107_UNKNOWN_AUTH_METHOD',
|
|
98
|
+
message: `Unknown auth method '${method}'`,
|
|
99
|
+
hint: `Supported methods: ${SUPPORTED_AUTH_METHODS.join(', ')}`,
|
|
100
|
+
loc: ast.auth.loc,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
checkQueryActionEntities(ast) {
|
|
106
|
+
const crudEntities = new Set(ast.cruds.map((c) => c.entity));
|
|
107
|
+
for (const query of ast.queries) {
|
|
108
|
+
for (const entity of query.entities) {
|
|
109
|
+
if (!crudEntities.has(entity)) {
|
|
110
|
+
this.diagnostics.push({
|
|
111
|
+
code: 'E108_UNKNOWN_ENTITY_REF',
|
|
112
|
+
message: `Query '${query.name}' references unknown entity '${entity}'`,
|
|
113
|
+
hint: `Add a crud block for entity '${entity}', or remove it from the entities list`,
|
|
114
|
+
loc: query.loc,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
for (const action of ast.actions) {
|
|
120
|
+
for (const entity of action.entities) {
|
|
121
|
+
if (!crudEntities.has(entity)) {
|
|
122
|
+
this.diagnostics.push({
|
|
123
|
+
code: 'E109_UNKNOWN_ENTITY_REF',
|
|
124
|
+
message: `Action '${action.name}' references unknown entity '${entity}'`,
|
|
125
|
+
hint: `Add a crud block for entity '${entity}', or remove it from the entities list`,
|
|
126
|
+
loc: action.loc,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
checkJobExecutors(ast) {
|
|
133
|
+
for (const job of ast.jobs) {
|
|
134
|
+
if (job.executor !== 'PgBoss') {
|
|
135
|
+
this.diagnostics.push({
|
|
136
|
+
code: 'E110_UNKNOWN_JOB_EXECUTOR',
|
|
137
|
+
message: `Unknown job executor '${job.executor}' in '${job.name}'`,
|
|
138
|
+
hint: 'Supported executors: PgBoss',
|
|
139
|
+
loc: job.loc,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=SemanticValidator.js.map
|