@collie-lang/compiler 1.3.3 → 1.5.2
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 +3 -3
- package/dist/index.cjs +848 -1196
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -11
- package/dist/index.d.ts +11 -11
- package/dist/index.js +848 -1196
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -50,15 +50,15 @@ __export(index_exports, {
|
|
|
50
50
|
module.exports = __toCommonJS(index_exports);
|
|
51
51
|
|
|
52
52
|
// src/rewrite.ts
|
|
53
|
-
function createTemplateEnv(
|
|
54
|
-
const
|
|
55
|
-
if (
|
|
56
|
-
for (const decl of
|
|
57
|
-
|
|
53
|
+
function createTemplateEnv(inputsDecls) {
|
|
54
|
+
const inputNames = /* @__PURE__ */ new Set();
|
|
55
|
+
if (inputsDecls) {
|
|
56
|
+
for (const decl of inputsDecls) {
|
|
57
|
+
inputNames.add(decl.name);
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
return {
|
|
61
|
-
|
|
61
|
+
inputNames,
|
|
62
62
|
localsStack: []
|
|
63
63
|
};
|
|
64
64
|
}
|
|
@@ -77,12 +77,6 @@ function isLocal(env, name) {
|
|
|
77
77
|
}
|
|
78
78
|
return false;
|
|
79
79
|
}
|
|
80
|
-
function isPropAlias(env, name) {
|
|
81
|
-
if (isLocal(env, name)) {
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
return env.propAliases.has(name);
|
|
85
|
-
}
|
|
86
80
|
var IGNORED_IDENTIFIERS = /* @__PURE__ */ new Set([
|
|
87
81
|
"null",
|
|
88
82
|
"undefined",
|
|
@@ -90,10 +84,10 @@ var IGNORED_IDENTIFIERS = /* @__PURE__ */ new Set([
|
|
|
90
84
|
"false",
|
|
91
85
|
"NaN",
|
|
92
86
|
"Infinity",
|
|
93
|
-
"this"
|
|
94
|
-
"props"
|
|
87
|
+
"this"
|
|
95
88
|
]);
|
|
96
89
|
var RESERVED_KEYWORDS = /* @__PURE__ */ new Set([
|
|
90
|
+
"async",
|
|
97
91
|
"await",
|
|
98
92
|
"break",
|
|
99
93
|
"case",
|
|
@@ -135,185 +129,33 @@ var RESERVED_KEYWORDS = /* @__PURE__ */ new Set([
|
|
|
135
129
|
"yield"
|
|
136
130
|
]);
|
|
137
131
|
function rewriteExpression(expression, env) {
|
|
138
|
-
|
|
139
|
-
let state = "code";
|
|
140
|
-
let output = "";
|
|
132
|
+
const tokens = tokenizeExpression(expression);
|
|
141
133
|
const usedBare = /* @__PURE__ */ new Set();
|
|
142
|
-
const usedPropsDot = /* @__PURE__ */ new Set();
|
|
143
134
|
const callSitesBare = /* @__PURE__ */ new Set();
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
const ch = expression[i];
|
|
148
|
-
if (state === "code") {
|
|
149
|
-
if (ch === "'" || ch === '"') {
|
|
150
|
-
state = ch === "'" ? "single" : "double";
|
|
151
|
-
output += ch;
|
|
152
|
-
i++;
|
|
153
|
-
continue;
|
|
154
|
-
}
|
|
155
|
-
if (ch === "`") {
|
|
156
|
-
state = "template";
|
|
157
|
-
output += ch;
|
|
158
|
-
i++;
|
|
159
|
-
continue;
|
|
160
|
-
}
|
|
161
|
-
if (ch === "/" && expression[i + 1] === "/") {
|
|
162
|
-
state = "line";
|
|
163
|
-
output += ch;
|
|
164
|
-
i++;
|
|
165
|
-
continue;
|
|
166
|
-
}
|
|
167
|
-
if (ch === "/" && expression[i + 1] === "*") {
|
|
168
|
-
state = "block";
|
|
169
|
-
output += ch;
|
|
170
|
-
i++;
|
|
171
|
-
continue;
|
|
172
|
-
}
|
|
173
|
-
if (isIdentifierStart(ch)) {
|
|
174
|
-
const start = i;
|
|
175
|
-
i++;
|
|
176
|
-
while (i < expression.length && isIdentifierPart(expression[i])) {
|
|
177
|
-
i++;
|
|
178
|
-
}
|
|
179
|
-
const name = expression.slice(start, i);
|
|
180
|
-
const prevNonSpace = findPreviousNonSpace(expression, start - 1);
|
|
181
|
-
const nextNonSpace = findNextNonSpace(expression, i);
|
|
182
|
-
const isMemberAccess = prevNonSpace === ".";
|
|
183
|
-
const isObjectKey = nextNonSpace === ":" && (prevNonSpace === "{" || prevNonSpace === ",");
|
|
184
|
-
const isCall = nextNonSpace === "(";
|
|
185
|
-
if (prevNonSpace === "." && start >= 2) {
|
|
186
|
-
const propsStart = findPreviousIdentifierStart(expression, start - 2);
|
|
187
|
-
if (propsStart !== null) {
|
|
188
|
-
const possibleProps = expression.slice(propsStart, start - 1).trim();
|
|
189
|
-
if (possibleProps === "props") {
|
|
190
|
-
usedPropsDot.add(name);
|
|
191
|
-
if (isCall) {
|
|
192
|
-
callSitesPropsDot.add(name);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
if (isMemberAccess || isObjectKey || isLocal(env, name) || shouldIgnoreIdentifier(name)) {
|
|
198
|
-
output += name;
|
|
199
|
-
continue;
|
|
200
|
-
}
|
|
201
|
-
if (isPropAlias(env, name)) {
|
|
202
|
-
output += `props.${name}`;
|
|
203
|
-
rewrittenAliases.add(name);
|
|
204
|
-
if (isCall) {
|
|
205
|
-
callSitesBare.add(name);
|
|
206
|
-
}
|
|
207
|
-
continue;
|
|
208
|
-
}
|
|
209
|
-
usedBare.add(name);
|
|
210
|
-
if (isCall) {
|
|
211
|
-
callSitesBare.add(name);
|
|
212
|
-
}
|
|
213
|
-
output += name;
|
|
214
|
-
continue;
|
|
215
|
-
}
|
|
216
|
-
output += ch;
|
|
217
|
-
i++;
|
|
218
|
-
continue;
|
|
219
|
-
}
|
|
220
|
-
if (state === "line") {
|
|
221
|
-
output += ch;
|
|
222
|
-
if (ch === "\n") {
|
|
223
|
-
state = "code";
|
|
224
|
-
}
|
|
225
|
-
i++;
|
|
226
|
-
continue;
|
|
227
|
-
}
|
|
228
|
-
if (state === "block") {
|
|
229
|
-
output += ch;
|
|
230
|
-
if (ch === "*" && expression[i + 1] === "/") {
|
|
231
|
-
output += "/";
|
|
232
|
-
i += 2;
|
|
233
|
-
state = "code";
|
|
234
|
-
continue;
|
|
235
|
-
}
|
|
236
|
-
i++;
|
|
237
|
-
continue;
|
|
238
|
-
}
|
|
239
|
-
if (state === "single") {
|
|
240
|
-
output += ch;
|
|
241
|
-
if (ch === "\\") {
|
|
242
|
-
if (i + 1 < expression.length) {
|
|
243
|
-
output += expression[i + 1];
|
|
244
|
-
i += 2;
|
|
245
|
-
continue;
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
if (ch === "'") {
|
|
249
|
-
state = "code";
|
|
250
|
-
}
|
|
251
|
-
i++;
|
|
252
|
-
continue;
|
|
253
|
-
}
|
|
254
|
-
if (state === "double") {
|
|
255
|
-
output += ch;
|
|
256
|
-
if (ch === "\\") {
|
|
257
|
-
if (i + 1 < expression.length) {
|
|
258
|
-
output += expression[i + 1];
|
|
259
|
-
i += 2;
|
|
260
|
-
continue;
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
if (ch === '"') {
|
|
264
|
-
state = "code";
|
|
265
|
-
}
|
|
266
|
-
i++;
|
|
267
|
-
continue;
|
|
268
|
-
}
|
|
269
|
-
if (state === "template") {
|
|
270
|
-
output += ch;
|
|
271
|
-
if (ch === "\\") {
|
|
272
|
-
if (i + 1 < expression.length) {
|
|
273
|
-
output += expression[i + 1];
|
|
274
|
-
i += 2;
|
|
275
|
-
continue;
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
if (ch === "`") {
|
|
279
|
-
state = "code";
|
|
280
|
-
}
|
|
281
|
-
i++;
|
|
282
|
-
continue;
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
return { code: output, usedBare, usedPropsDot, callSitesBare, callSitesPropsDot, rewrittenAliases };
|
|
135
|
+
const localScopes = [/* @__PURE__ */ new Set()];
|
|
136
|
+
analyzeTokens(tokens, 0, tokens.length, env, localScopes, usedBare, callSitesBare, false);
|
|
137
|
+
return { code: expression, usedBare, callSitesBare };
|
|
286
138
|
}
|
|
287
139
|
function rewriteJsxExpression(expression, env) {
|
|
288
|
-
let output = "";
|
|
289
140
|
let i = 0;
|
|
290
141
|
const usedBare = /* @__PURE__ */ new Set();
|
|
291
|
-
const usedPropsDot = /* @__PURE__ */ new Set();
|
|
292
142
|
const callSitesBare = /* @__PURE__ */ new Set();
|
|
293
|
-
const callSitesPropsDot = /* @__PURE__ */ new Set();
|
|
294
|
-
const rewrittenAliases = /* @__PURE__ */ new Set();
|
|
295
143
|
while (i < expression.length) {
|
|
296
144
|
const ch = expression[i];
|
|
297
145
|
if (ch === "{") {
|
|
298
146
|
const braceResult = readBalancedBraces(expression, i + 1);
|
|
299
147
|
if (!braceResult) {
|
|
300
|
-
output += expression.slice(i);
|
|
301
148
|
break;
|
|
302
149
|
}
|
|
303
150
|
const result = rewriteExpression(braceResult.content, env);
|
|
304
|
-
output += `{${result.code}}`;
|
|
305
151
|
for (const name of result.usedBare) usedBare.add(name);
|
|
306
|
-
for (const name of result.usedPropsDot) usedPropsDot.add(name);
|
|
307
152
|
for (const name of result.callSitesBare) callSitesBare.add(name);
|
|
308
|
-
for (const name of result.callSitesPropsDot) callSitesPropsDot.add(name);
|
|
309
|
-
for (const name of result.rewrittenAliases) rewrittenAliases.add(name);
|
|
310
153
|
i = braceResult.endIndex + 1;
|
|
311
154
|
continue;
|
|
312
155
|
}
|
|
313
|
-
output += ch;
|
|
314
156
|
i++;
|
|
315
157
|
}
|
|
316
|
-
return { code:
|
|
158
|
+
return { code: expression, usedBare, callSitesBare };
|
|
317
159
|
}
|
|
318
160
|
function readBalancedBraces(source, startIndex) {
|
|
319
161
|
let i = startIndex;
|
|
@@ -405,38 +247,6 @@ function readBalancedBraces(source, startIndex) {
|
|
|
405
247
|
}
|
|
406
248
|
return null;
|
|
407
249
|
}
|
|
408
|
-
function findPreviousNonSpace(text, index) {
|
|
409
|
-
for (let i = index; i >= 0; i--) {
|
|
410
|
-
const ch = text[i];
|
|
411
|
-
if (!/\s/.test(ch)) {
|
|
412
|
-
return ch;
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
return null;
|
|
416
|
-
}
|
|
417
|
-
function findNextNonSpace(text, index) {
|
|
418
|
-
for (let i = index; i < text.length; i++) {
|
|
419
|
-
const ch = text[i];
|
|
420
|
-
if (!/\s/.test(ch)) {
|
|
421
|
-
return ch;
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
return null;
|
|
425
|
-
}
|
|
426
|
-
function findPreviousIdentifierStart(text, index) {
|
|
427
|
-
let i = index;
|
|
428
|
-
while (i >= 0 && /\s/.test(text[i])) {
|
|
429
|
-
i--;
|
|
430
|
-
}
|
|
431
|
-
if (i < 0) return null;
|
|
432
|
-
if (!isIdentifierPart(text[i])) {
|
|
433
|
-
return null;
|
|
434
|
-
}
|
|
435
|
-
while (i > 0 && isIdentifierPart(text[i - 1])) {
|
|
436
|
-
i--;
|
|
437
|
-
}
|
|
438
|
-
return i;
|
|
439
|
-
}
|
|
440
250
|
function isIdentifierStart(ch) {
|
|
441
251
|
return /[A-Za-z_$]/.test(ch);
|
|
442
252
|
}
|
|
@@ -446,96 +256,592 @@ function isIdentifierPart(ch) {
|
|
|
446
256
|
function shouldIgnoreIdentifier(name) {
|
|
447
257
|
return IGNORED_IDENTIFIERS.has(name) || RESERVED_KEYWORDS.has(name);
|
|
448
258
|
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
259
|
+
function tokenizeExpression(expression) {
|
|
260
|
+
const tokens = [];
|
|
261
|
+
let i = 0;
|
|
262
|
+
while (i < expression.length) {
|
|
263
|
+
const ch = expression[i];
|
|
264
|
+
if (/\s/.test(ch)) {
|
|
265
|
+
i++;
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
if (ch === "/" && expression[i + 1] === "/") {
|
|
269
|
+
i += 2;
|
|
270
|
+
while (i < expression.length && expression[i] !== "\n") {
|
|
271
|
+
i++;
|
|
272
|
+
}
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
if (ch === "/" && expression[i + 1] === "*") {
|
|
276
|
+
i += 2;
|
|
277
|
+
while (i < expression.length && !(expression[i] === "*" && expression[i + 1] === "/")) {
|
|
278
|
+
i++;
|
|
279
|
+
}
|
|
280
|
+
i += 2;
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
if (ch === "'" || ch === '"') {
|
|
284
|
+
i = skipStringLiteral(expression, i, ch);
|
|
285
|
+
tokens.push({ type: "literal", value: "string" });
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
if (ch === "`") {
|
|
289
|
+
i = skipTemplateLiteral(expression, i);
|
|
290
|
+
tokens.push({ type: "literal", value: "template" });
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
if (isIdentifierStart(ch)) {
|
|
294
|
+
const start = i;
|
|
295
|
+
i++;
|
|
296
|
+
while (i < expression.length && isIdentifierPart(expression[i])) {
|
|
297
|
+
i++;
|
|
298
|
+
}
|
|
299
|
+
tokens.push({ type: "identifier", value: expression.slice(start, i) });
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
if (/[0-9]/.test(ch)) {
|
|
303
|
+
const start = i;
|
|
304
|
+
i++;
|
|
305
|
+
while (i < expression.length && /[0-9._]/.test(expression[i])) {
|
|
306
|
+
i++;
|
|
307
|
+
}
|
|
308
|
+
tokens.push({ type: "literal", value: expression.slice(start, i) });
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
if (expression.startsWith("...", i)) {
|
|
312
|
+
tokens.push({ type: "punctuator", value: "..." });
|
|
313
|
+
i += 3;
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
if (expression.startsWith("=>", i)) {
|
|
317
|
+
tokens.push({ type: "punctuator", value: "=>" });
|
|
318
|
+
i += 2;
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
if (expression.startsWith("?.", i)) {
|
|
322
|
+
tokens.push({ type: "punctuator", value: "?." });
|
|
323
|
+
i += 2;
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
if (expression.startsWith("??", i)) {
|
|
327
|
+
tokens.push({ type: "punctuator", value: "??" });
|
|
328
|
+
i += 2;
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
tokens.push({ type: "punctuator", value: ch });
|
|
332
|
+
i++;
|
|
462
333
|
}
|
|
463
|
-
|
|
464
|
-
parts.push(functionLines.join("\n"));
|
|
465
|
-
return parts.join("\n\n");
|
|
334
|
+
return tokens;
|
|
466
335
|
}
|
|
467
|
-
function
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
prelude.push(`import React from "react";`);
|
|
336
|
+
function skipStringLiteral(source, start, quote) {
|
|
337
|
+
let i = start + 1;
|
|
338
|
+
while (i < source.length) {
|
|
339
|
+
const ch = source[i];
|
|
340
|
+
if (ch === "\\") {
|
|
341
|
+
i += 2;
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
if (ch === quote) {
|
|
345
|
+
return i + 1;
|
|
346
|
+
}
|
|
347
|
+
i++;
|
|
480
348
|
}
|
|
481
|
-
|
|
482
|
-
return { prelude, propsType, propsDestructure, jsx, isTsx };
|
|
349
|
+
return source.length;
|
|
483
350
|
}
|
|
484
|
-
function
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
351
|
+
function skipTemplateLiteral(source, start) {
|
|
352
|
+
let i = start + 1;
|
|
353
|
+
while (i < source.length) {
|
|
354
|
+
const ch = source[i];
|
|
355
|
+
if (ch === "\\") {
|
|
356
|
+
i += 2;
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
if (ch === "`") {
|
|
360
|
+
return i + 1;
|
|
361
|
+
}
|
|
362
|
+
i++;
|
|
488
363
|
}
|
|
489
|
-
|
|
490
|
-
|
|
364
|
+
return source.length;
|
|
365
|
+
}
|
|
366
|
+
function analyzeTokens(tokens, start, end, env, scopes, usedBare, callSitesBare, allowStatements) {
|
|
367
|
+
let i = start;
|
|
368
|
+
while (i < end) {
|
|
369
|
+
const token = tokens[i];
|
|
370
|
+
if (token.type === "identifier") {
|
|
371
|
+
if (token.value === "function") {
|
|
372
|
+
const fnResult = parseFunctionExpression(tokens, i, end, env, scopes, usedBare, callSitesBare);
|
|
373
|
+
if (fnResult > i) {
|
|
374
|
+
i = fnResult;
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
if (allowStatements && (token.value === "const" || token.value === "let" || token.value === "var")) {
|
|
379
|
+
const declResult = parseVariableDeclaration(tokens, i, end, env, scopes, usedBare, callSitesBare);
|
|
380
|
+
if (declResult > i) {
|
|
381
|
+
i = declResult;
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
if (allowStatements && token.value === "catch") {
|
|
386
|
+
const catchResult = parseCatchClause(tokens, i, end, env, scopes, usedBare, callSitesBare);
|
|
387
|
+
if (catchResult > i) {
|
|
388
|
+
i = catchResult;
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
const arrowResult = parseArrowFunction(tokens, i, end, env, scopes, usedBare, callSitesBare);
|
|
393
|
+
if (arrowResult > i) {
|
|
394
|
+
i = arrowResult;
|
|
395
|
+
continue;
|
|
396
|
+
}
|
|
397
|
+
if (shouldIgnoreIdentifier(token.value)) {
|
|
398
|
+
i++;
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
if (isShadowed(env, scopes, token.value)) {
|
|
402
|
+
i++;
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
if (isMemberAccess(tokens, i) || isObjectKey(tokens, i)) {
|
|
406
|
+
i++;
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
usedBare.add(token.value);
|
|
410
|
+
if (isCallSite(tokens, i)) {
|
|
411
|
+
callSitesBare.add(token.value);
|
|
412
|
+
}
|
|
413
|
+
i++;
|
|
414
|
+
continue;
|
|
415
|
+
}
|
|
416
|
+
if (token.type === "punctuator" && token.value === "(") {
|
|
417
|
+
const arrowResult = parseArrowFunction(tokens, i, end, env, scopes, usedBare, callSitesBare);
|
|
418
|
+
if (arrowResult > i) {
|
|
419
|
+
i = arrowResult;
|
|
420
|
+
continue;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
i++;
|
|
491
424
|
}
|
|
492
|
-
return env;
|
|
493
425
|
}
|
|
494
|
-
function
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
if (root.children.length === 0) {
|
|
499
|
-
return false;
|
|
426
|
+
function parseArrowFunction(tokens, index, end, env, scopes, usedBare, callSitesBare) {
|
|
427
|
+
const token = tokens[index];
|
|
428
|
+
if (!token) {
|
|
429
|
+
return index;
|
|
500
430
|
}
|
|
501
|
-
if (
|
|
502
|
-
|
|
431
|
+
if (token.type === "identifier") {
|
|
432
|
+
const next = tokens[index + 1];
|
|
433
|
+
if (next && next.value === "=>") {
|
|
434
|
+
const params = /* @__PURE__ */ new Set([token.value]);
|
|
435
|
+
return analyzeArrowBody(tokens, index + 2, end, params, env, scopes, usedBare, callSitesBare);
|
|
436
|
+
}
|
|
503
437
|
}
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
438
|
+
if (token.type === "punctuator" && token.value === "(") {
|
|
439
|
+
const closeIndex = findMatchingToken(tokens, index, "(", ")");
|
|
440
|
+
if (closeIndex !== -1) {
|
|
441
|
+
const afterClose = tokens[closeIndex + 1];
|
|
442
|
+
if (afterClose && afterClose.value === "=>") {
|
|
443
|
+
const params = /* @__PURE__ */ new Set();
|
|
444
|
+
collectBindingNamesFromList(tokens, index + 1, closeIndex, params);
|
|
445
|
+
return analyzeArrowBody(tokens, closeIndex + 2, end, params, env, scopes, usedBare, callSitesBare);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
509
448
|
}
|
|
510
|
-
|
|
511
|
-
|
|
449
|
+
return index;
|
|
450
|
+
}
|
|
451
|
+
function analyzeArrowBody(tokens, start, end, params, env, scopes, usedBare, callSitesBare) {
|
|
452
|
+
const bodyToken = tokens[start];
|
|
453
|
+
if (!bodyToken) {
|
|
454
|
+
return start;
|
|
455
|
+
}
|
|
456
|
+
const scope = new Set(params);
|
|
457
|
+
scopes.push(scope);
|
|
458
|
+
if (bodyToken.type === "punctuator" && bodyToken.value === "{") {
|
|
459
|
+
const closeIndex = findMatchingToken(tokens, start, "{", "}");
|
|
460
|
+
const bodyEnd2 = closeIndex === -1 ? end : closeIndex;
|
|
461
|
+
analyzeTokens(tokens, start + 1, bodyEnd2, env, scopes, usedBare, callSitesBare, true);
|
|
462
|
+
scopes.pop();
|
|
463
|
+
return closeIndex === -1 ? end : closeIndex + 1;
|
|
464
|
+
}
|
|
465
|
+
const bodyEnd = findExpressionEnd(tokens, start, end, EXPRESSION_TERMINATORS);
|
|
466
|
+
analyzeTokens(tokens, start, bodyEnd, env, scopes, usedBare, callSitesBare, false);
|
|
467
|
+
scopes.pop();
|
|
468
|
+
return bodyEnd;
|
|
469
|
+
}
|
|
470
|
+
function parseFunctionExpression(tokens, index, end, env, scopes, usedBare, callSitesBare) {
|
|
471
|
+
let i = index + 1;
|
|
472
|
+
const nameToken = tokens[i];
|
|
473
|
+
let fnName;
|
|
474
|
+
if (nameToken && nameToken.type === "identifier" && tokens[i + 1]?.value === "(") {
|
|
475
|
+
fnName = nameToken.value;
|
|
476
|
+
i++;
|
|
512
477
|
}
|
|
513
|
-
if (
|
|
514
|
-
return
|
|
478
|
+
if (!tokens[i] || tokens[i].value !== "(") {
|
|
479
|
+
return index;
|
|
515
480
|
}
|
|
516
|
-
|
|
517
|
-
|
|
481
|
+
const closeIndex = findMatchingToken(tokens, i, "(", ")");
|
|
482
|
+
if (closeIndex === -1) {
|
|
483
|
+
return index;
|
|
484
|
+
}
|
|
485
|
+
const params = /* @__PURE__ */ new Set();
|
|
486
|
+
collectBindingNamesFromList(tokens, i + 1, closeIndex, params);
|
|
487
|
+
if (fnName) {
|
|
488
|
+
params.add(fnName);
|
|
489
|
+
}
|
|
490
|
+
const bodyStart = closeIndex + 1;
|
|
491
|
+
if (!tokens[bodyStart] || tokens[bodyStart].value !== "{") {
|
|
492
|
+
return index;
|
|
493
|
+
}
|
|
494
|
+
const closeBody = findMatchingToken(tokens, bodyStart, "{", "}");
|
|
495
|
+
const bodyEnd = closeBody === -1 ? end : closeBody;
|
|
496
|
+
scopes.push(params);
|
|
497
|
+
analyzeTokens(tokens, bodyStart + 1, bodyEnd, env, scopes, usedBare, callSitesBare, true);
|
|
498
|
+
scopes.pop();
|
|
499
|
+
return closeBody === -1 ? end : closeBody + 1;
|
|
500
|
+
}
|
|
501
|
+
function parseCatchClause(tokens, index, end, env, scopes, usedBare, callSitesBare) {
|
|
502
|
+
const next = tokens[index + 1];
|
|
503
|
+
if (!next || next.value !== "(") {
|
|
504
|
+
return index;
|
|
505
|
+
}
|
|
506
|
+
const closeIndex = findMatchingToken(tokens, index + 1, "(", ")");
|
|
507
|
+
if (closeIndex === -1) {
|
|
508
|
+
return index;
|
|
509
|
+
}
|
|
510
|
+
const params = /* @__PURE__ */ new Set();
|
|
511
|
+
collectBindingNamesFromList(tokens, index + 2, closeIndex, params);
|
|
512
|
+
const bodyStart = closeIndex + 1;
|
|
513
|
+
if (!tokens[bodyStart] || tokens[bodyStart].value !== "{") {
|
|
514
|
+
return index;
|
|
515
|
+
}
|
|
516
|
+
const closeBody = findMatchingToken(tokens, bodyStart, "{", "}");
|
|
517
|
+
const bodyEnd = closeBody === -1 ? end : closeBody;
|
|
518
|
+
scopes.push(params);
|
|
519
|
+
analyzeTokens(tokens, bodyStart + 1, bodyEnd, env, scopes, usedBare, callSitesBare, true);
|
|
520
|
+
scopes.pop();
|
|
521
|
+
return closeBody === -1 ? end : closeBody + 1;
|
|
522
|
+
}
|
|
523
|
+
function parseVariableDeclaration(tokens, index, end, env, scopes, usedBare, callSitesBare) {
|
|
524
|
+
let i = index + 1;
|
|
525
|
+
const scope = scopes[scopes.length - 1];
|
|
526
|
+
while (i < end) {
|
|
527
|
+
const names = /* @__PURE__ */ new Set();
|
|
528
|
+
const nextIndex = parseBindingPattern(tokens, i, end, names);
|
|
529
|
+
if (nextIndex === i) {
|
|
530
|
+
return index;
|
|
531
|
+
}
|
|
532
|
+
i = nextIndex;
|
|
533
|
+
if (tokens[i] && tokens[i].value === "=") {
|
|
534
|
+
const initStart = i + 1;
|
|
535
|
+
const initEnd = findExpressionEnd(tokens, initStart, end, DECLARATION_TERMINATORS);
|
|
536
|
+
analyzeTokens(tokens, initStart, initEnd, env, scopes, usedBare, callSitesBare, false);
|
|
537
|
+
i = initEnd;
|
|
538
|
+
}
|
|
539
|
+
for (const name of names) {
|
|
540
|
+
scope.add(name);
|
|
541
|
+
}
|
|
542
|
+
if (tokens[i] && tokens[i].value === ",") {
|
|
543
|
+
i++;
|
|
544
|
+
continue;
|
|
545
|
+
}
|
|
546
|
+
break;
|
|
518
547
|
}
|
|
519
|
-
return
|
|
548
|
+
return i;
|
|
520
549
|
}
|
|
521
|
-
function
|
|
522
|
-
|
|
523
|
-
|
|
550
|
+
function parseBindingPattern(tokens, start, end, names) {
|
|
551
|
+
const token = tokens[start];
|
|
552
|
+
if (!token) {
|
|
553
|
+
return start;
|
|
524
554
|
}
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
if (node.type === "Text") {
|
|
529
|
-
return emitText(node, env);
|
|
555
|
+
if (token.type === "identifier") {
|
|
556
|
+
names.add(token.value);
|
|
557
|
+
return start + 1;
|
|
530
558
|
}
|
|
531
|
-
if (
|
|
532
|
-
return
|
|
559
|
+
if (token.value === "{") {
|
|
560
|
+
return parseObjectPattern(tokens, start + 1, end, names);
|
|
533
561
|
}
|
|
534
|
-
if (
|
|
535
|
-
return
|
|
562
|
+
if (token.value === "[") {
|
|
563
|
+
return parseArrayPattern(tokens, start + 1, end, names);
|
|
536
564
|
}
|
|
537
|
-
|
|
538
|
-
|
|
565
|
+
return start + 1;
|
|
566
|
+
}
|
|
567
|
+
function parseObjectPattern(tokens, start, end, names) {
|
|
568
|
+
let i = start;
|
|
569
|
+
while (i < end) {
|
|
570
|
+
const token = tokens[i];
|
|
571
|
+
if (!token) {
|
|
572
|
+
return i;
|
|
573
|
+
}
|
|
574
|
+
if (token.value === "}") {
|
|
575
|
+
return i + 1;
|
|
576
|
+
}
|
|
577
|
+
if (token.value === ",") {
|
|
578
|
+
i++;
|
|
579
|
+
continue;
|
|
580
|
+
}
|
|
581
|
+
if (token.value === "...") {
|
|
582
|
+
i++;
|
|
583
|
+
i = parseBindingPattern(tokens, i, end, names);
|
|
584
|
+
i = skipDefaultValue(tokens, i, end, OBJECT_PATTERN_TERMINATORS);
|
|
585
|
+
continue;
|
|
586
|
+
}
|
|
587
|
+
if (token.value === "[") {
|
|
588
|
+
const closeIndex = findMatchingToken(tokens, i, "[", "]");
|
|
589
|
+
i = closeIndex === -1 ? end : closeIndex + 1;
|
|
590
|
+
if (tokens[i] && tokens[i].value === ":") {
|
|
591
|
+
i++;
|
|
592
|
+
i = parseBindingPattern(tokens, i, end, names);
|
|
593
|
+
i = skipDefaultValue(tokens, i, end, OBJECT_PATTERN_TERMINATORS);
|
|
594
|
+
}
|
|
595
|
+
continue;
|
|
596
|
+
}
|
|
597
|
+
if (token.type === "identifier" || token.type === "literal") {
|
|
598
|
+
const key = token.value;
|
|
599
|
+
i++;
|
|
600
|
+
if (tokens[i] && tokens[i].value === ":") {
|
|
601
|
+
i++;
|
|
602
|
+
i = parseBindingPattern(tokens, i, end, names);
|
|
603
|
+
} else if (token.type === "identifier") {
|
|
604
|
+
names.add(key);
|
|
605
|
+
}
|
|
606
|
+
i = skipDefaultValue(tokens, i, end, OBJECT_PATTERN_TERMINATORS);
|
|
607
|
+
continue;
|
|
608
|
+
}
|
|
609
|
+
i++;
|
|
610
|
+
}
|
|
611
|
+
return i;
|
|
612
|
+
}
|
|
613
|
+
function parseArrayPattern(tokens, start, end, names) {
|
|
614
|
+
let i = start;
|
|
615
|
+
while (i < end) {
|
|
616
|
+
const token = tokens[i];
|
|
617
|
+
if (!token) {
|
|
618
|
+
return i;
|
|
619
|
+
}
|
|
620
|
+
if (token.value === "]") {
|
|
621
|
+
return i + 1;
|
|
622
|
+
}
|
|
623
|
+
if (token.value === ",") {
|
|
624
|
+
i++;
|
|
625
|
+
continue;
|
|
626
|
+
}
|
|
627
|
+
if (token.value === "...") {
|
|
628
|
+
i++;
|
|
629
|
+
i = parseBindingPattern(tokens, i, end, names);
|
|
630
|
+
i = skipDefaultValue(tokens, i, end, ARRAY_PATTERN_TERMINATORS);
|
|
631
|
+
continue;
|
|
632
|
+
}
|
|
633
|
+
i = parseBindingPattern(tokens, i, end, names);
|
|
634
|
+
i = skipDefaultValue(tokens, i, end, ARRAY_PATTERN_TERMINATORS);
|
|
635
|
+
if (tokens[i] && tokens[i].value === ",") {
|
|
636
|
+
i++;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
return i;
|
|
640
|
+
}
|
|
641
|
+
function collectBindingNamesFromList(tokens, start, end, names) {
|
|
642
|
+
let i = start;
|
|
643
|
+
while (i < end) {
|
|
644
|
+
if (tokens[i] && tokens[i].value === ",") {
|
|
645
|
+
i++;
|
|
646
|
+
continue;
|
|
647
|
+
}
|
|
648
|
+
const nextIndex = parseBindingPattern(tokens, i, end, names);
|
|
649
|
+
if (nextIndex === i) {
|
|
650
|
+
i++;
|
|
651
|
+
continue;
|
|
652
|
+
}
|
|
653
|
+
i = skipParameterSuffix(tokens, nextIndex, end);
|
|
654
|
+
if (tokens[i] && tokens[i].value === ",") {
|
|
655
|
+
i++;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
function skipParameterSuffix(tokens, start, end) {
|
|
660
|
+
if (!tokens[start]) {
|
|
661
|
+
return start;
|
|
662
|
+
}
|
|
663
|
+
if (tokens[start].value === "=" || tokens[start].value === ":") {
|
|
664
|
+
return findExpressionEnd(tokens, start + 1, end, PARAMETER_TERMINATORS);
|
|
665
|
+
}
|
|
666
|
+
return start;
|
|
667
|
+
}
|
|
668
|
+
function skipDefaultValue(tokens, start, end, terminators) {
|
|
669
|
+
if (!tokens[start] || tokens[start].value !== "=") {
|
|
670
|
+
return start;
|
|
671
|
+
}
|
|
672
|
+
return findExpressionEnd(tokens, start + 1, end, terminators);
|
|
673
|
+
}
|
|
674
|
+
function findMatchingToken(tokens, start, open, close) {
|
|
675
|
+
let depth = 0;
|
|
676
|
+
for (let i = start; i < tokens.length; i++) {
|
|
677
|
+
const value = tokens[i].value;
|
|
678
|
+
if (value === open) {
|
|
679
|
+
depth++;
|
|
680
|
+
} else if (value === close) {
|
|
681
|
+
depth--;
|
|
682
|
+
if (depth === 0) {
|
|
683
|
+
return i;
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
return -1;
|
|
688
|
+
}
|
|
689
|
+
function findExpressionEnd(tokens, start, end, terminators) {
|
|
690
|
+
let depthParen = 0;
|
|
691
|
+
let depthBracket = 0;
|
|
692
|
+
let depthBrace = 0;
|
|
693
|
+
for (let i = start; i < end; i++) {
|
|
694
|
+
const value = tokens[i].value;
|
|
695
|
+
if (value === "(") {
|
|
696
|
+
depthParen++;
|
|
697
|
+
} else if (value === ")") {
|
|
698
|
+
if (depthParen === 0 && terminators.has(value)) {
|
|
699
|
+
return i;
|
|
700
|
+
}
|
|
701
|
+
depthParen = Math.max(0, depthParen - 1);
|
|
702
|
+
} else if (value === "[") {
|
|
703
|
+
depthBracket++;
|
|
704
|
+
} else if (value === "]") {
|
|
705
|
+
if (depthBracket === 0 && terminators.has(value)) {
|
|
706
|
+
return i;
|
|
707
|
+
}
|
|
708
|
+
depthBracket = Math.max(0, depthBracket - 1);
|
|
709
|
+
} else if (value === "{") {
|
|
710
|
+
depthBrace++;
|
|
711
|
+
} else if (value === "}") {
|
|
712
|
+
if (depthBrace === 0 && terminators.has(value)) {
|
|
713
|
+
return i;
|
|
714
|
+
}
|
|
715
|
+
depthBrace = Math.max(0, depthBrace - 1);
|
|
716
|
+
}
|
|
717
|
+
if (depthParen === 0 && depthBracket === 0 && depthBrace === 0 && terminators.has(value)) {
|
|
718
|
+
return i;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
return end;
|
|
722
|
+
}
|
|
723
|
+
function isMemberAccess(tokens, index) {
|
|
724
|
+
const prev = tokens[index - 1];
|
|
725
|
+
return prev?.value === "." || prev?.value === "?.";
|
|
726
|
+
}
|
|
727
|
+
function isObjectKey(tokens, index) {
|
|
728
|
+
const next = tokens[index + 1];
|
|
729
|
+
if (!next || next.value !== ":") {
|
|
730
|
+
return false;
|
|
731
|
+
}
|
|
732
|
+
const prev = tokens[index - 1];
|
|
733
|
+
return prev?.value === "{" || prev?.value === ",";
|
|
734
|
+
}
|
|
735
|
+
function isCallSite(tokens, index) {
|
|
736
|
+
const next = tokens[index + 1];
|
|
737
|
+
return next?.value === "(";
|
|
738
|
+
}
|
|
739
|
+
function isShadowed(env, scopes, name) {
|
|
740
|
+
if (isLocal(env, name)) {
|
|
741
|
+
return true;
|
|
742
|
+
}
|
|
743
|
+
for (let i = scopes.length - 1; i >= 0; i--) {
|
|
744
|
+
if (scopes[i].has(name)) {
|
|
745
|
+
return true;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
return false;
|
|
749
|
+
}
|
|
750
|
+
var PARAMETER_TERMINATORS = /* @__PURE__ */ new Set([","]);
|
|
751
|
+
var OBJECT_PATTERN_TERMINATORS = /* @__PURE__ */ new Set([",", "}"]);
|
|
752
|
+
var ARRAY_PATTERN_TERMINATORS = /* @__PURE__ */ new Set([",", "]"]);
|
|
753
|
+
var EXPRESSION_TERMINATORS = /* @__PURE__ */ new Set([",", ")", "]", "}", ";"]);
|
|
754
|
+
var DECLARATION_TERMINATORS = /* @__PURE__ */ new Set([",", ")", "]", "}", ";"]);
|
|
755
|
+
|
|
756
|
+
// src/codegen.ts
|
|
757
|
+
function generateRenderModule(root, options) {
|
|
758
|
+
const { prelude, inputsType, inputsPrelude, jsx, isTsx } = buildModuleParts(root, options);
|
|
759
|
+
const parts = [...prelude, inputsType];
|
|
760
|
+
if (!isTsx) {
|
|
761
|
+
parts.push(`/** @param {any} __inputs */`);
|
|
762
|
+
}
|
|
763
|
+
const functionLines = [
|
|
764
|
+
isTsx ? "export function render(__inputs: any) {" : "export function render(__inputs) {"
|
|
765
|
+
];
|
|
766
|
+
if (inputsPrelude) {
|
|
767
|
+
functionLines.push(` ${inputsPrelude}`);
|
|
768
|
+
}
|
|
769
|
+
functionLines.push(` return ${jsx};`, `}`);
|
|
770
|
+
parts.push(functionLines.join("\n"));
|
|
771
|
+
return parts.join("\n\n");
|
|
772
|
+
}
|
|
773
|
+
function buildModuleParts(root, options) {
|
|
774
|
+
const { jsxRuntime, flavor } = options;
|
|
775
|
+
const isTsx = flavor === "tsx";
|
|
776
|
+
const aliasEnv = buildClassAliasEnvironment(root.classAliases);
|
|
777
|
+
const env = createTemplateEnv(root.inputsDecls);
|
|
778
|
+
const jsx = renderRootChildren(root.children, aliasEnv, env);
|
|
779
|
+
const inputsPrelude = emitInputsPrelude(root.inputsDecls);
|
|
780
|
+
const prelude = [];
|
|
781
|
+
if (root.clientComponent) {
|
|
782
|
+
prelude.push(`"use client";`);
|
|
783
|
+
}
|
|
784
|
+
if (jsxRuntime === "classic" && templateUsesJsx(root)) {
|
|
785
|
+
prelude.push(`import React from "react";`);
|
|
786
|
+
}
|
|
787
|
+
const inputsType = emitInputsType(root.inputs, flavor);
|
|
788
|
+
return { prelude, inputsType, inputsPrelude, jsx, isTsx };
|
|
789
|
+
}
|
|
790
|
+
function buildClassAliasEnvironment(decl) {
|
|
791
|
+
const env = /* @__PURE__ */ new Map();
|
|
792
|
+
if (!decl) {
|
|
793
|
+
return env;
|
|
794
|
+
}
|
|
795
|
+
for (const alias of decl.aliases) {
|
|
796
|
+
env.set(alias.name, alias.classes);
|
|
797
|
+
}
|
|
798
|
+
return env;
|
|
799
|
+
}
|
|
800
|
+
function renderRootChildren(children, aliasEnv, env) {
|
|
801
|
+
return emitNodesExpression(children, aliasEnv, env);
|
|
802
|
+
}
|
|
803
|
+
function templateUsesJsx(root) {
|
|
804
|
+
if (root.children.length === 0) {
|
|
805
|
+
return false;
|
|
806
|
+
}
|
|
807
|
+
if (root.children.length > 1) {
|
|
808
|
+
return true;
|
|
809
|
+
}
|
|
810
|
+
return nodeUsesJsx(root.children[0]);
|
|
811
|
+
}
|
|
812
|
+
function nodeUsesJsx(node) {
|
|
813
|
+
if (node.type === "Element" || node.type === "Text" || node.type === "Component") {
|
|
814
|
+
return true;
|
|
815
|
+
}
|
|
816
|
+
if (node.type === "Expression" || node.type === "JSXPassthrough") {
|
|
817
|
+
return false;
|
|
818
|
+
}
|
|
819
|
+
if (node.type === "Conditional") {
|
|
820
|
+
return node.branches.some((branch) => branchUsesJsx(branch));
|
|
821
|
+
}
|
|
822
|
+
if (node.type === "For") {
|
|
823
|
+
return node.body.some((child) => nodeUsesJsx(child));
|
|
824
|
+
}
|
|
825
|
+
return false;
|
|
826
|
+
}
|
|
827
|
+
function branchUsesJsx(branch) {
|
|
828
|
+
if (!branch.body.length) {
|
|
829
|
+
return false;
|
|
830
|
+
}
|
|
831
|
+
return branch.body.some((child) => nodeUsesJsx(child));
|
|
832
|
+
}
|
|
833
|
+
function emitNodeInJsx(node, aliasEnv, env) {
|
|
834
|
+
if (node.type === "Text") {
|
|
835
|
+
return emitText(node, env);
|
|
836
|
+
}
|
|
837
|
+
if (node.type === "Expression") {
|
|
838
|
+
return `{${emitExpressionValue(node.value, env)}}`;
|
|
839
|
+
}
|
|
840
|
+
if (node.type === "JSXPassthrough") {
|
|
841
|
+
return `{${emitJsxExpression(node.expression, env)}}`;
|
|
842
|
+
}
|
|
843
|
+
if (node.type === "Conditional") {
|
|
844
|
+
return `{${emitConditionalExpression(node, aliasEnv, env)}}`;
|
|
539
845
|
}
|
|
540
846
|
if (node.type === "For") {
|
|
541
847
|
return `{${emitForExpression(node, aliasEnv, env)}}`;
|
|
@@ -559,8 +865,8 @@ function emitElement(node, aliasEnv, env) {
|
|
|
559
865
|
}
|
|
560
866
|
function emitComponent(node, aliasEnv, env) {
|
|
561
867
|
const attrs = emitAttributes(node.attributes, aliasEnv, env);
|
|
562
|
-
const
|
|
563
|
-
const allAttrs = `${attrs}${
|
|
868
|
+
const slotBindings = emitSlotBindings(node, aliasEnv, env);
|
|
869
|
+
const allAttrs = `${attrs}${slotBindings}`;
|
|
564
870
|
const children = emitChildrenWithSpacing(node.children, aliasEnv, env);
|
|
565
871
|
if (children.length > 0) {
|
|
566
872
|
return `<${node.name}${allAttrs}>${children}</${node.name}>`;
|
|
@@ -598,7 +904,7 @@ function emitAttributes(attributes, aliasEnv, env) {
|
|
|
598
904
|
return ` ${attr.name}=${emitAttributeValue(attr.value, env)}`;
|
|
599
905
|
}).join("");
|
|
600
906
|
}
|
|
601
|
-
function
|
|
907
|
+
function emitSlotBindings(node, aliasEnv, env) {
|
|
602
908
|
if (!node.slots || node.slots.length === 0) {
|
|
603
909
|
return "";
|
|
604
910
|
}
|
|
@@ -729,41 +1035,41 @@ function emitSingleNodeExpression(node, aliasEnv, env) {
|
|
|
729
1035
|
}
|
|
730
1036
|
return emitNodeInJsx(node, aliasEnv, env);
|
|
731
1037
|
}
|
|
732
|
-
function
|
|
1038
|
+
function emitInputsType(inputs, flavor) {
|
|
733
1039
|
if (flavor === "tsx") {
|
|
734
|
-
return
|
|
1040
|
+
return emitTsInputsType(inputs);
|
|
735
1041
|
}
|
|
736
|
-
return
|
|
1042
|
+
return emitJsDocInputsType(inputs);
|
|
737
1043
|
}
|
|
738
|
-
function
|
|
739
|
-
if (!
|
|
740
|
-
return "/** @typedef {any}
|
|
1044
|
+
function emitJsDocInputsType(inputs) {
|
|
1045
|
+
if (!inputs) {
|
|
1046
|
+
return "/** @typedef {any} Inputs */";
|
|
741
1047
|
}
|
|
742
|
-
if (!
|
|
743
|
-
return "/** @typedef {{}}
|
|
1048
|
+
if (!inputs.fields.length) {
|
|
1049
|
+
return "/** @typedef {{}} Inputs */";
|
|
744
1050
|
}
|
|
745
|
-
const fields =
|
|
1051
|
+
const fields = inputs.fields.map((field) => {
|
|
746
1052
|
const optional = field.optional ? "?" : "";
|
|
747
1053
|
return `${field.name}${optional}: ${field.typeText}`;
|
|
748
1054
|
}).join("; ");
|
|
749
|
-
return `/** @typedef {{ ${fields} }}
|
|
1055
|
+
return `/** @typedef {{ ${fields} }} Inputs */`;
|
|
750
1056
|
}
|
|
751
|
-
function
|
|
752
|
-
if (!
|
|
753
|
-
return "export type
|
|
1057
|
+
function emitTsInputsType(inputs) {
|
|
1058
|
+
if (!inputs || inputs.fields.length === 0) {
|
|
1059
|
+
return "export type Inputs = Record<string, never>;";
|
|
754
1060
|
}
|
|
755
|
-
const lines =
|
|
1061
|
+
const lines = inputs.fields.map((field) => {
|
|
756
1062
|
const optional = field.optional ? "?" : "";
|
|
757
1063
|
return ` ${field.name}${optional}: ${field.typeText};`;
|
|
758
1064
|
});
|
|
759
|
-
return ["export interface
|
|
1065
|
+
return ["export interface Inputs {", ...lines, "}"].join("\n");
|
|
760
1066
|
}
|
|
761
|
-
function
|
|
762
|
-
if (!
|
|
1067
|
+
function emitInputsPrelude(inputsDecls) {
|
|
1068
|
+
if (!inputsDecls || inputsDecls.length === 0) {
|
|
763
1069
|
return null;
|
|
764
1070
|
}
|
|
765
|
-
const names =
|
|
766
|
-
return `const { ${names.join(", ")} } =
|
|
1071
|
+
const names = inputsDecls.map((decl) => decl.name);
|
|
1072
|
+
return `const { ${names.join(", ")} } = __inputs ?? {};`;
|
|
767
1073
|
}
|
|
768
1074
|
function escapeText(value) {
|
|
769
1075
|
return value.replace(/[&<>{}]/g, (char) => {
|
|
@@ -925,836 +1231,196 @@ function unescapeChar(char, quote) {
|
|
|
925
1231
|
default:
|
|
926
1232
|
if (char === quote) {
|
|
927
1233
|
return quote;
|
|
928
|
-
}
|
|
929
|
-
return char;
|
|
930
|
-
}
|
|
931
|
-
}
|
|
932
|
-
function buildClassAliasEnvironment2(decl) {
|
|
933
|
-
const env = /* @__PURE__ */ new Map();
|
|
934
|
-
if (!decl) {
|
|
935
|
-
return env;
|
|
936
|
-
}
|
|
937
|
-
for (const alias of decl.aliases) {
|
|
938
|
-
env.set(alias.name, alias.classes);
|
|
939
|
-
}
|
|
940
|
-
return env;
|
|
941
|
-
}
|
|
942
|
-
function expandClasses2(classes, aliasEnv) {
|
|
943
|
-
const result = [];
|
|
944
|
-
for (const cls of classes) {
|
|
945
|
-
const match = cls.match(/^\$([A-Za-z_][A-Za-z0-9_]*)$/);
|
|
946
|
-
if (!match) {
|
|
947
|
-
result.push(cls);
|
|
948
|
-
continue;
|
|
949
|
-
}
|
|
950
|
-
const aliasClasses = aliasEnv.get(match[1]);
|
|
951
|
-
if (!aliasClasses) {
|
|
952
|
-
continue;
|
|
953
|
-
}
|
|
954
|
-
result.push(...aliasClasses);
|
|
955
|
-
}
|
|
956
|
-
return result;
|
|
957
|
-
}
|
|
958
|
-
function escapeStaticText(value) {
|
|
959
|
-
return value.replace(/[&<>{}]/g, (char) => {
|
|
960
|
-
switch (char) {
|
|
961
|
-
case "&":
|
|
962
|
-
return "&";
|
|
963
|
-
case "<":
|
|
964
|
-
return "<";
|
|
965
|
-
case ">":
|
|
966
|
-
return ">";
|
|
967
|
-
case "{":
|
|
968
|
-
return "{";
|
|
969
|
-
case "}":
|
|
970
|
-
return "}";
|
|
971
|
-
default:
|
|
972
|
-
return char;
|
|
973
|
-
}
|
|
974
|
-
});
|
|
975
|
-
}
|
|
976
|
-
function escapeAttributeValue(value) {
|
|
977
|
-
return value.replace(/["&<>]/g, (char) => {
|
|
978
|
-
switch (char) {
|
|
979
|
-
case "&":
|
|
980
|
-
return "&";
|
|
981
|
-
case "<":
|
|
982
|
-
return "<";
|
|
983
|
-
case ">":
|
|
984
|
-
return ">";
|
|
985
|
-
case '"':
|
|
986
|
-
return """;
|
|
987
|
-
default:
|
|
988
|
-
return char;
|
|
989
|
-
}
|
|
990
|
-
});
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
// src/diagnostics.ts
|
|
994
|
-
function createSpan(line, col, length, lineOffset) {
|
|
995
|
-
const startOffset = lineOffset + col - 1;
|
|
996
|
-
return {
|
|
997
|
-
start: { line, col, offset: startOffset },
|
|
998
|
-
end: { line, col: col + length, offset: startOffset + length }
|
|
999
|
-
};
|
|
1000
|
-
}
|
|
1001
|
-
|
|
1002
|
-
// src/dialect.ts
|
|
1003
|
-
function enforceDialect(root, config) {
|
|
1004
|
-
const diagnostics = [];
|
|
1005
|
-
if (root.idToken) {
|
|
1006
|
-
diagnostics.push(
|
|
1007
|
-
...evaluateToken(
|
|
1008
|
-
{ kind: "id", token: root.idToken, span: root.idTokenSpan },
|
|
1009
|
-
config.tokens.id
|
|
1010
|
-
)
|
|
1011
|
-
);
|
|
1012
|
-
}
|
|
1013
|
-
walkNodes(root.children, (occurrence) => {
|
|
1014
|
-
const rule = config.tokens[occurrence.kind];
|
|
1015
|
-
diagnostics.push(...evaluateToken(occurrence, rule));
|
|
1016
|
-
});
|
|
1017
|
-
return diagnostics;
|
|
1018
|
-
}
|
|
1019
|
-
function walkNodes(nodes, onToken) {
|
|
1020
|
-
for (const node of nodes) {
|
|
1021
|
-
if (node.type === "For") {
|
|
1022
|
-
onFor(node, onToken);
|
|
1023
|
-
walkNodes(node.body, onToken);
|
|
1024
|
-
continue;
|
|
1025
|
-
}
|
|
1026
|
-
if (node.type === "Conditional") {
|
|
1027
|
-
onConditional(node, onToken);
|
|
1028
|
-
continue;
|
|
1029
|
-
}
|
|
1030
|
-
if (node.type === "Element" || node.type === "Component") {
|
|
1031
|
-
walkNodes(node.children, onToken);
|
|
1032
|
-
if (node.type === "Component" && node.slots) {
|
|
1033
|
-
for (const slot of node.slots) {
|
|
1034
|
-
walkNodes(slot.children, onToken);
|
|
1035
|
-
}
|
|
1036
|
-
}
|
|
1037
|
-
continue;
|
|
1038
|
-
}
|
|
1039
|
-
}
|
|
1040
|
-
}
|
|
1041
|
-
function onFor(node, onToken) {
|
|
1042
|
-
if (!node.token) {
|
|
1043
|
-
return;
|
|
1044
|
-
}
|
|
1045
|
-
onToken({ kind: "for", token: node.token, span: node.tokenSpan });
|
|
1046
|
-
}
|
|
1047
|
-
function onConditional(node, onToken) {
|
|
1048
|
-
for (const branch of node.branches) {
|
|
1049
|
-
onBranch(branch, onToken);
|
|
1050
|
-
walkNodes(branch.body, onToken);
|
|
1051
|
-
}
|
|
1052
|
-
}
|
|
1053
|
-
function onBranch(branch, onToken) {
|
|
1054
|
-
if (!branch.token || !branch.kind) {
|
|
1055
|
-
return;
|
|
1056
|
-
}
|
|
1057
|
-
onToken({ kind: branch.kind, token: branch.token, span: branch.tokenSpan });
|
|
1058
|
-
}
|
|
1059
|
-
function evaluateToken(occurrence, rule) {
|
|
1060
|
-
const diagnostics = [];
|
|
1061
|
-
const used = occurrence.token;
|
|
1062
|
-
const preferred = rule.preferred;
|
|
1063
|
-
const isAllowed = rule.allow.includes(used);
|
|
1064
|
-
if (!isAllowed) {
|
|
1065
|
-
const severity = levelToSeverity(rule.onDisallowed);
|
|
1066
|
-
if (severity) {
|
|
1067
|
-
diagnostics.push(
|
|
1068
|
-
createDialectDiagnostic(
|
|
1069
|
-
"dialect.token.disallowed",
|
|
1070
|
-
severity,
|
|
1071
|
-
used,
|
|
1072
|
-
preferred,
|
|
1073
|
-
occurrence.span,
|
|
1074
|
-
`Token "${used}" is not allowed for ${occurrence.kind}. Preferred: "${preferred}".`
|
|
1075
|
-
)
|
|
1076
|
-
);
|
|
1077
|
-
}
|
|
1078
|
-
return diagnostics;
|
|
1079
|
-
}
|
|
1080
|
-
if (used !== preferred) {
|
|
1081
|
-
const severity = levelToSeverity(rule.onDisallowed);
|
|
1082
|
-
if (severity) {
|
|
1083
|
-
diagnostics.push(
|
|
1084
|
-
createDialectDiagnostic(
|
|
1085
|
-
"dialect.token.nonPreferred",
|
|
1086
|
-
severity,
|
|
1087
|
-
used,
|
|
1088
|
-
preferred,
|
|
1089
|
-
occurrence.span,
|
|
1090
|
-
`Token "${used}" is allowed but not preferred for ${occurrence.kind}. Preferred: "${preferred}".`
|
|
1091
|
-
)
|
|
1092
|
-
);
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
return diagnostics;
|
|
1096
|
-
}
|
|
1097
|
-
function createDialectDiagnostic(code, severity, used, preferred, span, message) {
|
|
1098
|
-
const fix = span ? {
|
|
1099
|
-
range: span,
|
|
1100
|
-
replacementText: preferred
|
|
1101
|
-
} : void 0;
|
|
1102
|
-
return {
|
|
1103
|
-
severity,
|
|
1104
|
-
code,
|
|
1105
|
-
message: message.replace(/\\s+/g, " "),
|
|
1106
|
-
span,
|
|
1107
|
-
fix
|
|
1108
|
-
};
|
|
1109
|
-
}
|
|
1110
|
-
function levelToSeverity(level) {
|
|
1111
|
-
if (level === "off") {
|
|
1112
|
-
return null;
|
|
1113
|
-
}
|
|
1114
|
-
if (level === "error") {
|
|
1115
|
-
return "error";
|
|
1116
|
-
}
|
|
1117
|
-
return "warning";
|
|
1118
|
-
}
|
|
1119
|
-
|
|
1120
|
-
// src/props.ts
|
|
1121
|
-
var IGNORED_IDENTIFIERS2 = /* @__PURE__ */ new Set([
|
|
1122
|
-
"null",
|
|
1123
|
-
"undefined",
|
|
1124
|
-
"true",
|
|
1125
|
-
"false",
|
|
1126
|
-
"NaN",
|
|
1127
|
-
"Infinity",
|
|
1128
|
-
"this",
|
|
1129
|
-
"props"
|
|
1130
|
-
]);
|
|
1131
|
-
var RESERVED_KEYWORDS2 = /* @__PURE__ */ new Set([
|
|
1132
|
-
"await",
|
|
1133
|
-
"break",
|
|
1134
|
-
"case",
|
|
1135
|
-
"catch",
|
|
1136
|
-
"class",
|
|
1137
|
-
"const",
|
|
1138
|
-
"continue",
|
|
1139
|
-
"debugger",
|
|
1140
|
-
"default",
|
|
1141
|
-
"delete",
|
|
1142
|
-
"do",
|
|
1143
|
-
"else",
|
|
1144
|
-
"enum",
|
|
1145
|
-
"export",
|
|
1146
|
-
"extends",
|
|
1147
|
-
"false",
|
|
1148
|
-
"finally",
|
|
1149
|
-
"for",
|
|
1150
|
-
"function",
|
|
1151
|
-
"if",
|
|
1152
|
-
"import",
|
|
1153
|
-
"in",
|
|
1154
|
-
"instanceof",
|
|
1155
|
-
"let",
|
|
1156
|
-
"new",
|
|
1157
|
-
"null",
|
|
1158
|
-
"return",
|
|
1159
|
-
"super",
|
|
1160
|
-
"switch",
|
|
1161
|
-
"this",
|
|
1162
|
-
"throw",
|
|
1163
|
-
"true",
|
|
1164
|
-
"try",
|
|
1165
|
-
"typeof",
|
|
1166
|
-
"var",
|
|
1167
|
-
"void",
|
|
1168
|
-
"while",
|
|
1169
|
-
"with",
|
|
1170
|
-
"yield"
|
|
1171
|
-
]);
|
|
1172
|
-
function enforceProps(root, propsConfig) {
|
|
1173
|
-
const diagnostics = [];
|
|
1174
|
-
const declaredProps = /* @__PURE__ */ new Map();
|
|
1175
|
-
const usedLocal = /* @__PURE__ */ new Map();
|
|
1176
|
-
const usedNamespace = /* @__PURE__ */ new Map();
|
|
1177
|
-
const usedAny = /* @__PURE__ */ new Set();
|
|
1178
|
-
const missingReported = /* @__PURE__ */ new Set();
|
|
1179
|
-
const localStyleReported = /* @__PURE__ */ new Set();
|
|
1180
|
-
const namespaceStyleReported = /* @__PURE__ */ new Set();
|
|
1181
|
-
if (root.props?.fields) {
|
|
1182
|
-
for (const field of root.props.fields) {
|
|
1183
|
-
declaredProps.set(field.name, field);
|
|
1184
|
-
}
|
|
1185
|
-
}
|
|
1186
|
-
const preferStyle = propsConfig.preferAccessStyle;
|
|
1187
|
-
const flagLocalStyle = !propsConfig.allowDeclaredLocals || preferStyle === "namespace";
|
|
1188
|
-
const flagNamespaceStyle = !propsConfig.allowPropsNamespace || preferStyle === "locals";
|
|
1189
|
-
const walkNodes2 = (nodes, locals) => {
|
|
1190
|
-
for (const node of nodes) {
|
|
1191
|
-
if (node.type === "Conditional") {
|
|
1192
|
-
handleConditional(node, locals);
|
|
1193
|
-
continue;
|
|
1194
|
-
}
|
|
1195
|
-
if (node.type === "For") {
|
|
1196
|
-
handleFor(node, locals);
|
|
1197
|
-
continue;
|
|
1198
|
-
}
|
|
1199
|
-
if (node.type === "Expression") {
|
|
1200
|
-
handleExpression(node.value, node.span, locals);
|
|
1201
|
-
continue;
|
|
1202
|
-
}
|
|
1203
|
-
if (node.type === "JSXPassthrough") {
|
|
1204
|
-
handleExpression(node.expression, node.span, locals);
|
|
1205
|
-
continue;
|
|
1206
|
-
}
|
|
1207
|
-
if (node.type === "Text") {
|
|
1208
|
-
handleText(node.parts, locals);
|
|
1209
|
-
continue;
|
|
1210
|
-
}
|
|
1211
|
-
if (node.type === "Element") {
|
|
1212
|
-
handleElement(node, locals);
|
|
1213
|
-
continue;
|
|
1214
|
-
}
|
|
1215
|
-
if (node.type === "Component") {
|
|
1216
|
-
handleComponent(node, locals);
|
|
1217
|
-
continue;
|
|
1218
|
-
}
|
|
1219
|
-
}
|
|
1220
|
-
};
|
|
1221
|
-
const handleConditional = (node, locals) => {
|
|
1222
|
-
for (const branch of node.branches) {
|
|
1223
|
-
if (branch.test) {
|
|
1224
|
-
handleExpression(branch.test, branch.testSpan, locals);
|
|
1225
|
-
}
|
|
1226
|
-
walkNodes2(branch.body, locals);
|
|
1227
|
-
}
|
|
1228
|
-
};
|
|
1229
|
-
const handleFor = (node, locals) => {
|
|
1230
|
-
handleExpression(node.arrayExpr, node.arrayExprSpan, locals);
|
|
1231
|
-
const nextLocals = new Set(locals);
|
|
1232
|
-
nextLocals.add(node.itemName);
|
|
1233
|
-
walkNodes2(node.body, nextLocals);
|
|
1234
|
-
};
|
|
1235
|
-
const handleElement = (node, locals) => {
|
|
1236
|
-
if (node.guard) {
|
|
1237
|
-
handleExpression(node.guard, node.guardSpan, locals);
|
|
1238
|
-
}
|
|
1239
|
-
handleAttributes(node.attributes, locals);
|
|
1240
|
-
walkNodes2(node.children, locals);
|
|
1241
|
-
};
|
|
1242
|
-
const handleComponent = (node, locals) => {
|
|
1243
|
-
if (node.guard) {
|
|
1244
|
-
handleExpression(node.guard, node.guardSpan, locals);
|
|
1245
|
-
}
|
|
1246
|
-
handleAttributes(node.attributes, locals);
|
|
1247
|
-
if (node.slots) {
|
|
1248
|
-
for (const slot of node.slots) {
|
|
1249
|
-
walkNodes2(slot.children, locals);
|
|
1250
|
-
}
|
|
1251
|
-
}
|
|
1252
|
-
walkNodes2(node.children, locals);
|
|
1253
|
-
};
|
|
1254
|
-
const handleText = (parts, locals) => {
|
|
1255
|
-
for (const part of parts) {
|
|
1256
|
-
if (part.type === "expr") {
|
|
1257
|
-
handleExpression(part.value, part.span, locals);
|
|
1258
|
-
}
|
|
1259
|
-
}
|
|
1260
|
-
};
|
|
1261
|
-
const handleAttributes = (attributes, locals) => {
|
|
1262
|
-
for (const attr of attributes) {
|
|
1263
|
-
if (!attr.value) continue;
|
|
1264
|
-
const trimmed = attr.value.trim();
|
|
1265
|
-
if (!trimmed || trimmed.startsWith("'") || trimmed.startsWith('"')) {
|
|
1266
|
-
continue;
|
|
1267
|
-
}
|
|
1268
|
-
handleExpression(trimmed, void 0, locals);
|
|
1269
|
-
}
|
|
1270
|
-
};
|
|
1271
|
-
const handleExpression = (expression, span, locals) => {
|
|
1272
|
-
const occurrences = scanExpression(expression);
|
|
1273
|
-
for (const occurrence of occurrences) {
|
|
1274
|
-
const name = occurrence.name;
|
|
1275
|
-
if (occurrence.kind === "local" && locals.has(name)) {
|
|
1276
|
-
continue;
|
|
1277
|
-
}
|
|
1278
|
-
if (shouldIgnoreIdentifier2(name)) {
|
|
1279
|
-
continue;
|
|
1280
|
-
}
|
|
1281
|
-
const usageSpan = span ? offsetSpan(span, occurrence.index, occurrence.length) : void 0;
|
|
1282
|
-
if (occurrence.kind === "namespace") {
|
|
1283
|
-
recordUsage(usedNamespace, name, usageSpan);
|
|
1284
|
-
usedAny.add(name);
|
|
1285
|
-
if (propsConfig.requireDeclarationForLocals && !declaredProps.has(name) && !missingReported.has(name)) {
|
|
1286
|
-
const severity = levelToSeverity2(propsConfig.diagnostics.missingDeclaration);
|
|
1287
|
-
if (severity) {
|
|
1288
|
-
diagnostics.push(createMissingDeclarationDiagnostic(name, severity, usageSpan));
|
|
1289
|
-
missingReported.add(name);
|
|
1290
|
-
}
|
|
1291
|
-
}
|
|
1292
|
-
if (flagNamespaceStyle && !namespaceStyleReported.has(name)) {
|
|
1293
|
-
const severity = levelToSeverity2(propsConfig.diagnostics.style);
|
|
1294
|
-
if (severity) {
|
|
1295
|
-
diagnostics.push(
|
|
1296
|
-
createStyleDiagnostic(
|
|
1297
|
-
name,
|
|
1298
|
-
"namespace",
|
|
1299
|
-
severity,
|
|
1300
|
-
usageSpan,
|
|
1301
|
-
propsConfig.allowPropsNamespace
|
|
1302
|
-
)
|
|
1303
|
-
);
|
|
1304
|
-
namespaceStyleReported.add(name);
|
|
1305
|
-
}
|
|
1306
|
-
}
|
|
1307
|
-
continue;
|
|
1308
|
-
}
|
|
1309
|
-
recordUsage(usedLocal, name, usageSpan);
|
|
1310
|
-
usedAny.add(name);
|
|
1311
|
-
if (propsConfig.requireDeclarationForLocals && !declaredProps.has(name) && !missingReported.has(name)) {
|
|
1312
|
-
const severity = levelToSeverity2(propsConfig.diagnostics.missingDeclaration);
|
|
1313
|
-
if (severity) {
|
|
1314
|
-
diagnostics.push(createMissingDeclarationDiagnostic(name, severity, usageSpan));
|
|
1315
|
-
missingReported.add(name);
|
|
1316
|
-
}
|
|
1317
|
-
}
|
|
1318
|
-
if (flagLocalStyle && !localStyleReported.has(name)) {
|
|
1319
|
-
const severity = levelToSeverity2(propsConfig.diagnostics.style);
|
|
1320
|
-
if (severity) {
|
|
1321
|
-
diagnostics.push(
|
|
1322
|
-
createStyleDiagnostic(name, "local", severity, usageSpan, propsConfig.allowDeclaredLocals)
|
|
1323
|
-
);
|
|
1324
|
-
localStyleReported.add(name);
|
|
1325
|
-
}
|
|
1326
|
-
}
|
|
1327
|
-
}
|
|
1328
|
-
};
|
|
1329
|
-
walkNodes2(root.children, /* @__PURE__ */ new Set());
|
|
1330
|
-
if (root.props?.fields) {
|
|
1331
|
-
for (const field of root.props.fields) {
|
|
1332
|
-
if (!usedAny.has(field.name)) {
|
|
1333
|
-
const severity = levelToSeverity2(propsConfig.diagnostics.unusedDeclaration);
|
|
1334
|
-
if (severity) {
|
|
1335
|
-
diagnostics.push({
|
|
1336
|
-
severity,
|
|
1337
|
-
code: "props.unusedDeclaration",
|
|
1338
|
-
message: `Prop "${field.name}" is declared but never used.`,
|
|
1339
|
-
span: field.span
|
|
1340
|
-
});
|
|
1341
|
-
}
|
|
1342
|
-
}
|
|
1343
|
-
}
|
|
1344
|
-
}
|
|
1345
|
-
if (propsConfig.requirePropsBlockWhen.enabled && !root.props && usedAny.size >= propsConfig.requirePropsBlockWhen.minUniquePropsUsed) {
|
|
1346
|
-
const severity = levelToSeverity2(propsConfig.requirePropsBlockWhen.severity);
|
|
1347
|
-
if (severity) {
|
|
1348
|
-
diagnostics.push({
|
|
1349
|
-
severity,
|
|
1350
|
-
code: "props.block.recommendedOrRequired",
|
|
1351
|
-
message: `Props block recommended: ${usedAny.size} unique prop${usedAny.size === 1 ? "" : "s"} used.`
|
|
1352
|
-
});
|
|
1353
|
-
}
|
|
1354
|
-
}
|
|
1355
|
-
return diagnostics;
|
|
1356
|
-
}
|
|
1357
|
-
function createMissingDeclarationDiagnostic(name, severity, span) {
|
|
1358
|
-
return {
|
|
1359
|
-
severity,
|
|
1360
|
-
code: "props.missingDeclaration",
|
|
1361
|
-
message: `Prop \`${name}\` is used but not declared in \`#props\`.`,
|
|
1362
|
-
span,
|
|
1363
|
-
data: {
|
|
1364
|
-
kind: "addPropDeclaration",
|
|
1365
|
-
propName: name
|
|
1366
|
-
}
|
|
1367
|
-
};
|
|
1368
|
-
}
|
|
1369
|
-
function createStyleDiagnostic(name, kind, severity, span, allowed) {
|
|
1370
|
-
if (kind === "namespace") {
|
|
1371
|
-
const message2 = allowed ? `props.${name} is allowed but not preferred; use "${name}" instead.` : `props.${name} is disabled; use "${name}" instead.`;
|
|
1372
|
-
return {
|
|
1373
|
-
severity,
|
|
1374
|
-
code: "props.style.nonPreferred",
|
|
1375
|
-
message: message2,
|
|
1376
|
-
span
|
|
1377
|
-
};
|
|
1378
|
-
}
|
|
1379
|
-
const message = allowed ? `"${name}" is allowed but not preferred; use props.${name} instead.` : `"${name}" is disabled; use props.${name} instead.`;
|
|
1380
|
-
return {
|
|
1381
|
-
severity,
|
|
1382
|
-
code: "props.style.nonPreferred",
|
|
1383
|
-
message,
|
|
1384
|
-
span
|
|
1385
|
-
};
|
|
1386
|
-
}
|
|
1387
|
-
function recordUsage(map, name, span) {
|
|
1388
|
-
const existing = map.get(name);
|
|
1389
|
-
if (existing) {
|
|
1390
|
-
existing.count += 1;
|
|
1391
|
-
return;
|
|
1392
|
-
}
|
|
1393
|
-
map.set(name, { count: 1, span });
|
|
1394
|
-
}
|
|
1395
|
-
function scanExpression(expression) {
|
|
1396
|
-
const occurrences = [];
|
|
1397
|
-
let i = 0;
|
|
1398
|
-
let state = "code";
|
|
1399
|
-
while (i < expression.length) {
|
|
1400
|
-
const ch = expression[i];
|
|
1401
|
-
if (state === "code") {
|
|
1402
|
-
if (ch === "'" || ch === '"') {
|
|
1403
|
-
state = ch === "'" ? "single" : "double";
|
|
1404
|
-
i++;
|
|
1405
|
-
continue;
|
|
1406
|
-
}
|
|
1407
|
-
if (ch === "`") {
|
|
1408
|
-
state = "template";
|
|
1409
|
-
i++;
|
|
1410
|
-
continue;
|
|
1411
|
-
}
|
|
1412
|
-
if (ch === "/" && expression[i + 1] === "/") {
|
|
1413
|
-
state = "line";
|
|
1414
|
-
i += 2;
|
|
1415
|
-
continue;
|
|
1416
|
-
}
|
|
1417
|
-
if (ch === "/" && expression[i + 1] === "*") {
|
|
1418
|
-
state = "block";
|
|
1419
|
-
i += 2;
|
|
1420
|
-
continue;
|
|
1421
|
-
}
|
|
1422
|
-
if (isIdentifierStart2(ch)) {
|
|
1423
|
-
const start = i;
|
|
1424
|
-
i++;
|
|
1425
|
-
while (i < expression.length && isIdentifierPart2(expression[i])) {
|
|
1426
|
-
i++;
|
|
1427
|
-
}
|
|
1428
|
-
const name = expression.slice(start, i);
|
|
1429
|
-
const prevNonSpace = findPreviousNonSpace2(expression, start - 1);
|
|
1430
|
-
if (name === "props" && prevNonSpace !== ".") {
|
|
1431
|
-
const namespace = readNamespaceAccess(expression, i);
|
|
1432
|
-
if (namespace) {
|
|
1433
|
-
occurrences.push({
|
|
1434
|
-
name: namespace.name,
|
|
1435
|
-
kind: "namespace",
|
|
1436
|
-
index: namespace.index,
|
|
1437
|
-
length: namespace.name.length
|
|
1438
|
-
});
|
|
1439
|
-
i = namespace.endIndex;
|
|
1440
|
-
continue;
|
|
1441
|
-
}
|
|
1442
|
-
}
|
|
1443
|
-
if (prevNonSpace !== ".") {
|
|
1444
|
-
occurrences.push({ name, kind: "local", index: start, length: name.length });
|
|
1445
|
-
}
|
|
1446
|
-
continue;
|
|
1447
|
-
}
|
|
1448
|
-
i++;
|
|
1449
|
-
continue;
|
|
1450
|
-
}
|
|
1451
|
-
if (state === "line") {
|
|
1452
|
-
if (ch === "\n") {
|
|
1453
|
-
state = "code";
|
|
1454
|
-
}
|
|
1455
|
-
i++;
|
|
1456
|
-
continue;
|
|
1457
|
-
}
|
|
1458
|
-
if (state === "block") {
|
|
1459
|
-
if (ch === "*" && expression[i + 1] === "/") {
|
|
1460
|
-
state = "code";
|
|
1461
|
-
i += 2;
|
|
1462
|
-
continue;
|
|
1463
|
-
}
|
|
1464
|
-
i++;
|
|
1465
|
-
continue;
|
|
1466
|
-
}
|
|
1467
|
-
if (state === "single") {
|
|
1468
|
-
if (ch === "\\") {
|
|
1469
|
-
i += 2;
|
|
1470
|
-
continue;
|
|
1471
|
-
}
|
|
1472
|
-
if (ch === "'") {
|
|
1473
|
-
state = "code";
|
|
1474
|
-
}
|
|
1475
|
-
i++;
|
|
1476
|
-
continue;
|
|
1477
|
-
}
|
|
1478
|
-
if (state === "double") {
|
|
1479
|
-
if (ch === "\\") {
|
|
1480
|
-
i += 2;
|
|
1481
|
-
continue;
|
|
1482
|
-
}
|
|
1483
|
-
if (ch === '"') {
|
|
1484
|
-
state = "code";
|
|
1485
|
-
}
|
|
1486
|
-
i++;
|
|
1487
|
-
continue;
|
|
1488
|
-
}
|
|
1489
|
-
if (state === "template") {
|
|
1490
|
-
if (ch === "\\") {
|
|
1491
|
-
i += 2;
|
|
1492
|
-
continue;
|
|
1493
|
-
}
|
|
1494
|
-
if (ch === "`") {
|
|
1495
|
-
state = "code";
|
|
1496
|
-
i++;
|
|
1497
|
-
continue;
|
|
1498
|
-
}
|
|
1499
|
-
i++;
|
|
1500
|
-
continue;
|
|
1501
|
-
}
|
|
1234
|
+
}
|
|
1235
|
+
return char;
|
|
1502
1236
|
}
|
|
1503
|
-
return occurrences;
|
|
1504
1237
|
}
|
|
1505
|
-
function
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
}
|
|
1510
|
-
if (expression[i] === "?") {
|
|
1511
|
-
if (expression[i + 1] !== ".") {
|
|
1512
|
-
return null;
|
|
1513
|
-
}
|
|
1514
|
-
i += 2;
|
|
1515
|
-
} else if (expression[i] === ".") {
|
|
1516
|
-
i++;
|
|
1517
|
-
} else {
|
|
1518
|
-
return null;
|
|
1519
|
-
}
|
|
1520
|
-
while (i < expression.length && /\s/.test(expression[i])) {
|
|
1521
|
-
i++;
|
|
1522
|
-
}
|
|
1523
|
-
if (!isIdentifierStart2(expression[i])) {
|
|
1524
|
-
return null;
|
|
1238
|
+
function buildClassAliasEnvironment2(decl) {
|
|
1239
|
+
const env = /* @__PURE__ */ new Map();
|
|
1240
|
+
if (!decl) {
|
|
1241
|
+
return env;
|
|
1525
1242
|
}
|
|
1526
|
-
const
|
|
1527
|
-
|
|
1528
|
-
while (i < expression.length && isIdentifierPart2(expression[i])) {
|
|
1529
|
-
i++;
|
|
1243
|
+
for (const alias of decl.aliases) {
|
|
1244
|
+
env.set(alias.name, alias.classes);
|
|
1530
1245
|
}
|
|
1531
|
-
return
|
|
1532
|
-
name: expression.slice(propStart, i),
|
|
1533
|
-
index: propStart,
|
|
1534
|
-
endIndex: i
|
|
1535
|
-
};
|
|
1246
|
+
return env;
|
|
1536
1247
|
}
|
|
1537
|
-
function
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1248
|
+
function expandClasses2(classes, aliasEnv) {
|
|
1249
|
+
const result = [];
|
|
1250
|
+
for (const cls of classes) {
|
|
1251
|
+
const match = cls.match(/^\$([A-Za-z_][A-Za-z0-9_]*)$/);
|
|
1252
|
+
if (!match) {
|
|
1253
|
+
result.push(cls);
|
|
1254
|
+
continue;
|
|
1255
|
+
}
|
|
1256
|
+
const aliasClasses = aliasEnv.get(match[1]);
|
|
1257
|
+
if (!aliasClasses) {
|
|
1258
|
+
continue;
|
|
1542
1259
|
}
|
|
1260
|
+
result.push(...aliasClasses);
|
|
1543
1261
|
}
|
|
1544
|
-
return
|
|
1545
|
-
}
|
|
1546
|
-
function isIdentifierStart2(ch) {
|
|
1547
|
-
return /[A-Za-z_$]/.test(ch);
|
|
1548
|
-
}
|
|
1549
|
-
function isIdentifierPart2(ch) {
|
|
1550
|
-
return /[A-Za-z0-9_$]/.test(ch);
|
|
1262
|
+
return result;
|
|
1551
1263
|
}
|
|
1552
|
-
function
|
|
1553
|
-
return
|
|
1264
|
+
function escapeStaticText(value) {
|
|
1265
|
+
return value.replace(/[&<>{}]/g, (char) => {
|
|
1266
|
+
switch (char) {
|
|
1267
|
+
case "&":
|
|
1268
|
+
return "&";
|
|
1269
|
+
case "<":
|
|
1270
|
+
return "<";
|
|
1271
|
+
case ">":
|
|
1272
|
+
return ">";
|
|
1273
|
+
case "{":
|
|
1274
|
+
return "{";
|
|
1275
|
+
case "}":
|
|
1276
|
+
return "}";
|
|
1277
|
+
default:
|
|
1278
|
+
return char;
|
|
1279
|
+
}
|
|
1280
|
+
});
|
|
1554
1281
|
}
|
|
1555
|
-
function
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1282
|
+
function escapeAttributeValue(value) {
|
|
1283
|
+
return value.replace(/["&<>]/g, (char) => {
|
|
1284
|
+
switch (char) {
|
|
1285
|
+
case "&":
|
|
1286
|
+
return "&";
|
|
1287
|
+
case "<":
|
|
1288
|
+
return "<";
|
|
1289
|
+
case ">":
|
|
1290
|
+
return ">";
|
|
1291
|
+
case '"':
|
|
1292
|
+
return """;
|
|
1293
|
+
default:
|
|
1294
|
+
return char;
|
|
1295
|
+
}
|
|
1296
|
+
});
|
|
1563
1297
|
}
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1298
|
+
|
|
1299
|
+
// src/diagnostics.ts
|
|
1300
|
+
function createSpan(line, col, length, lineOffset) {
|
|
1301
|
+
const startOffset = lineOffset + col - 1;
|
|
1567
1302
|
return {
|
|
1568
|
-
start: {
|
|
1569
|
-
|
|
1570
|
-
col: startCol,
|
|
1571
|
-
offset: startOffset
|
|
1572
|
-
},
|
|
1573
|
-
end: {
|
|
1574
|
-
line: base.start.line,
|
|
1575
|
-
col: startCol + length,
|
|
1576
|
-
offset: startOffset + length
|
|
1577
|
-
}
|
|
1303
|
+
start: { line, col, offset: startOffset },
|
|
1304
|
+
end: { line, col: col + length, offset: startOffset + length }
|
|
1578
1305
|
};
|
|
1579
1306
|
}
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
}
|
|
1307
|
+
|
|
1308
|
+
// src/dialect.ts
|
|
1309
|
+
function enforceDialect(root, config) {
|
|
1584
1310
|
const diagnostics = [];
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
message: `Identifier "${name}" is used without "props." but is not declared in #props. Declare "${name}" in #props or use "props.${name}".`
|
|
1593
|
-
});
|
|
1594
|
-
}
|
|
1595
|
-
}
|
|
1596
|
-
for (const [name, decl] of declaredProps) {
|
|
1597
|
-
const usedAsBare = allUsage.usedBareAliases.has(name);
|
|
1598
|
-
const usedAsProps = allUsage.usedPropsDot.has(name);
|
|
1599
|
-
if (!usedAsBare && !usedAsProps) {
|
|
1600
|
-
diagnostics.push({
|
|
1601
|
-
severity: "warning",
|
|
1602
|
-
code: "props.unusedDeclaration",
|
|
1603
|
-
message: `Prop "${name}" is declared in #props but never used in this template.`,
|
|
1604
|
-
span: decl.span
|
|
1605
|
-
});
|
|
1606
|
-
}
|
|
1607
|
-
}
|
|
1608
|
-
for (const name of allUsage.usedPropsDot) {
|
|
1609
|
-
if (declaredProps.has(name)) {
|
|
1610
|
-
diagnostics.push({
|
|
1611
|
-
severity: "warning",
|
|
1612
|
-
code: "props.style.nonPreferred",
|
|
1613
|
-
message: `"props.${name}" is unnecessary because "${name}" is declared in #props. Use "{${name}}" instead.`
|
|
1614
|
-
});
|
|
1615
|
-
}
|
|
1616
|
-
}
|
|
1617
|
-
for (const [name, decl] of declaredProps) {
|
|
1618
|
-
const isCallable = decl.kind === "callable";
|
|
1619
|
-
const usedAsCall = allUsage.callSitesBare.has(name);
|
|
1620
|
-
const usedAsValue = allUsage.usedBareAliases.has(name) && !usedAsCall;
|
|
1621
|
-
if (isCallable && usedAsValue) {
|
|
1622
|
-
diagnostics.push({
|
|
1623
|
-
severity: "warning",
|
|
1624
|
-
code: "props.style.nonPreferred",
|
|
1625
|
-
message: `"${name}" is declared as callable in #props (${name}()) but used as a value.`
|
|
1626
|
-
});
|
|
1627
|
-
} else if (!isCallable && usedAsCall) {
|
|
1628
|
-
diagnostics.push({
|
|
1629
|
-
severity: "warning",
|
|
1630
|
-
code: "props.style.nonPreferred",
|
|
1631
|
-
message: `"${name}" is declared as a value in #props but used as a function call.`
|
|
1632
|
-
});
|
|
1633
|
-
}
|
|
1311
|
+
if (root.idToken) {
|
|
1312
|
+
diagnostics.push(
|
|
1313
|
+
...evaluateToken(
|
|
1314
|
+
{ kind: "id", token: root.idToken, span: root.idTokenSpan },
|
|
1315
|
+
config.tokens.id
|
|
1316
|
+
)
|
|
1317
|
+
);
|
|
1634
1318
|
}
|
|
1319
|
+
walkNodes(root.children, (occurrence) => {
|
|
1320
|
+
const rule = config.tokens[occurrence.kind];
|
|
1321
|
+
diagnostics.push(...evaluateToken(occurrence, rule));
|
|
1322
|
+
});
|
|
1635
1323
|
return diagnostics;
|
|
1636
1324
|
}
|
|
1637
|
-
function
|
|
1638
|
-
const
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
callSitesPropsDot: /* @__PURE__ */ new Set()
|
|
1644
|
-
};
|
|
1645
|
-
const env = createTemplateEnv(root.propsDecls);
|
|
1646
|
-
function mergeResult(result) {
|
|
1647
|
-
for (const name of result.usedBare) {
|
|
1648
|
-
usage.usedBare.add(name);
|
|
1649
|
-
}
|
|
1650
|
-
for (const name of result.rewrittenAliases) {
|
|
1651
|
-
usage.usedBareAliases.add(name);
|
|
1652
|
-
}
|
|
1653
|
-
for (const name of result.usedPropsDot) {
|
|
1654
|
-
usage.usedPropsDot.add(name);
|
|
1325
|
+
function walkNodes(nodes, onToken) {
|
|
1326
|
+
for (const node of nodes) {
|
|
1327
|
+
if (node.type === "For") {
|
|
1328
|
+
onFor(node, onToken);
|
|
1329
|
+
walkNodes(node.body, onToken);
|
|
1330
|
+
continue;
|
|
1655
1331
|
}
|
|
1656
|
-
|
|
1657
|
-
|
|
1332
|
+
if (node.type === "Conditional") {
|
|
1333
|
+
onConditional(node, onToken);
|
|
1334
|
+
continue;
|
|
1658
1335
|
}
|
|
1659
|
-
|
|
1660
|
-
|
|
1336
|
+
if (node.type === "Element" || node.type === "Component") {
|
|
1337
|
+
walkNodes(node.children, onToken);
|
|
1338
|
+
if (node.type === "Component" && node.slots) {
|
|
1339
|
+
for (const slot of node.slots) {
|
|
1340
|
+
walkNodes(slot.children, onToken);
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
continue;
|
|
1661
1344
|
}
|
|
1662
1345
|
}
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1346
|
+
}
|
|
1347
|
+
function onFor(node, onToken) {
|
|
1348
|
+
if (!node.token) {
|
|
1349
|
+
return;
|
|
1667
1350
|
}
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1351
|
+
onToken({ kind: "for", token: node.token, span: node.tokenSpan });
|
|
1352
|
+
}
|
|
1353
|
+
function onConditional(node, onToken) {
|
|
1354
|
+
for (const branch of node.branches) {
|
|
1355
|
+
onBranch(branch, onToken);
|
|
1356
|
+
walkNodes(branch.body, onToken);
|
|
1672
1357
|
}
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
if (part.type === "expr") {
|
|
1678
|
-
analyzeExpression(part.value);
|
|
1679
|
-
}
|
|
1680
|
-
}
|
|
1681
|
-
break;
|
|
1682
|
-
case "Expression":
|
|
1683
|
-
analyzeExpression(node.value);
|
|
1684
|
-
break;
|
|
1685
|
-
case "JSXPassthrough":
|
|
1686
|
-
analyzeJsxExpression(node.expression);
|
|
1687
|
-
break;
|
|
1688
|
-
case "Element":
|
|
1689
|
-
if (node.guard) {
|
|
1690
|
-
analyzeExpression(node.guard);
|
|
1691
|
-
}
|
|
1692
|
-
for (const attr of node.attributes) {
|
|
1693
|
-
if (attr.value) {
|
|
1694
|
-
analyzeAttributeValue(attr.value);
|
|
1695
|
-
}
|
|
1696
|
-
}
|
|
1697
|
-
for (const child of node.children) {
|
|
1698
|
-
walkNode(child);
|
|
1699
|
-
}
|
|
1700
|
-
break;
|
|
1701
|
-
case "Component":
|
|
1702
|
-
if (node.guard) {
|
|
1703
|
-
analyzeExpression(node.guard);
|
|
1704
|
-
}
|
|
1705
|
-
for (const attr of node.attributes) {
|
|
1706
|
-
if (attr.value) {
|
|
1707
|
-
analyzeAttributeValue(attr.value);
|
|
1708
|
-
}
|
|
1709
|
-
}
|
|
1710
|
-
if (node.slots) {
|
|
1711
|
-
for (const slot of node.slots) {
|
|
1712
|
-
for (const child of slot.children) {
|
|
1713
|
-
walkNode(child);
|
|
1714
|
-
}
|
|
1715
|
-
}
|
|
1716
|
-
}
|
|
1717
|
-
for (const child of node.children) {
|
|
1718
|
-
walkNode(child);
|
|
1719
|
-
}
|
|
1720
|
-
break;
|
|
1721
|
-
case "Conditional":
|
|
1722
|
-
for (const branch of node.branches) {
|
|
1723
|
-
if (branch.test) {
|
|
1724
|
-
analyzeExpression(branch.test);
|
|
1725
|
-
}
|
|
1726
|
-
for (const child of branch.body) {
|
|
1727
|
-
walkNode(child);
|
|
1728
|
-
}
|
|
1729
|
-
}
|
|
1730
|
-
break;
|
|
1731
|
-
case "For":
|
|
1732
|
-
analyzeExpression(node.arrayExpr);
|
|
1733
|
-
for (const child of node.body) {
|
|
1734
|
-
walkNode(child);
|
|
1735
|
-
}
|
|
1736
|
-
break;
|
|
1737
|
-
}
|
|
1358
|
+
}
|
|
1359
|
+
function onBranch(branch, onToken) {
|
|
1360
|
+
if (!branch.token || !branch.kind) {
|
|
1361
|
+
return;
|
|
1738
1362
|
}
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1363
|
+
onToken({ kind: branch.kind, token: branch.token, span: branch.tokenSpan });
|
|
1364
|
+
}
|
|
1365
|
+
function evaluateToken(occurrence, rule) {
|
|
1366
|
+
const diagnostics = [];
|
|
1367
|
+
const used = occurrence.token;
|
|
1368
|
+
const preferred = rule.preferred;
|
|
1369
|
+
const isAllowed = rule.allow.includes(used);
|
|
1370
|
+
if (!isAllowed) {
|
|
1371
|
+
const severity = levelToSeverity(rule.onDisallowed);
|
|
1372
|
+
if (severity) {
|
|
1373
|
+
diagnostics.push(
|
|
1374
|
+
createDialectDiagnostic(
|
|
1375
|
+
"dialect.token.disallowed",
|
|
1376
|
+
severity,
|
|
1377
|
+
used,
|
|
1378
|
+
preferred,
|
|
1379
|
+
occurrence.span,
|
|
1380
|
+
`Token "${used}" is not allowed for ${occurrence.kind}. Preferred: "${preferred}".`
|
|
1381
|
+
)
|
|
1382
|
+
);
|
|
1749
1383
|
}
|
|
1384
|
+
return diagnostics;
|
|
1750
1385
|
}
|
|
1751
|
-
|
|
1752
|
-
|
|
1386
|
+
if (used !== preferred) {
|
|
1387
|
+
const severity = levelToSeverity(rule.onDisallowed);
|
|
1388
|
+
if (severity) {
|
|
1389
|
+
diagnostics.push(
|
|
1390
|
+
createDialectDiagnostic(
|
|
1391
|
+
"dialect.token.nonPreferred",
|
|
1392
|
+
severity,
|
|
1393
|
+
used,
|
|
1394
|
+
preferred,
|
|
1395
|
+
occurrence.span,
|
|
1396
|
+
`Token "${used}" is allowed but not preferred for ${occurrence.kind}. Preferred: "${preferred}".`
|
|
1397
|
+
)
|
|
1398
|
+
);
|
|
1399
|
+
}
|
|
1753
1400
|
}
|
|
1754
|
-
return
|
|
1401
|
+
return diagnostics;
|
|
1402
|
+
}
|
|
1403
|
+
function createDialectDiagnostic(code, severity, used, preferred, span, message) {
|
|
1404
|
+
const fix = span ? {
|
|
1405
|
+
range: span,
|
|
1406
|
+
replacementText: preferred
|
|
1407
|
+
} : void 0;
|
|
1408
|
+
return {
|
|
1409
|
+
severity,
|
|
1410
|
+
code,
|
|
1411
|
+
message: message.replace(/\\s+/g, " "),
|
|
1412
|
+
span,
|
|
1413
|
+
fix
|
|
1414
|
+
};
|
|
1755
1415
|
}
|
|
1756
|
-
function
|
|
1757
|
-
|
|
1416
|
+
function levelToSeverity(level) {
|
|
1417
|
+
if (level === "off") {
|
|
1418
|
+
return null;
|
|
1419
|
+
}
|
|
1420
|
+
if (level === "error") {
|
|
1421
|
+
return "error";
|
|
1422
|
+
}
|
|
1423
|
+
return "warning";
|
|
1758
1424
|
}
|
|
1759
1425
|
|
|
1760
1426
|
// src/parser.ts
|
|
@@ -1934,7 +1600,7 @@ function parseTemplateBlock(lines, lineOffsets, startIndex, endIndex, options) {
|
|
|
1934
1600
|
const diagnostics = [];
|
|
1935
1601
|
const root = { type: "Root", children: [] };
|
|
1936
1602
|
const stack = [{ node: root, level: -1 }];
|
|
1937
|
-
let
|
|
1603
|
+
let inputsBlockLevel = null;
|
|
1938
1604
|
let classesBlockLevel = null;
|
|
1939
1605
|
let sawTopLevelTemplateNode = false;
|
|
1940
1606
|
const conditionalChains = /* @__PURE__ */ new Map();
|
|
@@ -1976,19 +1642,19 @@ function parseTemplateBlock(lines, lineOffsets, startIndex, endIndex, options) {
|
|
|
1976
1642
|
continue;
|
|
1977
1643
|
}
|
|
1978
1644
|
let level = indent / 2;
|
|
1979
|
-
if (
|
|
1980
|
-
|
|
1645
|
+
if (inputsBlockLevel !== null && level <= inputsBlockLevel) {
|
|
1646
|
+
inputsBlockLevel = null;
|
|
1981
1647
|
}
|
|
1982
1648
|
if (classesBlockLevel !== null && level <= classesBlockLevel) {
|
|
1983
1649
|
classesBlockLevel = null;
|
|
1984
1650
|
}
|
|
1985
|
-
const
|
|
1651
|
+
const isInInputsBlock = inputsBlockLevel !== null && level > inputsBlockLevel;
|
|
1986
1652
|
const isInClassesBlock = classesBlockLevel !== null && level > classesBlockLevel;
|
|
1987
1653
|
while (stack.length > 1 && stack[stack.length - 1].level >= level) {
|
|
1988
1654
|
stack.pop();
|
|
1989
1655
|
}
|
|
1990
1656
|
const parentLevel = stack[stack.length - 1].level;
|
|
1991
|
-
if (level > parentLevel + 1 && !
|
|
1657
|
+
if (level > parentLevel + 1 && !isInInputsBlock && !isInClassesBlock) {
|
|
1992
1658
|
pushDiag(
|
|
1993
1659
|
diagnostics,
|
|
1994
1660
|
"COLLIE003",
|
|
@@ -2034,48 +1700,35 @@ function parseTemplateBlock(lines, lineOffsets, startIndex, endIndex, options) {
|
|
|
2034
1700
|
}
|
|
2035
1701
|
continue;
|
|
2036
1702
|
}
|
|
2037
|
-
if (trimmed === "
|
|
2038
|
-
pushDiag(
|
|
2039
|
-
diagnostics,
|
|
2040
|
-
"COLLIE103",
|
|
2041
|
-
"`props` must be declared using `#props`.",
|
|
2042
|
-
lineNumber,
|
|
2043
|
-
indent + 1,
|
|
2044
|
-
lineOffset,
|
|
2045
|
-
trimmed.length
|
|
2046
|
-
);
|
|
2047
|
-
if (level === 0) {
|
|
2048
|
-
propsBlockLevel = level;
|
|
2049
|
-
}
|
|
2050
|
-
continue;
|
|
2051
|
-
}
|
|
2052
|
-
if (trimmed === "#props") {
|
|
1703
|
+
if (trimmed === "#inputs") {
|
|
2053
1704
|
if (level !== 0) {
|
|
2054
1705
|
pushDiag(
|
|
2055
1706
|
diagnostics,
|
|
2056
1707
|
"COLLIE102",
|
|
2057
|
-
"#
|
|
1708
|
+
"#inputs block must be at the top level.",
|
|
2058
1709
|
lineNumber,
|
|
2059
1710
|
indent + 1,
|
|
2060
1711
|
lineOffset,
|
|
2061
1712
|
trimmed.length
|
|
2062
1713
|
);
|
|
2063
|
-
} else if (root.
|
|
1714
|
+
} else if (root.inputs) {
|
|
2064
1715
|
pushDiag(
|
|
2065
1716
|
diagnostics,
|
|
2066
1717
|
"COLLIE101",
|
|
2067
|
-
"Only one #
|
|
1718
|
+
"Only one #inputs block is allowed per #id.",
|
|
2068
1719
|
lineNumber,
|
|
2069
1720
|
indent + 1,
|
|
2070
1721
|
lineOffset,
|
|
2071
1722
|
trimmed.length
|
|
2072
1723
|
);
|
|
2073
1724
|
} else {
|
|
2074
|
-
root.
|
|
2075
|
-
root.propsDecls = [];
|
|
1725
|
+
root.inputs = { fields: [] };
|
|
2076
1726
|
}
|
|
2077
1727
|
if (level === 0) {
|
|
2078
|
-
|
|
1728
|
+
if (!root.inputsDecls) {
|
|
1729
|
+
root.inputsDecls = [];
|
|
1730
|
+
}
|
|
1731
|
+
inputsBlockLevel = level;
|
|
2079
1732
|
}
|
|
2080
1733
|
continue;
|
|
2081
1734
|
}
|
|
@@ -2115,33 +1768,33 @@ function parseTemplateBlock(lines, lineOffsets, startIndex, endIndex, options) {
|
|
|
2115
1768
|
}
|
|
2116
1769
|
continue;
|
|
2117
1770
|
}
|
|
2118
|
-
if (
|
|
2119
|
-
if (level !==
|
|
1771
|
+
if (inputsBlockLevel !== null && level > inputsBlockLevel) {
|
|
1772
|
+
if (level !== inputsBlockLevel + 1) {
|
|
2120
1773
|
pushDiag(
|
|
2121
1774
|
diagnostics,
|
|
2122
1775
|
"COLLIE102",
|
|
2123
|
-
"#
|
|
1776
|
+
"#inputs lines must be indented two spaces under the #inputs header.",
|
|
2124
1777
|
lineNumber,
|
|
2125
1778
|
indent + 1,
|
|
2126
1779
|
lineOffset
|
|
2127
1780
|
);
|
|
2128
1781
|
continue;
|
|
2129
1782
|
}
|
|
2130
|
-
const decl =
|
|
2131
|
-
if (decl && root.
|
|
2132
|
-
const existing = root.
|
|
1783
|
+
const decl = parseInputDecl(lineContent, lineNumber, indent + 1, lineOffset, diagnostics);
|
|
1784
|
+
if (decl && root.inputsDecls) {
|
|
1785
|
+
const existing = root.inputsDecls.find((d) => d.name === decl.name);
|
|
2133
1786
|
if (existing) {
|
|
2134
1787
|
pushDiag(
|
|
2135
1788
|
diagnostics,
|
|
2136
1789
|
"COLLIE106",
|
|
2137
|
-
`Duplicate
|
|
1790
|
+
`Duplicate input declaration "${decl.name}".`,
|
|
2138
1791
|
lineNumber,
|
|
2139
1792
|
indent + 1,
|
|
2140
1793
|
lineOffset,
|
|
2141
1794
|
trimmed.length
|
|
2142
1795
|
);
|
|
2143
1796
|
} else {
|
|
2144
|
-
root.
|
|
1797
|
+
root.inputsDecls.push(decl);
|
|
2145
1798
|
}
|
|
2146
1799
|
}
|
|
2147
1800
|
continue;
|
|
@@ -2554,9 +2207,7 @@ function parseTemplateBlock(lines, lineOffsets, startIndex, endIndex, options) {
|
|
|
2554
2207
|
}
|
|
2555
2208
|
if (options.dialect) {
|
|
2556
2209
|
diagnostics.push(...enforceDialect(root, options.dialect));
|
|
2557
|
-
diagnostics.push(...enforceProps(root, options.dialect.props));
|
|
2558
2210
|
}
|
|
2559
|
-
diagnostics.push(...enforcePropAliases(root));
|
|
2560
2211
|
return { root, diagnostics };
|
|
2561
2212
|
}
|
|
2562
2213
|
function buildLineOffsets(lines) {
|
|
@@ -3716,13 +3367,13 @@ function parseAndAddAttribute(attrStr, attributes, diagnostics, lineNumber, colu
|
|
|
3716
3367
|
}
|
|
3717
3368
|
}
|
|
3718
3369
|
}
|
|
3719
|
-
function
|
|
3370
|
+
function parseInputDecl(line, lineNumber, column, lineOffset, diagnostics) {
|
|
3720
3371
|
const trimmed = line.trim();
|
|
3721
3372
|
if (trimmed.includes(":") || trimmed.includes("<") || trimmed.includes("?")) {
|
|
3722
3373
|
pushDiag(
|
|
3723
3374
|
diagnostics,
|
|
3724
3375
|
"COLLIE104",
|
|
3725
|
-
'Types are not supported in #
|
|
3376
|
+
'Types are not supported in #inputs yet. Use "name" or "name()".',
|
|
3726
3377
|
lineNumber,
|
|
3727
3378
|
column,
|
|
3728
3379
|
lineOffset,
|
|
@@ -3730,32 +3381,32 @@ function parsePropDecl(line, lineNumber, column, lineOffset, diagnostics) {
|
|
|
3730
3381
|
);
|
|
3731
3382
|
return null;
|
|
3732
3383
|
}
|
|
3733
|
-
const
|
|
3734
|
-
if (
|
|
3735
|
-
const name =
|
|
3384
|
+
const valueMatch = trimmed.match(/^([A-Za-z_$][A-Za-z0-9_$]*)$/);
|
|
3385
|
+
if (valueMatch) {
|
|
3386
|
+
const name = valueMatch[1];
|
|
3736
3387
|
const nameStart = line.indexOf(name);
|
|
3737
3388
|
const nameColumn = column + nameStart;
|
|
3738
3389
|
return {
|
|
3739
3390
|
name,
|
|
3740
|
-
kind: "
|
|
3391
|
+
kind: "value",
|
|
3741
3392
|
span: createSpan(lineNumber, nameColumn, name.length, lineOffset)
|
|
3742
3393
|
};
|
|
3743
3394
|
}
|
|
3744
|
-
const
|
|
3745
|
-
if (
|
|
3746
|
-
const name =
|
|
3395
|
+
const fnMatch = trimmed.match(/^([A-Za-z_$][A-Za-z0-9_$]*)\(\)$/);
|
|
3396
|
+
if (fnMatch) {
|
|
3397
|
+
const name = fnMatch[1];
|
|
3747
3398
|
const nameStart = line.indexOf(name);
|
|
3748
3399
|
const nameColumn = column + nameStart;
|
|
3749
3400
|
return {
|
|
3750
3401
|
name,
|
|
3751
|
-
kind: "
|
|
3402
|
+
kind: "fn",
|
|
3752
3403
|
span: createSpan(lineNumber, nameColumn, name.length, lineOffset)
|
|
3753
3404
|
};
|
|
3754
3405
|
}
|
|
3755
3406
|
pushDiag(
|
|
3756
3407
|
diagnostics,
|
|
3757
3408
|
"COLLIE105",
|
|
3758
|
-
'Invalid #
|
|
3409
|
+
'Invalid #inputs declaration. Use "name" or "name()".',
|
|
3759
3410
|
lineNumber,
|
|
3760
3411
|
column,
|
|
3761
3412
|
lineOffset,
|
|
@@ -3890,8 +3541,8 @@ function serializeRoot(root, indentSize) {
|
|
|
3890
3541
|
if (root.classAliases && root.classAliases.aliases.length > 0) {
|
|
3891
3542
|
sections.push(formatClassAliases(root.classAliases, indentSize));
|
|
3892
3543
|
}
|
|
3893
|
-
if (root.
|
|
3894
|
-
sections.push(
|
|
3544
|
+
if (root.inputs && root.inputs.fields.length > 0) {
|
|
3545
|
+
sections.push(formatInputs(root.inputs, indentSize));
|
|
3895
3546
|
}
|
|
3896
3547
|
if (root.children.length > 0) {
|
|
3897
3548
|
sections.push(formatNodes(root.children, 0, indentSize));
|
|
@@ -3920,10 +3571,10 @@ function formatClassAliases(decl, indentSize) {
|
|
|
3920
3571
|
}
|
|
3921
3572
|
return lines;
|
|
3922
3573
|
}
|
|
3923
|
-
function
|
|
3574
|
+
function formatInputs(inputs, indentSize) {
|
|
3924
3575
|
const indent = indentString(1, indentSize);
|
|
3925
|
-
const lines = ["
|
|
3926
|
-
for (const field of
|
|
3576
|
+
const lines = ["#inputs"];
|
|
3577
|
+
for (const field of inputs.fields) {
|
|
3927
3578
|
const optionalFlag = field.optional ? "?" : "";
|
|
3928
3579
|
lines.push(cleanLine(`${indent}${field.name}${optionalFlag}: ${field.typeText.trim()}`));
|
|
3929
3580
|
}
|
|
@@ -4113,19 +3764,19 @@ function convertTsxToCollie(source, options = {}) {
|
|
|
4113
3764
|
);
|
|
4114
3765
|
const warnings = [];
|
|
4115
3766
|
const ctx = { sourceFile, warnings };
|
|
4116
|
-
const
|
|
4117
|
-
const component = findComponentInfo(sourceFile,
|
|
3767
|
+
const inputDeclarations = collectInputDeclarations(sourceFile);
|
|
3768
|
+
const component = findComponentInfo(sourceFile, inputDeclarations, ctx);
|
|
4118
3769
|
if (!component) {
|
|
4119
3770
|
throw new Error("Could not find a component that returns JSX in this file.");
|
|
4120
3771
|
}
|
|
4121
|
-
const
|
|
3772
|
+
const inputsLines = buildInputsBlock(component, inputDeclarations, ctx);
|
|
4122
3773
|
const templateLines = convertJsxNode(component.jsxRoot, ctx, 0);
|
|
4123
3774
|
if (!templateLines.length) {
|
|
4124
3775
|
throw new Error("Unable to convert JSX tree to Collie template.");
|
|
4125
3776
|
}
|
|
4126
3777
|
const sections = [];
|
|
4127
|
-
if (
|
|
4128
|
-
sections.push(
|
|
3778
|
+
if (inputsLines.length) {
|
|
3779
|
+
sections.push(inputsLines.join("\n"));
|
|
4129
3780
|
}
|
|
4130
3781
|
sections.push(templateLines.join("\n"));
|
|
4131
3782
|
const collie = `${sections.join("\n\n").trimEnd()}
|
|
@@ -4140,18 +3791,18 @@ function inferScriptKind(filename) {
|
|
|
4140
3791
|
if (ext === ".ts") return import_typescript.default.ScriptKind.TS;
|
|
4141
3792
|
return import_typescript.default.ScriptKind.JS;
|
|
4142
3793
|
}
|
|
4143
|
-
function
|
|
3794
|
+
function collectInputDeclarations(sourceFile) {
|
|
4144
3795
|
const map = /* @__PURE__ */ new Map();
|
|
4145
3796
|
for (const statement of sourceFile.statements) {
|
|
4146
3797
|
if (import_typescript.default.isInterfaceDeclaration(statement) && statement.name) {
|
|
4147
|
-
map.set(statement.name.text,
|
|
3798
|
+
map.set(statement.name.text, extractInputsFromMembers(statement.members, sourceFile));
|
|
4148
3799
|
} else if (import_typescript.default.isTypeAliasDeclaration(statement) && import_typescript.default.isTypeLiteralNode(statement.type)) {
|
|
4149
|
-
map.set(statement.name.text,
|
|
3800
|
+
map.set(statement.name.text, extractInputsFromMembers(statement.type.members, sourceFile));
|
|
4150
3801
|
}
|
|
4151
3802
|
}
|
|
4152
3803
|
return map;
|
|
4153
3804
|
}
|
|
4154
|
-
function
|
|
3805
|
+
function extractInputsFromMembers(members, sourceFile) {
|
|
4155
3806
|
const fields = [];
|
|
4156
3807
|
for (const member of members) {
|
|
4157
3808
|
if (!import_typescript.default.isPropertySignature(member) || member.name === void 0) {
|
|
@@ -4176,11 +3827,11 @@ function findComponentInfo(sourceFile, declarations, ctx) {
|
|
|
4176
3827
|
const jsx = findJsxReturn(statement.body);
|
|
4177
3828
|
if (jsx) {
|
|
4178
3829
|
const defaults = extractDefaultsFromParameters(statement.parameters, ctx);
|
|
4179
|
-
const
|
|
3830
|
+
const inputsInfo = resolveInputsFromParameters(statement.parameters, declarations, ctx);
|
|
4180
3831
|
return {
|
|
4181
3832
|
jsxRoot: jsx,
|
|
4182
|
-
|
|
4183
|
-
|
|
3833
|
+
inputsTypeName: inputsInfo.typeName,
|
|
3834
|
+
inlineInputs: inputsInfo.inline,
|
|
4184
3835
|
defaults
|
|
4185
3836
|
};
|
|
4186
3837
|
}
|
|
@@ -4194,20 +3845,20 @@ function findComponentInfo(sourceFile, declarations, ctx) {
|
|
|
4194
3845
|
continue;
|
|
4195
3846
|
}
|
|
4196
3847
|
const defaults = extractDefaultsFromParameters(init.parameters, ctx);
|
|
4197
|
-
const
|
|
4198
|
-
if (!
|
|
4199
|
-
const inferred =
|
|
4200
|
-
if (inferred.typeName && !
|
|
4201
|
-
|
|
3848
|
+
const inputsInfo = resolveInputsFromParameters(init.parameters, declarations, ctx);
|
|
3849
|
+
if (!inputsInfo.typeName && !inputsInfo.inline && decl.type) {
|
|
3850
|
+
const inferred = resolveInputsFromTypeAnnotation(decl.type, sourceFile, declarations);
|
|
3851
|
+
if (inferred.typeName && !inputsInfo.typeName) {
|
|
3852
|
+
inputsInfo.typeName = inferred.typeName;
|
|
4202
3853
|
}
|
|
4203
|
-
if (inferred.inline && !
|
|
4204
|
-
|
|
3854
|
+
if (inferred.inline && !inputsInfo.inline) {
|
|
3855
|
+
inputsInfo.inline = inferred.inline;
|
|
4205
3856
|
}
|
|
4206
3857
|
}
|
|
4207
3858
|
return {
|
|
4208
3859
|
jsxRoot: jsx,
|
|
4209
|
-
|
|
4210
|
-
|
|
3860
|
+
inputsTypeName: inputsInfo.typeName,
|
|
3861
|
+
inlineInputs: inputsInfo.inline,
|
|
4211
3862
|
defaults
|
|
4212
3863
|
};
|
|
4213
3864
|
}
|
|
@@ -4216,13 +3867,13 @@ function findComponentInfo(sourceFile, declarations, ctx) {
|
|
|
4216
3867
|
}
|
|
4217
3868
|
return null;
|
|
4218
3869
|
}
|
|
4219
|
-
function
|
|
3870
|
+
function resolveInputsFromParameters(parameters, declarations, ctx) {
|
|
4220
3871
|
if (!parameters.length) {
|
|
4221
3872
|
return {};
|
|
4222
3873
|
}
|
|
4223
3874
|
const param = parameters[0];
|
|
4224
3875
|
if (param.type) {
|
|
4225
|
-
const inferred =
|
|
3876
|
+
const inferred = resolveInputsFromTypeAnnotation(param.type, ctx.sourceFile, declarations);
|
|
4226
3877
|
if (inferred.inline) {
|
|
4227
3878
|
return inferred;
|
|
4228
3879
|
}
|
|
@@ -4232,7 +3883,7 @@ function resolvePropsFromParameters(parameters, declarations, ctx) {
|
|
|
4232
3883
|
}
|
|
4233
3884
|
return {};
|
|
4234
3885
|
}
|
|
4235
|
-
function
|
|
3886
|
+
function resolveInputsFromTypeAnnotation(typeNode, sourceFile, declarations) {
|
|
4236
3887
|
if (import_typescript.default.isTypeReferenceNode(typeNode)) {
|
|
4237
3888
|
const referenced = getTypeReferenceName(typeNode.typeName);
|
|
4238
3889
|
if (referenced && declarations.has(referenced)) {
|
|
@@ -4246,12 +3897,12 @@ function resolvePropsFromTypeAnnotation(typeNode, sourceFile, declarations) {
|
|
|
4246
3897
|
return { typeName: nested };
|
|
4247
3898
|
}
|
|
4248
3899
|
} else if (import_typescript.default.isTypeLiteralNode(typeArg)) {
|
|
4249
|
-
return { inline:
|
|
3900
|
+
return { inline: extractInputsFromMembers(typeArg.members, sourceFile) };
|
|
4250
3901
|
}
|
|
4251
3902
|
}
|
|
4252
3903
|
}
|
|
4253
3904
|
if (import_typescript.default.isTypeLiteralNode(typeNode)) {
|
|
4254
|
-
return { inline:
|
|
3905
|
+
return { inline: extractInputsFromMembers(typeNode.members, sourceFile) };
|
|
4255
3906
|
}
|
|
4256
3907
|
return {};
|
|
4257
3908
|
}
|
|
@@ -4307,16 +3958,16 @@ function extractDefaultsFromParameters(parameters, ctx) {
|
|
|
4307
3958
|
if (!element.initializer) {
|
|
4308
3959
|
continue;
|
|
4309
3960
|
}
|
|
4310
|
-
const
|
|
4311
|
-
if (!
|
|
3961
|
+
const inputName = getBindingElementInputName(element, ctx.sourceFile);
|
|
3962
|
+
if (!inputName) {
|
|
4312
3963
|
ctx.warnings.push("Skipping complex destructured default value.");
|
|
4313
3964
|
continue;
|
|
4314
3965
|
}
|
|
4315
|
-
defaults.set(
|
|
3966
|
+
defaults.set(inputName, element.initializer.getText(ctx.sourceFile).trim());
|
|
4316
3967
|
}
|
|
4317
3968
|
return defaults;
|
|
4318
3969
|
}
|
|
4319
|
-
function
|
|
3970
|
+
function getBindingElementInputName(element, sourceFile) {
|
|
4320
3971
|
const prop = element.propertyName;
|
|
4321
3972
|
if (prop) {
|
|
4322
3973
|
if (import_typescript.default.isIdentifier(prop) || import_typescript.default.isStringLiteral(prop) || import_typescript.default.isNumericLiteral(prop)) {
|
|
@@ -4338,24 +3989,25 @@ function getPropertyName(name, sourceFile) {
|
|
|
4338
3989
|
}
|
|
4339
3990
|
return name.getText(sourceFile);
|
|
4340
3991
|
}
|
|
4341
|
-
function
|
|
4342
|
-
const fields = info.
|
|
3992
|
+
function buildInputsBlock(info, inputDeclarations, ctx) {
|
|
3993
|
+
const fields = info.inlineInputs ?? (info.inputsTypeName ? inputDeclarations.get(info.inputsTypeName) ?? [] : void 0) ?? [];
|
|
4343
3994
|
if (!fields.length && !info.defaults.size) {
|
|
4344
3995
|
return [];
|
|
4345
3996
|
}
|
|
4346
|
-
const lines = ["
|
|
3997
|
+
const lines = ["#inputs"];
|
|
4347
3998
|
if (fields.length) {
|
|
4348
3999
|
for (const field of fields) {
|
|
4349
4000
|
const def = info.defaults.get(field.name);
|
|
4350
|
-
let line = ` ${field.name}
|
|
4001
|
+
let line = ` ${field.name}`;
|
|
4351
4002
|
if (def) {
|
|
4352
|
-
|
|
4003
|
+
ctx.warnings.push(`Default value for "${field.name}" cannot be preserved in Collie #inputs.`);
|
|
4353
4004
|
}
|
|
4354
4005
|
lines.push(line);
|
|
4355
4006
|
}
|
|
4356
4007
|
} else {
|
|
4357
4008
|
for (const [name, defValue] of info.defaults.entries()) {
|
|
4358
|
-
|
|
4009
|
+
ctx.warnings.push(`Default value for "${name}" cannot be preserved in Collie #inputs.`);
|
|
4010
|
+
lines.push(` ${name}`);
|
|
4359
4011
|
}
|
|
4360
4012
|
}
|
|
4361
4013
|
return lines;
|
|
@@ -4636,28 +4288,28 @@ function hasErrors(diagnostics) {
|
|
|
4636
4288
|
function createStubComponent(name, flavor) {
|
|
4637
4289
|
if (flavor === "tsx") {
|
|
4638
4290
|
return [
|
|
4639
|
-
"export type
|
|
4640
|
-
`export default function ${name}(
|
|
4291
|
+
"export type Inputs = Record<string, never>;",
|
|
4292
|
+
`export default function ${name}(__inputs: Inputs) {`,
|
|
4641
4293
|
" return null;",
|
|
4642
4294
|
"}"
|
|
4643
4295
|
].join("\n");
|
|
4644
4296
|
}
|
|
4645
|
-
return [`export default function ${name}(
|
|
4297
|
+
return [`export default function ${name}(__inputs) {`, " return null;", "}"].join("\n");
|
|
4646
4298
|
}
|
|
4647
4299
|
function createStubRender(flavor) {
|
|
4648
4300
|
if (flavor === "tsx") {
|
|
4649
4301
|
return [
|
|
4650
|
-
"export type
|
|
4651
|
-
"export function render(
|
|
4302
|
+
"export type Inputs = Record<string, never>;",
|
|
4303
|
+
"export function render(__inputs: any) {",
|
|
4652
4304
|
" return null;",
|
|
4653
4305
|
"}"
|
|
4654
4306
|
].join("\n");
|
|
4655
4307
|
}
|
|
4656
|
-
return ["export function render(
|
|
4308
|
+
return ["export function render(__inputs) {", " return null;", "}"].join("\n");
|
|
4657
4309
|
}
|
|
4658
4310
|
function wrapRenderModuleAsComponent(renderModule, name, flavor) {
|
|
4659
|
-
const signature = flavor === "tsx" ? `export default function ${name}(
|
|
4660
|
-
const wrapper = [signature, " return render(
|
|
4311
|
+
const signature = flavor === "tsx" ? `export default function ${name}(__inputs: Inputs) {` : `export default function ${name}(__inputs) {`;
|
|
4312
|
+
const wrapper = [signature, " return render(__inputs);", "}"].join("\n");
|
|
4661
4313
|
return `${renderModule}
|
|
4662
4314
|
|
|
4663
4315
|
${wrapper}`;
|