@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.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
// src/rewrite.ts
|
|
2
|
-
function createTemplateEnv(
|
|
3
|
-
const
|
|
4
|
-
if (
|
|
5
|
-
for (const decl of
|
|
6
|
-
|
|
2
|
+
function createTemplateEnv(inputsDecls) {
|
|
3
|
+
const inputNames = /* @__PURE__ */ new Set();
|
|
4
|
+
if (inputsDecls) {
|
|
5
|
+
for (const decl of inputsDecls) {
|
|
6
|
+
inputNames.add(decl.name);
|
|
7
7
|
}
|
|
8
8
|
}
|
|
9
9
|
return {
|
|
10
|
-
|
|
10
|
+
inputNames,
|
|
11
11
|
localsStack: []
|
|
12
12
|
};
|
|
13
13
|
}
|
|
@@ -26,12 +26,6 @@ function isLocal(env, name) {
|
|
|
26
26
|
}
|
|
27
27
|
return false;
|
|
28
28
|
}
|
|
29
|
-
function isPropAlias(env, name) {
|
|
30
|
-
if (isLocal(env, name)) {
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
return env.propAliases.has(name);
|
|
34
|
-
}
|
|
35
29
|
var IGNORED_IDENTIFIERS = /* @__PURE__ */ new Set([
|
|
36
30
|
"null",
|
|
37
31
|
"undefined",
|
|
@@ -39,10 +33,10 @@ var IGNORED_IDENTIFIERS = /* @__PURE__ */ new Set([
|
|
|
39
33
|
"false",
|
|
40
34
|
"NaN",
|
|
41
35
|
"Infinity",
|
|
42
|
-
"this"
|
|
43
|
-
"props"
|
|
36
|
+
"this"
|
|
44
37
|
]);
|
|
45
38
|
var RESERVED_KEYWORDS = /* @__PURE__ */ new Set([
|
|
39
|
+
"async",
|
|
46
40
|
"await",
|
|
47
41
|
"break",
|
|
48
42
|
"case",
|
|
@@ -84,185 +78,33 @@ var RESERVED_KEYWORDS = /* @__PURE__ */ new Set([
|
|
|
84
78
|
"yield"
|
|
85
79
|
]);
|
|
86
80
|
function rewriteExpression(expression, env) {
|
|
87
|
-
|
|
88
|
-
let state = "code";
|
|
89
|
-
let output = "";
|
|
81
|
+
const tokens = tokenizeExpression(expression);
|
|
90
82
|
const usedBare = /* @__PURE__ */ new Set();
|
|
91
|
-
const usedPropsDot = /* @__PURE__ */ new Set();
|
|
92
83
|
const callSitesBare = /* @__PURE__ */ new Set();
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const ch = expression[i];
|
|
97
|
-
if (state === "code") {
|
|
98
|
-
if (ch === "'" || ch === '"') {
|
|
99
|
-
state = ch === "'" ? "single" : "double";
|
|
100
|
-
output += ch;
|
|
101
|
-
i++;
|
|
102
|
-
continue;
|
|
103
|
-
}
|
|
104
|
-
if (ch === "`") {
|
|
105
|
-
state = "template";
|
|
106
|
-
output += ch;
|
|
107
|
-
i++;
|
|
108
|
-
continue;
|
|
109
|
-
}
|
|
110
|
-
if (ch === "/" && expression[i + 1] === "/") {
|
|
111
|
-
state = "line";
|
|
112
|
-
output += ch;
|
|
113
|
-
i++;
|
|
114
|
-
continue;
|
|
115
|
-
}
|
|
116
|
-
if (ch === "/" && expression[i + 1] === "*") {
|
|
117
|
-
state = "block";
|
|
118
|
-
output += ch;
|
|
119
|
-
i++;
|
|
120
|
-
continue;
|
|
121
|
-
}
|
|
122
|
-
if (isIdentifierStart(ch)) {
|
|
123
|
-
const start = i;
|
|
124
|
-
i++;
|
|
125
|
-
while (i < expression.length && isIdentifierPart(expression[i])) {
|
|
126
|
-
i++;
|
|
127
|
-
}
|
|
128
|
-
const name = expression.slice(start, i);
|
|
129
|
-
const prevNonSpace = findPreviousNonSpace(expression, start - 1);
|
|
130
|
-
const nextNonSpace = findNextNonSpace(expression, i);
|
|
131
|
-
const isMemberAccess = prevNonSpace === ".";
|
|
132
|
-
const isObjectKey = nextNonSpace === ":" && (prevNonSpace === "{" || prevNonSpace === ",");
|
|
133
|
-
const isCall = nextNonSpace === "(";
|
|
134
|
-
if (prevNonSpace === "." && start >= 2) {
|
|
135
|
-
const propsStart = findPreviousIdentifierStart(expression, start - 2);
|
|
136
|
-
if (propsStart !== null) {
|
|
137
|
-
const possibleProps = expression.slice(propsStart, start - 1).trim();
|
|
138
|
-
if (possibleProps === "props") {
|
|
139
|
-
usedPropsDot.add(name);
|
|
140
|
-
if (isCall) {
|
|
141
|
-
callSitesPropsDot.add(name);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
if (isMemberAccess || isObjectKey || isLocal(env, name) || shouldIgnoreIdentifier(name)) {
|
|
147
|
-
output += name;
|
|
148
|
-
continue;
|
|
149
|
-
}
|
|
150
|
-
if (isPropAlias(env, name)) {
|
|
151
|
-
output += `props.${name}`;
|
|
152
|
-
rewrittenAliases.add(name);
|
|
153
|
-
if (isCall) {
|
|
154
|
-
callSitesBare.add(name);
|
|
155
|
-
}
|
|
156
|
-
continue;
|
|
157
|
-
}
|
|
158
|
-
usedBare.add(name);
|
|
159
|
-
if (isCall) {
|
|
160
|
-
callSitesBare.add(name);
|
|
161
|
-
}
|
|
162
|
-
output += name;
|
|
163
|
-
continue;
|
|
164
|
-
}
|
|
165
|
-
output += ch;
|
|
166
|
-
i++;
|
|
167
|
-
continue;
|
|
168
|
-
}
|
|
169
|
-
if (state === "line") {
|
|
170
|
-
output += ch;
|
|
171
|
-
if (ch === "\n") {
|
|
172
|
-
state = "code";
|
|
173
|
-
}
|
|
174
|
-
i++;
|
|
175
|
-
continue;
|
|
176
|
-
}
|
|
177
|
-
if (state === "block") {
|
|
178
|
-
output += ch;
|
|
179
|
-
if (ch === "*" && expression[i + 1] === "/") {
|
|
180
|
-
output += "/";
|
|
181
|
-
i += 2;
|
|
182
|
-
state = "code";
|
|
183
|
-
continue;
|
|
184
|
-
}
|
|
185
|
-
i++;
|
|
186
|
-
continue;
|
|
187
|
-
}
|
|
188
|
-
if (state === "single") {
|
|
189
|
-
output += ch;
|
|
190
|
-
if (ch === "\\") {
|
|
191
|
-
if (i + 1 < expression.length) {
|
|
192
|
-
output += expression[i + 1];
|
|
193
|
-
i += 2;
|
|
194
|
-
continue;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
if (ch === "'") {
|
|
198
|
-
state = "code";
|
|
199
|
-
}
|
|
200
|
-
i++;
|
|
201
|
-
continue;
|
|
202
|
-
}
|
|
203
|
-
if (state === "double") {
|
|
204
|
-
output += ch;
|
|
205
|
-
if (ch === "\\") {
|
|
206
|
-
if (i + 1 < expression.length) {
|
|
207
|
-
output += expression[i + 1];
|
|
208
|
-
i += 2;
|
|
209
|
-
continue;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
if (ch === '"') {
|
|
213
|
-
state = "code";
|
|
214
|
-
}
|
|
215
|
-
i++;
|
|
216
|
-
continue;
|
|
217
|
-
}
|
|
218
|
-
if (state === "template") {
|
|
219
|
-
output += ch;
|
|
220
|
-
if (ch === "\\") {
|
|
221
|
-
if (i + 1 < expression.length) {
|
|
222
|
-
output += expression[i + 1];
|
|
223
|
-
i += 2;
|
|
224
|
-
continue;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
if (ch === "`") {
|
|
228
|
-
state = "code";
|
|
229
|
-
}
|
|
230
|
-
i++;
|
|
231
|
-
continue;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
return { code: output, usedBare, usedPropsDot, callSitesBare, callSitesPropsDot, rewrittenAliases };
|
|
84
|
+
const localScopes = [/* @__PURE__ */ new Set()];
|
|
85
|
+
analyzeTokens(tokens, 0, tokens.length, env, localScopes, usedBare, callSitesBare, false);
|
|
86
|
+
return { code: expression, usedBare, callSitesBare };
|
|
235
87
|
}
|
|
236
88
|
function rewriteJsxExpression(expression, env) {
|
|
237
|
-
let output = "";
|
|
238
89
|
let i = 0;
|
|
239
90
|
const usedBare = /* @__PURE__ */ new Set();
|
|
240
|
-
const usedPropsDot = /* @__PURE__ */ new Set();
|
|
241
91
|
const callSitesBare = /* @__PURE__ */ new Set();
|
|
242
|
-
const callSitesPropsDot = /* @__PURE__ */ new Set();
|
|
243
|
-
const rewrittenAliases = /* @__PURE__ */ new Set();
|
|
244
92
|
while (i < expression.length) {
|
|
245
93
|
const ch = expression[i];
|
|
246
94
|
if (ch === "{") {
|
|
247
95
|
const braceResult = readBalancedBraces(expression, i + 1);
|
|
248
96
|
if (!braceResult) {
|
|
249
|
-
output += expression.slice(i);
|
|
250
97
|
break;
|
|
251
98
|
}
|
|
252
99
|
const result = rewriteExpression(braceResult.content, env);
|
|
253
|
-
output += `{${result.code}}`;
|
|
254
100
|
for (const name of result.usedBare) usedBare.add(name);
|
|
255
|
-
for (const name of result.usedPropsDot) usedPropsDot.add(name);
|
|
256
101
|
for (const name of result.callSitesBare) callSitesBare.add(name);
|
|
257
|
-
for (const name of result.callSitesPropsDot) callSitesPropsDot.add(name);
|
|
258
|
-
for (const name of result.rewrittenAliases) rewrittenAliases.add(name);
|
|
259
102
|
i = braceResult.endIndex + 1;
|
|
260
103
|
continue;
|
|
261
104
|
}
|
|
262
|
-
output += ch;
|
|
263
105
|
i++;
|
|
264
106
|
}
|
|
265
|
-
return { code:
|
|
107
|
+
return { code: expression, usedBare, callSitesBare };
|
|
266
108
|
}
|
|
267
109
|
function readBalancedBraces(source, startIndex) {
|
|
268
110
|
let i = startIndex;
|
|
@@ -354,38 +196,6 @@ function readBalancedBraces(source, startIndex) {
|
|
|
354
196
|
}
|
|
355
197
|
return null;
|
|
356
198
|
}
|
|
357
|
-
function findPreviousNonSpace(text, index) {
|
|
358
|
-
for (let i = index; i >= 0; i--) {
|
|
359
|
-
const ch = text[i];
|
|
360
|
-
if (!/\s/.test(ch)) {
|
|
361
|
-
return ch;
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
return null;
|
|
365
|
-
}
|
|
366
|
-
function findNextNonSpace(text, index) {
|
|
367
|
-
for (let i = index; i < text.length; i++) {
|
|
368
|
-
const ch = text[i];
|
|
369
|
-
if (!/\s/.test(ch)) {
|
|
370
|
-
return ch;
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
return null;
|
|
374
|
-
}
|
|
375
|
-
function findPreviousIdentifierStart(text, index) {
|
|
376
|
-
let i = index;
|
|
377
|
-
while (i >= 0 && /\s/.test(text[i])) {
|
|
378
|
-
i--;
|
|
379
|
-
}
|
|
380
|
-
if (i < 0) return null;
|
|
381
|
-
if (!isIdentifierPart(text[i])) {
|
|
382
|
-
return null;
|
|
383
|
-
}
|
|
384
|
-
while (i > 0 && isIdentifierPart(text[i - 1])) {
|
|
385
|
-
i--;
|
|
386
|
-
}
|
|
387
|
-
return i;
|
|
388
|
-
}
|
|
389
199
|
function isIdentifierStart(ch) {
|
|
390
200
|
return /[A-Za-z_$]/.test(ch);
|
|
391
201
|
}
|
|
@@ -395,96 +205,592 @@ function isIdentifierPart(ch) {
|
|
|
395
205
|
function shouldIgnoreIdentifier(name) {
|
|
396
206
|
return IGNORED_IDENTIFIERS.has(name) || RESERVED_KEYWORDS.has(name);
|
|
397
207
|
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
208
|
+
function tokenizeExpression(expression) {
|
|
209
|
+
const tokens = [];
|
|
210
|
+
let i = 0;
|
|
211
|
+
while (i < expression.length) {
|
|
212
|
+
const ch = expression[i];
|
|
213
|
+
if (/\s/.test(ch)) {
|
|
214
|
+
i++;
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
if (ch === "/" && expression[i + 1] === "/") {
|
|
218
|
+
i += 2;
|
|
219
|
+
while (i < expression.length && expression[i] !== "\n") {
|
|
220
|
+
i++;
|
|
221
|
+
}
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
if (ch === "/" && expression[i + 1] === "*") {
|
|
225
|
+
i += 2;
|
|
226
|
+
while (i < expression.length && !(expression[i] === "*" && expression[i + 1] === "/")) {
|
|
227
|
+
i++;
|
|
228
|
+
}
|
|
229
|
+
i += 2;
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
if (ch === "'" || ch === '"') {
|
|
233
|
+
i = skipStringLiteral(expression, i, ch);
|
|
234
|
+
tokens.push({ type: "literal", value: "string" });
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
if (ch === "`") {
|
|
238
|
+
i = skipTemplateLiteral(expression, i);
|
|
239
|
+
tokens.push({ type: "literal", value: "template" });
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
if (isIdentifierStart(ch)) {
|
|
243
|
+
const start = i;
|
|
244
|
+
i++;
|
|
245
|
+
while (i < expression.length && isIdentifierPart(expression[i])) {
|
|
246
|
+
i++;
|
|
247
|
+
}
|
|
248
|
+
tokens.push({ type: "identifier", value: expression.slice(start, i) });
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
if (/[0-9]/.test(ch)) {
|
|
252
|
+
const start = i;
|
|
253
|
+
i++;
|
|
254
|
+
while (i < expression.length && /[0-9._]/.test(expression[i])) {
|
|
255
|
+
i++;
|
|
256
|
+
}
|
|
257
|
+
tokens.push({ type: "literal", value: expression.slice(start, i) });
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
if (expression.startsWith("...", i)) {
|
|
261
|
+
tokens.push({ type: "punctuator", value: "..." });
|
|
262
|
+
i += 3;
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
if (expression.startsWith("=>", i)) {
|
|
266
|
+
tokens.push({ type: "punctuator", value: "=>" });
|
|
267
|
+
i += 2;
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
if (expression.startsWith("?.", i)) {
|
|
271
|
+
tokens.push({ type: "punctuator", value: "?." });
|
|
272
|
+
i += 2;
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
if (expression.startsWith("??", i)) {
|
|
276
|
+
tokens.push({ type: "punctuator", value: "??" });
|
|
277
|
+
i += 2;
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
tokens.push({ type: "punctuator", value: ch });
|
|
281
|
+
i++;
|
|
411
282
|
}
|
|
412
|
-
|
|
413
|
-
parts.push(functionLines.join("\n"));
|
|
414
|
-
return parts.join("\n\n");
|
|
283
|
+
return tokens;
|
|
415
284
|
}
|
|
416
|
-
function
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
prelude.push(`import React from "react";`);
|
|
285
|
+
function skipStringLiteral(source, start, quote) {
|
|
286
|
+
let i = start + 1;
|
|
287
|
+
while (i < source.length) {
|
|
288
|
+
const ch = source[i];
|
|
289
|
+
if (ch === "\\") {
|
|
290
|
+
i += 2;
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
if (ch === quote) {
|
|
294
|
+
return i + 1;
|
|
295
|
+
}
|
|
296
|
+
i++;
|
|
429
297
|
}
|
|
430
|
-
|
|
431
|
-
return { prelude, propsType, propsDestructure, jsx, isTsx };
|
|
298
|
+
return source.length;
|
|
432
299
|
}
|
|
433
|
-
function
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
300
|
+
function skipTemplateLiteral(source, start) {
|
|
301
|
+
let i = start + 1;
|
|
302
|
+
while (i < source.length) {
|
|
303
|
+
const ch = source[i];
|
|
304
|
+
if (ch === "\\") {
|
|
305
|
+
i += 2;
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
if (ch === "`") {
|
|
309
|
+
return i + 1;
|
|
310
|
+
}
|
|
311
|
+
i++;
|
|
437
312
|
}
|
|
438
|
-
|
|
439
|
-
|
|
313
|
+
return source.length;
|
|
314
|
+
}
|
|
315
|
+
function analyzeTokens(tokens, start, end, env, scopes, usedBare, callSitesBare, allowStatements) {
|
|
316
|
+
let i = start;
|
|
317
|
+
while (i < end) {
|
|
318
|
+
const token = tokens[i];
|
|
319
|
+
if (token.type === "identifier") {
|
|
320
|
+
if (token.value === "function") {
|
|
321
|
+
const fnResult = parseFunctionExpression(tokens, i, end, env, scopes, usedBare, callSitesBare);
|
|
322
|
+
if (fnResult > i) {
|
|
323
|
+
i = fnResult;
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
if (allowStatements && (token.value === "const" || token.value === "let" || token.value === "var")) {
|
|
328
|
+
const declResult = parseVariableDeclaration(tokens, i, end, env, scopes, usedBare, callSitesBare);
|
|
329
|
+
if (declResult > i) {
|
|
330
|
+
i = declResult;
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
if (allowStatements && token.value === "catch") {
|
|
335
|
+
const catchResult = parseCatchClause(tokens, i, end, env, scopes, usedBare, callSitesBare);
|
|
336
|
+
if (catchResult > i) {
|
|
337
|
+
i = catchResult;
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
const arrowResult = parseArrowFunction(tokens, i, end, env, scopes, usedBare, callSitesBare);
|
|
342
|
+
if (arrowResult > i) {
|
|
343
|
+
i = arrowResult;
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
if (shouldIgnoreIdentifier(token.value)) {
|
|
347
|
+
i++;
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
if (isShadowed(env, scopes, token.value)) {
|
|
351
|
+
i++;
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
if (isMemberAccess(tokens, i) || isObjectKey(tokens, i)) {
|
|
355
|
+
i++;
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
usedBare.add(token.value);
|
|
359
|
+
if (isCallSite(tokens, i)) {
|
|
360
|
+
callSitesBare.add(token.value);
|
|
361
|
+
}
|
|
362
|
+
i++;
|
|
363
|
+
continue;
|
|
364
|
+
}
|
|
365
|
+
if (token.type === "punctuator" && token.value === "(") {
|
|
366
|
+
const arrowResult = parseArrowFunction(tokens, i, end, env, scopes, usedBare, callSitesBare);
|
|
367
|
+
if (arrowResult > i) {
|
|
368
|
+
i = arrowResult;
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
i++;
|
|
440
373
|
}
|
|
441
|
-
return env;
|
|
442
374
|
}
|
|
443
|
-
function
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
if (root.children.length === 0) {
|
|
448
|
-
return false;
|
|
375
|
+
function parseArrowFunction(tokens, index, end, env, scopes, usedBare, callSitesBare) {
|
|
376
|
+
const token = tokens[index];
|
|
377
|
+
if (!token) {
|
|
378
|
+
return index;
|
|
449
379
|
}
|
|
450
|
-
if (
|
|
451
|
-
|
|
380
|
+
if (token.type === "identifier") {
|
|
381
|
+
const next = tokens[index + 1];
|
|
382
|
+
if (next && next.value === "=>") {
|
|
383
|
+
const params = /* @__PURE__ */ new Set([token.value]);
|
|
384
|
+
return analyzeArrowBody(tokens, index + 2, end, params, env, scopes, usedBare, callSitesBare);
|
|
385
|
+
}
|
|
452
386
|
}
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
387
|
+
if (token.type === "punctuator" && token.value === "(") {
|
|
388
|
+
const closeIndex = findMatchingToken(tokens, index, "(", ")");
|
|
389
|
+
if (closeIndex !== -1) {
|
|
390
|
+
const afterClose = tokens[closeIndex + 1];
|
|
391
|
+
if (afterClose && afterClose.value === "=>") {
|
|
392
|
+
const params = /* @__PURE__ */ new Set();
|
|
393
|
+
collectBindingNamesFromList(tokens, index + 1, closeIndex, params);
|
|
394
|
+
return analyzeArrowBody(tokens, closeIndex + 2, end, params, env, scopes, usedBare, callSitesBare);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
458
397
|
}
|
|
459
|
-
|
|
460
|
-
|
|
398
|
+
return index;
|
|
399
|
+
}
|
|
400
|
+
function analyzeArrowBody(tokens, start, end, params, env, scopes, usedBare, callSitesBare) {
|
|
401
|
+
const bodyToken = tokens[start];
|
|
402
|
+
if (!bodyToken) {
|
|
403
|
+
return start;
|
|
404
|
+
}
|
|
405
|
+
const scope = new Set(params);
|
|
406
|
+
scopes.push(scope);
|
|
407
|
+
if (bodyToken.type === "punctuator" && bodyToken.value === "{") {
|
|
408
|
+
const closeIndex = findMatchingToken(tokens, start, "{", "}");
|
|
409
|
+
const bodyEnd2 = closeIndex === -1 ? end : closeIndex;
|
|
410
|
+
analyzeTokens(tokens, start + 1, bodyEnd2, env, scopes, usedBare, callSitesBare, true);
|
|
411
|
+
scopes.pop();
|
|
412
|
+
return closeIndex === -1 ? end : closeIndex + 1;
|
|
413
|
+
}
|
|
414
|
+
const bodyEnd = findExpressionEnd(tokens, start, end, EXPRESSION_TERMINATORS);
|
|
415
|
+
analyzeTokens(tokens, start, bodyEnd, env, scopes, usedBare, callSitesBare, false);
|
|
416
|
+
scopes.pop();
|
|
417
|
+
return bodyEnd;
|
|
418
|
+
}
|
|
419
|
+
function parseFunctionExpression(tokens, index, end, env, scopes, usedBare, callSitesBare) {
|
|
420
|
+
let i = index + 1;
|
|
421
|
+
const nameToken = tokens[i];
|
|
422
|
+
let fnName;
|
|
423
|
+
if (nameToken && nameToken.type === "identifier" && tokens[i + 1]?.value === "(") {
|
|
424
|
+
fnName = nameToken.value;
|
|
425
|
+
i++;
|
|
461
426
|
}
|
|
462
|
-
if (
|
|
463
|
-
return
|
|
427
|
+
if (!tokens[i] || tokens[i].value !== "(") {
|
|
428
|
+
return index;
|
|
464
429
|
}
|
|
465
|
-
|
|
466
|
-
|
|
430
|
+
const closeIndex = findMatchingToken(tokens, i, "(", ")");
|
|
431
|
+
if (closeIndex === -1) {
|
|
432
|
+
return index;
|
|
433
|
+
}
|
|
434
|
+
const params = /* @__PURE__ */ new Set();
|
|
435
|
+
collectBindingNamesFromList(tokens, i + 1, closeIndex, params);
|
|
436
|
+
if (fnName) {
|
|
437
|
+
params.add(fnName);
|
|
438
|
+
}
|
|
439
|
+
const bodyStart = closeIndex + 1;
|
|
440
|
+
if (!tokens[bodyStart] || tokens[bodyStart].value !== "{") {
|
|
441
|
+
return index;
|
|
442
|
+
}
|
|
443
|
+
const closeBody = findMatchingToken(tokens, bodyStart, "{", "}");
|
|
444
|
+
const bodyEnd = closeBody === -1 ? end : closeBody;
|
|
445
|
+
scopes.push(params);
|
|
446
|
+
analyzeTokens(tokens, bodyStart + 1, bodyEnd, env, scopes, usedBare, callSitesBare, true);
|
|
447
|
+
scopes.pop();
|
|
448
|
+
return closeBody === -1 ? end : closeBody + 1;
|
|
449
|
+
}
|
|
450
|
+
function parseCatchClause(tokens, index, end, env, scopes, usedBare, callSitesBare) {
|
|
451
|
+
const next = tokens[index + 1];
|
|
452
|
+
if (!next || next.value !== "(") {
|
|
453
|
+
return index;
|
|
454
|
+
}
|
|
455
|
+
const closeIndex = findMatchingToken(tokens, index + 1, "(", ")");
|
|
456
|
+
if (closeIndex === -1) {
|
|
457
|
+
return index;
|
|
458
|
+
}
|
|
459
|
+
const params = /* @__PURE__ */ new Set();
|
|
460
|
+
collectBindingNamesFromList(tokens, index + 2, closeIndex, params);
|
|
461
|
+
const bodyStart = closeIndex + 1;
|
|
462
|
+
if (!tokens[bodyStart] || tokens[bodyStart].value !== "{") {
|
|
463
|
+
return index;
|
|
464
|
+
}
|
|
465
|
+
const closeBody = findMatchingToken(tokens, bodyStart, "{", "}");
|
|
466
|
+
const bodyEnd = closeBody === -1 ? end : closeBody;
|
|
467
|
+
scopes.push(params);
|
|
468
|
+
analyzeTokens(tokens, bodyStart + 1, bodyEnd, env, scopes, usedBare, callSitesBare, true);
|
|
469
|
+
scopes.pop();
|
|
470
|
+
return closeBody === -1 ? end : closeBody + 1;
|
|
471
|
+
}
|
|
472
|
+
function parseVariableDeclaration(tokens, index, end, env, scopes, usedBare, callSitesBare) {
|
|
473
|
+
let i = index + 1;
|
|
474
|
+
const scope = scopes[scopes.length - 1];
|
|
475
|
+
while (i < end) {
|
|
476
|
+
const names = /* @__PURE__ */ new Set();
|
|
477
|
+
const nextIndex = parseBindingPattern(tokens, i, end, names);
|
|
478
|
+
if (nextIndex === i) {
|
|
479
|
+
return index;
|
|
480
|
+
}
|
|
481
|
+
i = nextIndex;
|
|
482
|
+
if (tokens[i] && tokens[i].value === "=") {
|
|
483
|
+
const initStart = i + 1;
|
|
484
|
+
const initEnd = findExpressionEnd(tokens, initStart, end, DECLARATION_TERMINATORS);
|
|
485
|
+
analyzeTokens(tokens, initStart, initEnd, env, scopes, usedBare, callSitesBare, false);
|
|
486
|
+
i = initEnd;
|
|
487
|
+
}
|
|
488
|
+
for (const name of names) {
|
|
489
|
+
scope.add(name);
|
|
490
|
+
}
|
|
491
|
+
if (tokens[i] && tokens[i].value === ",") {
|
|
492
|
+
i++;
|
|
493
|
+
continue;
|
|
494
|
+
}
|
|
495
|
+
break;
|
|
467
496
|
}
|
|
468
|
-
return
|
|
497
|
+
return i;
|
|
469
498
|
}
|
|
470
|
-
function
|
|
471
|
-
|
|
472
|
-
|
|
499
|
+
function parseBindingPattern(tokens, start, end, names) {
|
|
500
|
+
const token = tokens[start];
|
|
501
|
+
if (!token) {
|
|
502
|
+
return start;
|
|
473
503
|
}
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
if (node.type === "Text") {
|
|
478
|
-
return emitText(node, env);
|
|
504
|
+
if (token.type === "identifier") {
|
|
505
|
+
names.add(token.value);
|
|
506
|
+
return start + 1;
|
|
479
507
|
}
|
|
480
|
-
if (
|
|
481
|
-
return
|
|
508
|
+
if (token.value === "{") {
|
|
509
|
+
return parseObjectPattern(tokens, start + 1, end, names);
|
|
482
510
|
}
|
|
483
|
-
if (
|
|
484
|
-
return
|
|
511
|
+
if (token.value === "[") {
|
|
512
|
+
return parseArrayPattern(tokens, start + 1, end, names);
|
|
485
513
|
}
|
|
486
|
-
|
|
487
|
-
|
|
514
|
+
return start + 1;
|
|
515
|
+
}
|
|
516
|
+
function parseObjectPattern(tokens, start, end, names) {
|
|
517
|
+
let i = start;
|
|
518
|
+
while (i < end) {
|
|
519
|
+
const token = tokens[i];
|
|
520
|
+
if (!token) {
|
|
521
|
+
return i;
|
|
522
|
+
}
|
|
523
|
+
if (token.value === "}") {
|
|
524
|
+
return i + 1;
|
|
525
|
+
}
|
|
526
|
+
if (token.value === ",") {
|
|
527
|
+
i++;
|
|
528
|
+
continue;
|
|
529
|
+
}
|
|
530
|
+
if (token.value === "...") {
|
|
531
|
+
i++;
|
|
532
|
+
i = parseBindingPattern(tokens, i, end, names);
|
|
533
|
+
i = skipDefaultValue(tokens, i, end, OBJECT_PATTERN_TERMINATORS);
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
if (token.value === "[") {
|
|
537
|
+
const closeIndex = findMatchingToken(tokens, i, "[", "]");
|
|
538
|
+
i = closeIndex === -1 ? end : closeIndex + 1;
|
|
539
|
+
if (tokens[i] && tokens[i].value === ":") {
|
|
540
|
+
i++;
|
|
541
|
+
i = parseBindingPattern(tokens, i, end, names);
|
|
542
|
+
i = skipDefaultValue(tokens, i, end, OBJECT_PATTERN_TERMINATORS);
|
|
543
|
+
}
|
|
544
|
+
continue;
|
|
545
|
+
}
|
|
546
|
+
if (token.type === "identifier" || token.type === "literal") {
|
|
547
|
+
const key = token.value;
|
|
548
|
+
i++;
|
|
549
|
+
if (tokens[i] && tokens[i].value === ":") {
|
|
550
|
+
i++;
|
|
551
|
+
i = parseBindingPattern(tokens, i, end, names);
|
|
552
|
+
} else if (token.type === "identifier") {
|
|
553
|
+
names.add(key);
|
|
554
|
+
}
|
|
555
|
+
i = skipDefaultValue(tokens, i, end, OBJECT_PATTERN_TERMINATORS);
|
|
556
|
+
continue;
|
|
557
|
+
}
|
|
558
|
+
i++;
|
|
559
|
+
}
|
|
560
|
+
return i;
|
|
561
|
+
}
|
|
562
|
+
function parseArrayPattern(tokens, start, end, names) {
|
|
563
|
+
let i = start;
|
|
564
|
+
while (i < end) {
|
|
565
|
+
const token = tokens[i];
|
|
566
|
+
if (!token) {
|
|
567
|
+
return i;
|
|
568
|
+
}
|
|
569
|
+
if (token.value === "]") {
|
|
570
|
+
return i + 1;
|
|
571
|
+
}
|
|
572
|
+
if (token.value === ",") {
|
|
573
|
+
i++;
|
|
574
|
+
continue;
|
|
575
|
+
}
|
|
576
|
+
if (token.value === "...") {
|
|
577
|
+
i++;
|
|
578
|
+
i = parseBindingPattern(tokens, i, end, names);
|
|
579
|
+
i = skipDefaultValue(tokens, i, end, ARRAY_PATTERN_TERMINATORS);
|
|
580
|
+
continue;
|
|
581
|
+
}
|
|
582
|
+
i = parseBindingPattern(tokens, i, end, names);
|
|
583
|
+
i = skipDefaultValue(tokens, i, end, ARRAY_PATTERN_TERMINATORS);
|
|
584
|
+
if (tokens[i] && tokens[i].value === ",") {
|
|
585
|
+
i++;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
return i;
|
|
589
|
+
}
|
|
590
|
+
function collectBindingNamesFromList(tokens, start, end, names) {
|
|
591
|
+
let i = start;
|
|
592
|
+
while (i < end) {
|
|
593
|
+
if (tokens[i] && tokens[i].value === ",") {
|
|
594
|
+
i++;
|
|
595
|
+
continue;
|
|
596
|
+
}
|
|
597
|
+
const nextIndex = parseBindingPattern(tokens, i, end, names);
|
|
598
|
+
if (nextIndex === i) {
|
|
599
|
+
i++;
|
|
600
|
+
continue;
|
|
601
|
+
}
|
|
602
|
+
i = skipParameterSuffix(tokens, nextIndex, end);
|
|
603
|
+
if (tokens[i] && tokens[i].value === ",") {
|
|
604
|
+
i++;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
function skipParameterSuffix(tokens, start, end) {
|
|
609
|
+
if (!tokens[start]) {
|
|
610
|
+
return start;
|
|
611
|
+
}
|
|
612
|
+
if (tokens[start].value === "=" || tokens[start].value === ":") {
|
|
613
|
+
return findExpressionEnd(tokens, start + 1, end, PARAMETER_TERMINATORS);
|
|
614
|
+
}
|
|
615
|
+
return start;
|
|
616
|
+
}
|
|
617
|
+
function skipDefaultValue(tokens, start, end, terminators) {
|
|
618
|
+
if (!tokens[start] || tokens[start].value !== "=") {
|
|
619
|
+
return start;
|
|
620
|
+
}
|
|
621
|
+
return findExpressionEnd(tokens, start + 1, end, terminators);
|
|
622
|
+
}
|
|
623
|
+
function findMatchingToken(tokens, start, open, close) {
|
|
624
|
+
let depth = 0;
|
|
625
|
+
for (let i = start; i < tokens.length; i++) {
|
|
626
|
+
const value = tokens[i].value;
|
|
627
|
+
if (value === open) {
|
|
628
|
+
depth++;
|
|
629
|
+
} else if (value === close) {
|
|
630
|
+
depth--;
|
|
631
|
+
if (depth === 0) {
|
|
632
|
+
return i;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
return -1;
|
|
637
|
+
}
|
|
638
|
+
function findExpressionEnd(tokens, start, end, terminators) {
|
|
639
|
+
let depthParen = 0;
|
|
640
|
+
let depthBracket = 0;
|
|
641
|
+
let depthBrace = 0;
|
|
642
|
+
for (let i = start; i < end; i++) {
|
|
643
|
+
const value = tokens[i].value;
|
|
644
|
+
if (value === "(") {
|
|
645
|
+
depthParen++;
|
|
646
|
+
} else if (value === ")") {
|
|
647
|
+
if (depthParen === 0 && terminators.has(value)) {
|
|
648
|
+
return i;
|
|
649
|
+
}
|
|
650
|
+
depthParen = Math.max(0, depthParen - 1);
|
|
651
|
+
} else if (value === "[") {
|
|
652
|
+
depthBracket++;
|
|
653
|
+
} else if (value === "]") {
|
|
654
|
+
if (depthBracket === 0 && terminators.has(value)) {
|
|
655
|
+
return i;
|
|
656
|
+
}
|
|
657
|
+
depthBracket = Math.max(0, depthBracket - 1);
|
|
658
|
+
} else if (value === "{") {
|
|
659
|
+
depthBrace++;
|
|
660
|
+
} else if (value === "}") {
|
|
661
|
+
if (depthBrace === 0 && terminators.has(value)) {
|
|
662
|
+
return i;
|
|
663
|
+
}
|
|
664
|
+
depthBrace = Math.max(0, depthBrace - 1);
|
|
665
|
+
}
|
|
666
|
+
if (depthParen === 0 && depthBracket === 0 && depthBrace === 0 && terminators.has(value)) {
|
|
667
|
+
return i;
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
return end;
|
|
671
|
+
}
|
|
672
|
+
function isMemberAccess(tokens, index) {
|
|
673
|
+
const prev = tokens[index - 1];
|
|
674
|
+
return prev?.value === "." || prev?.value === "?.";
|
|
675
|
+
}
|
|
676
|
+
function isObjectKey(tokens, index) {
|
|
677
|
+
const next = tokens[index + 1];
|
|
678
|
+
if (!next || next.value !== ":") {
|
|
679
|
+
return false;
|
|
680
|
+
}
|
|
681
|
+
const prev = tokens[index - 1];
|
|
682
|
+
return prev?.value === "{" || prev?.value === ",";
|
|
683
|
+
}
|
|
684
|
+
function isCallSite(tokens, index) {
|
|
685
|
+
const next = tokens[index + 1];
|
|
686
|
+
return next?.value === "(";
|
|
687
|
+
}
|
|
688
|
+
function isShadowed(env, scopes, name) {
|
|
689
|
+
if (isLocal(env, name)) {
|
|
690
|
+
return true;
|
|
691
|
+
}
|
|
692
|
+
for (let i = scopes.length - 1; i >= 0; i--) {
|
|
693
|
+
if (scopes[i].has(name)) {
|
|
694
|
+
return true;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
return false;
|
|
698
|
+
}
|
|
699
|
+
var PARAMETER_TERMINATORS = /* @__PURE__ */ new Set([","]);
|
|
700
|
+
var OBJECT_PATTERN_TERMINATORS = /* @__PURE__ */ new Set([",", "}"]);
|
|
701
|
+
var ARRAY_PATTERN_TERMINATORS = /* @__PURE__ */ new Set([",", "]"]);
|
|
702
|
+
var EXPRESSION_TERMINATORS = /* @__PURE__ */ new Set([",", ")", "]", "}", ";"]);
|
|
703
|
+
var DECLARATION_TERMINATORS = /* @__PURE__ */ new Set([",", ")", "]", "}", ";"]);
|
|
704
|
+
|
|
705
|
+
// src/codegen.ts
|
|
706
|
+
function generateRenderModule(root, options) {
|
|
707
|
+
const { prelude, inputsType, inputsPrelude, jsx, isTsx } = buildModuleParts(root, options);
|
|
708
|
+
const parts = [...prelude, inputsType];
|
|
709
|
+
if (!isTsx) {
|
|
710
|
+
parts.push(`/** @param {any} __inputs */`);
|
|
711
|
+
}
|
|
712
|
+
const functionLines = [
|
|
713
|
+
isTsx ? "export function render(__inputs: any) {" : "export function render(__inputs) {"
|
|
714
|
+
];
|
|
715
|
+
if (inputsPrelude) {
|
|
716
|
+
functionLines.push(` ${inputsPrelude}`);
|
|
717
|
+
}
|
|
718
|
+
functionLines.push(` return ${jsx};`, `}`);
|
|
719
|
+
parts.push(functionLines.join("\n"));
|
|
720
|
+
return parts.join("\n\n");
|
|
721
|
+
}
|
|
722
|
+
function buildModuleParts(root, options) {
|
|
723
|
+
const { jsxRuntime, flavor } = options;
|
|
724
|
+
const isTsx = flavor === "tsx";
|
|
725
|
+
const aliasEnv = buildClassAliasEnvironment(root.classAliases);
|
|
726
|
+
const env = createTemplateEnv(root.inputsDecls);
|
|
727
|
+
const jsx = renderRootChildren(root.children, aliasEnv, env);
|
|
728
|
+
const inputsPrelude = emitInputsPrelude(root.inputsDecls);
|
|
729
|
+
const prelude = [];
|
|
730
|
+
if (root.clientComponent) {
|
|
731
|
+
prelude.push(`"use client";`);
|
|
732
|
+
}
|
|
733
|
+
if (jsxRuntime === "classic" && templateUsesJsx(root)) {
|
|
734
|
+
prelude.push(`import React from "react";`);
|
|
735
|
+
}
|
|
736
|
+
const inputsType = emitInputsType(root.inputs, flavor);
|
|
737
|
+
return { prelude, inputsType, inputsPrelude, jsx, isTsx };
|
|
738
|
+
}
|
|
739
|
+
function buildClassAliasEnvironment(decl) {
|
|
740
|
+
const env = /* @__PURE__ */ new Map();
|
|
741
|
+
if (!decl) {
|
|
742
|
+
return env;
|
|
743
|
+
}
|
|
744
|
+
for (const alias of decl.aliases) {
|
|
745
|
+
env.set(alias.name, alias.classes);
|
|
746
|
+
}
|
|
747
|
+
return env;
|
|
748
|
+
}
|
|
749
|
+
function renderRootChildren(children, aliasEnv, env) {
|
|
750
|
+
return emitNodesExpression(children, aliasEnv, env);
|
|
751
|
+
}
|
|
752
|
+
function templateUsesJsx(root) {
|
|
753
|
+
if (root.children.length === 0) {
|
|
754
|
+
return false;
|
|
755
|
+
}
|
|
756
|
+
if (root.children.length > 1) {
|
|
757
|
+
return true;
|
|
758
|
+
}
|
|
759
|
+
return nodeUsesJsx(root.children[0]);
|
|
760
|
+
}
|
|
761
|
+
function nodeUsesJsx(node) {
|
|
762
|
+
if (node.type === "Element" || node.type === "Text" || node.type === "Component") {
|
|
763
|
+
return true;
|
|
764
|
+
}
|
|
765
|
+
if (node.type === "Expression" || node.type === "JSXPassthrough") {
|
|
766
|
+
return false;
|
|
767
|
+
}
|
|
768
|
+
if (node.type === "Conditional") {
|
|
769
|
+
return node.branches.some((branch) => branchUsesJsx(branch));
|
|
770
|
+
}
|
|
771
|
+
if (node.type === "For") {
|
|
772
|
+
return node.body.some((child) => nodeUsesJsx(child));
|
|
773
|
+
}
|
|
774
|
+
return false;
|
|
775
|
+
}
|
|
776
|
+
function branchUsesJsx(branch) {
|
|
777
|
+
if (!branch.body.length) {
|
|
778
|
+
return false;
|
|
779
|
+
}
|
|
780
|
+
return branch.body.some((child) => nodeUsesJsx(child));
|
|
781
|
+
}
|
|
782
|
+
function emitNodeInJsx(node, aliasEnv, env) {
|
|
783
|
+
if (node.type === "Text") {
|
|
784
|
+
return emitText(node, env);
|
|
785
|
+
}
|
|
786
|
+
if (node.type === "Expression") {
|
|
787
|
+
return `{${emitExpressionValue(node.value, env)}}`;
|
|
788
|
+
}
|
|
789
|
+
if (node.type === "JSXPassthrough") {
|
|
790
|
+
return `{${emitJsxExpression(node.expression, env)}}`;
|
|
791
|
+
}
|
|
792
|
+
if (node.type === "Conditional") {
|
|
793
|
+
return `{${emitConditionalExpression(node, aliasEnv, env)}}`;
|
|
488
794
|
}
|
|
489
795
|
if (node.type === "For") {
|
|
490
796
|
return `{${emitForExpression(node, aliasEnv, env)}}`;
|
|
@@ -508,8 +814,8 @@ function emitElement(node, aliasEnv, env) {
|
|
|
508
814
|
}
|
|
509
815
|
function emitComponent(node, aliasEnv, env) {
|
|
510
816
|
const attrs = emitAttributes(node.attributes, aliasEnv, env);
|
|
511
|
-
const
|
|
512
|
-
const allAttrs = `${attrs}${
|
|
817
|
+
const slotBindings = emitSlotBindings(node, aliasEnv, env);
|
|
818
|
+
const allAttrs = `${attrs}${slotBindings}`;
|
|
513
819
|
const children = emitChildrenWithSpacing(node.children, aliasEnv, env);
|
|
514
820
|
if (children.length > 0) {
|
|
515
821
|
return `<${node.name}${allAttrs}>${children}</${node.name}>`;
|
|
@@ -547,7 +853,7 @@ function emitAttributes(attributes, aliasEnv, env) {
|
|
|
547
853
|
return ` ${attr.name}=${emitAttributeValue(attr.value, env)}`;
|
|
548
854
|
}).join("");
|
|
549
855
|
}
|
|
550
|
-
function
|
|
856
|
+
function emitSlotBindings(node, aliasEnv, env) {
|
|
551
857
|
if (!node.slots || node.slots.length === 0) {
|
|
552
858
|
return "";
|
|
553
859
|
}
|
|
@@ -678,41 +984,41 @@ function emitSingleNodeExpression(node, aliasEnv, env) {
|
|
|
678
984
|
}
|
|
679
985
|
return emitNodeInJsx(node, aliasEnv, env);
|
|
680
986
|
}
|
|
681
|
-
function
|
|
987
|
+
function emitInputsType(inputs, flavor) {
|
|
682
988
|
if (flavor === "tsx") {
|
|
683
|
-
return
|
|
989
|
+
return emitTsInputsType(inputs);
|
|
684
990
|
}
|
|
685
|
-
return
|
|
991
|
+
return emitJsDocInputsType(inputs);
|
|
686
992
|
}
|
|
687
|
-
function
|
|
688
|
-
if (!
|
|
689
|
-
return "/** @typedef {any}
|
|
993
|
+
function emitJsDocInputsType(inputs) {
|
|
994
|
+
if (!inputs) {
|
|
995
|
+
return "/** @typedef {any} Inputs */";
|
|
690
996
|
}
|
|
691
|
-
if (!
|
|
692
|
-
return "/** @typedef {{}}
|
|
997
|
+
if (!inputs.fields.length) {
|
|
998
|
+
return "/** @typedef {{}} Inputs */";
|
|
693
999
|
}
|
|
694
|
-
const fields =
|
|
1000
|
+
const fields = inputs.fields.map((field) => {
|
|
695
1001
|
const optional = field.optional ? "?" : "";
|
|
696
1002
|
return `${field.name}${optional}: ${field.typeText}`;
|
|
697
1003
|
}).join("; ");
|
|
698
|
-
return `/** @typedef {{ ${fields} }}
|
|
1004
|
+
return `/** @typedef {{ ${fields} }} Inputs */`;
|
|
699
1005
|
}
|
|
700
|
-
function
|
|
701
|
-
if (!
|
|
702
|
-
return "export type
|
|
1006
|
+
function emitTsInputsType(inputs) {
|
|
1007
|
+
if (!inputs || inputs.fields.length === 0) {
|
|
1008
|
+
return "export type Inputs = Record<string, never>;";
|
|
703
1009
|
}
|
|
704
|
-
const lines =
|
|
1010
|
+
const lines = inputs.fields.map((field) => {
|
|
705
1011
|
const optional = field.optional ? "?" : "";
|
|
706
1012
|
return ` ${field.name}${optional}: ${field.typeText};`;
|
|
707
1013
|
});
|
|
708
|
-
return ["export interface
|
|
1014
|
+
return ["export interface Inputs {", ...lines, "}"].join("\n");
|
|
709
1015
|
}
|
|
710
|
-
function
|
|
711
|
-
if (!
|
|
1016
|
+
function emitInputsPrelude(inputsDecls) {
|
|
1017
|
+
if (!inputsDecls || inputsDecls.length === 0) {
|
|
712
1018
|
return null;
|
|
713
1019
|
}
|
|
714
|
-
const names =
|
|
715
|
-
return `const { ${names.join(", ")} } =
|
|
1020
|
+
const names = inputsDecls.map((decl) => decl.name);
|
|
1021
|
+
return `const { ${names.join(", ")} } = __inputs ?? {};`;
|
|
716
1022
|
}
|
|
717
1023
|
function escapeText(value) {
|
|
718
1024
|
return value.replace(/[&<>{}]/g, (char) => {
|
|
@@ -874,836 +1180,196 @@ function unescapeChar(char, quote) {
|
|
|
874
1180
|
default:
|
|
875
1181
|
if (char === quote) {
|
|
876
1182
|
return quote;
|
|
877
|
-
}
|
|
878
|
-
return char;
|
|
879
|
-
}
|
|
880
|
-
}
|
|
881
|
-
function buildClassAliasEnvironment2(decl) {
|
|
882
|
-
const env = /* @__PURE__ */ new Map();
|
|
883
|
-
if (!decl) {
|
|
884
|
-
return env;
|
|
885
|
-
}
|
|
886
|
-
for (const alias of decl.aliases) {
|
|
887
|
-
env.set(alias.name, alias.classes);
|
|
888
|
-
}
|
|
889
|
-
return env;
|
|
890
|
-
}
|
|
891
|
-
function expandClasses2(classes, aliasEnv) {
|
|
892
|
-
const result = [];
|
|
893
|
-
for (const cls of classes) {
|
|
894
|
-
const match = cls.match(/^\$([A-Za-z_][A-Za-z0-9_]*)$/);
|
|
895
|
-
if (!match) {
|
|
896
|
-
result.push(cls);
|
|
897
|
-
continue;
|
|
898
|
-
}
|
|
899
|
-
const aliasClasses = aliasEnv.get(match[1]);
|
|
900
|
-
if (!aliasClasses) {
|
|
901
|
-
continue;
|
|
902
|
-
}
|
|
903
|
-
result.push(...aliasClasses);
|
|
904
|
-
}
|
|
905
|
-
return result;
|
|
906
|
-
}
|
|
907
|
-
function escapeStaticText(value) {
|
|
908
|
-
return value.replace(/[&<>{}]/g, (char) => {
|
|
909
|
-
switch (char) {
|
|
910
|
-
case "&":
|
|
911
|
-
return "&";
|
|
912
|
-
case "<":
|
|
913
|
-
return "<";
|
|
914
|
-
case ">":
|
|
915
|
-
return ">";
|
|
916
|
-
case "{":
|
|
917
|
-
return "{";
|
|
918
|
-
case "}":
|
|
919
|
-
return "}";
|
|
920
|
-
default:
|
|
921
|
-
return char;
|
|
922
|
-
}
|
|
923
|
-
});
|
|
924
|
-
}
|
|
925
|
-
function escapeAttributeValue(value) {
|
|
926
|
-
return value.replace(/["&<>]/g, (char) => {
|
|
927
|
-
switch (char) {
|
|
928
|
-
case "&":
|
|
929
|
-
return "&";
|
|
930
|
-
case "<":
|
|
931
|
-
return "<";
|
|
932
|
-
case ">":
|
|
933
|
-
return ">";
|
|
934
|
-
case '"':
|
|
935
|
-
return """;
|
|
936
|
-
default:
|
|
937
|
-
return char;
|
|
938
|
-
}
|
|
939
|
-
});
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
// src/diagnostics.ts
|
|
943
|
-
function createSpan(line, col, length, lineOffset) {
|
|
944
|
-
const startOffset = lineOffset + col - 1;
|
|
945
|
-
return {
|
|
946
|
-
start: { line, col, offset: startOffset },
|
|
947
|
-
end: { line, col: col + length, offset: startOffset + length }
|
|
948
|
-
};
|
|
949
|
-
}
|
|
950
|
-
|
|
951
|
-
// src/dialect.ts
|
|
952
|
-
function enforceDialect(root, config) {
|
|
953
|
-
const diagnostics = [];
|
|
954
|
-
if (root.idToken) {
|
|
955
|
-
diagnostics.push(
|
|
956
|
-
...evaluateToken(
|
|
957
|
-
{ kind: "id", token: root.idToken, span: root.idTokenSpan },
|
|
958
|
-
config.tokens.id
|
|
959
|
-
)
|
|
960
|
-
);
|
|
961
|
-
}
|
|
962
|
-
walkNodes(root.children, (occurrence) => {
|
|
963
|
-
const rule = config.tokens[occurrence.kind];
|
|
964
|
-
diagnostics.push(...evaluateToken(occurrence, rule));
|
|
965
|
-
});
|
|
966
|
-
return diagnostics;
|
|
967
|
-
}
|
|
968
|
-
function walkNodes(nodes, onToken) {
|
|
969
|
-
for (const node of nodes) {
|
|
970
|
-
if (node.type === "For") {
|
|
971
|
-
onFor(node, onToken);
|
|
972
|
-
walkNodes(node.body, onToken);
|
|
973
|
-
continue;
|
|
974
|
-
}
|
|
975
|
-
if (node.type === "Conditional") {
|
|
976
|
-
onConditional(node, onToken);
|
|
977
|
-
continue;
|
|
978
|
-
}
|
|
979
|
-
if (node.type === "Element" || node.type === "Component") {
|
|
980
|
-
walkNodes(node.children, onToken);
|
|
981
|
-
if (node.type === "Component" && node.slots) {
|
|
982
|
-
for (const slot of node.slots) {
|
|
983
|
-
walkNodes(slot.children, onToken);
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
continue;
|
|
987
|
-
}
|
|
988
|
-
}
|
|
989
|
-
}
|
|
990
|
-
function onFor(node, onToken) {
|
|
991
|
-
if (!node.token) {
|
|
992
|
-
return;
|
|
993
|
-
}
|
|
994
|
-
onToken({ kind: "for", token: node.token, span: node.tokenSpan });
|
|
995
|
-
}
|
|
996
|
-
function onConditional(node, onToken) {
|
|
997
|
-
for (const branch of node.branches) {
|
|
998
|
-
onBranch(branch, onToken);
|
|
999
|
-
walkNodes(branch.body, onToken);
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
|
-
function onBranch(branch, onToken) {
|
|
1003
|
-
if (!branch.token || !branch.kind) {
|
|
1004
|
-
return;
|
|
1005
|
-
}
|
|
1006
|
-
onToken({ kind: branch.kind, token: branch.token, span: branch.tokenSpan });
|
|
1007
|
-
}
|
|
1008
|
-
function evaluateToken(occurrence, rule) {
|
|
1009
|
-
const diagnostics = [];
|
|
1010
|
-
const used = occurrence.token;
|
|
1011
|
-
const preferred = rule.preferred;
|
|
1012
|
-
const isAllowed = rule.allow.includes(used);
|
|
1013
|
-
if (!isAllowed) {
|
|
1014
|
-
const severity = levelToSeverity(rule.onDisallowed);
|
|
1015
|
-
if (severity) {
|
|
1016
|
-
diagnostics.push(
|
|
1017
|
-
createDialectDiagnostic(
|
|
1018
|
-
"dialect.token.disallowed",
|
|
1019
|
-
severity,
|
|
1020
|
-
used,
|
|
1021
|
-
preferred,
|
|
1022
|
-
occurrence.span,
|
|
1023
|
-
`Token "${used}" is not allowed for ${occurrence.kind}. Preferred: "${preferred}".`
|
|
1024
|
-
)
|
|
1025
|
-
);
|
|
1026
|
-
}
|
|
1027
|
-
return diagnostics;
|
|
1028
|
-
}
|
|
1029
|
-
if (used !== preferred) {
|
|
1030
|
-
const severity = levelToSeverity(rule.onDisallowed);
|
|
1031
|
-
if (severity) {
|
|
1032
|
-
diagnostics.push(
|
|
1033
|
-
createDialectDiagnostic(
|
|
1034
|
-
"dialect.token.nonPreferred",
|
|
1035
|
-
severity,
|
|
1036
|
-
used,
|
|
1037
|
-
preferred,
|
|
1038
|
-
occurrence.span,
|
|
1039
|
-
`Token "${used}" is allowed but not preferred for ${occurrence.kind}. Preferred: "${preferred}".`
|
|
1040
|
-
)
|
|
1041
|
-
);
|
|
1042
|
-
}
|
|
1043
|
-
}
|
|
1044
|
-
return diagnostics;
|
|
1045
|
-
}
|
|
1046
|
-
function createDialectDiagnostic(code, severity, used, preferred, span, message) {
|
|
1047
|
-
const fix = span ? {
|
|
1048
|
-
range: span,
|
|
1049
|
-
replacementText: preferred
|
|
1050
|
-
} : void 0;
|
|
1051
|
-
return {
|
|
1052
|
-
severity,
|
|
1053
|
-
code,
|
|
1054
|
-
message: message.replace(/\\s+/g, " "),
|
|
1055
|
-
span,
|
|
1056
|
-
fix
|
|
1057
|
-
};
|
|
1058
|
-
}
|
|
1059
|
-
function levelToSeverity(level) {
|
|
1060
|
-
if (level === "off") {
|
|
1061
|
-
return null;
|
|
1062
|
-
}
|
|
1063
|
-
if (level === "error") {
|
|
1064
|
-
return "error";
|
|
1065
|
-
}
|
|
1066
|
-
return "warning";
|
|
1067
|
-
}
|
|
1068
|
-
|
|
1069
|
-
// src/props.ts
|
|
1070
|
-
var IGNORED_IDENTIFIERS2 = /* @__PURE__ */ new Set([
|
|
1071
|
-
"null",
|
|
1072
|
-
"undefined",
|
|
1073
|
-
"true",
|
|
1074
|
-
"false",
|
|
1075
|
-
"NaN",
|
|
1076
|
-
"Infinity",
|
|
1077
|
-
"this",
|
|
1078
|
-
"props"
|
|
1079
|
-
]);
|
|
1080
|
-
var RESERVED_KEYWORDS2 = /* @__PURE__ */ new Set([
|
|
1081
|
-
"await",
|
|
1082
|
-
"break",
|
|
1083
|
-
"case",
|
|
1084
|
-
"catch",
|
|
1085
|
-
"class",
|
|
1086
|
-
"const",
|
|
1087
|
-
"continue",
|
|
1088
|
-
"debugger",
|
|
1089
|
-
"default",
|
|
1090
|
-
"delete",
|
|
1091
|
-
"do",
|
|
1092
|
-
"else",
|
|
1093
|
-
"enum",
|
|
1094
|
-
"export",
|
|
1095
|
-
"extends",
|
|
1096
|
-
"false",
|
|
1097
|
-
"finally",
|
|
1098
|
-
"for",
|
|
1099
|
-
"function",
|
|
1100
|
-
"if",
|
|
1101
|
-
"import",
|
|
1102
|
-
"in",
|
|
1103
|
-
"instanceof",
|
|
1104
|
-
"let",
|
|
1105
|
-
"new",
|
|
1106
|
-
"null",
|
|
1107
|
-
"return",
|
|
1108
|
-
"super",
|
|
1109
|
-
"switch",
|
|
1110
|
-
"this",
|
|
1111
|
-
"throw",
|
|
1112
|
-
"true",
|
|
1113
|
-
"try",
|
|
1114
|
-
"typeof",
|
|
1115
|
-
"var",
|
|
1116
|
-
"void",
|
|
1117
|
-
"while",
|
|
1118
|
-
"with",
|
|
1119
|
-
"yield"
|
|
1120
|
-
]);
|
|
1121
|
-
function enforceProps(root, propsConfig) {
|
|
1122
|
-
const diagnostics = [];
|
|
1123
|
-
const declaredProps = /* @__PURE__ */ new Map();
|
|
1124
|
-
const usedLocal = /* @__PURE__ */ new Map();
|
|
1125
|
-
const usedNamespace = /* @__PURE__ */ new Map();
|
|
1126
|
-
const usedAny = /* @__PURE__ */ new Set();
|
|
1127
|
-
const missingReported = /* @__PURE__ */ new Set();
|
|
1128
|
-
const localStyleReported = /* @__PURE__ */ new Set();
|
|
1129
|
-
const namespaceStyleReported = /* @__PURE__ */ new Set();
|
|
1130
|
-
if (root.props?.fields) {
|
|
1131
|
-
for (const field of root.props.fields) {
|
|
1132
|
-
declaredProps.set(field.name, field);
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1135
|
-
const preferStyle = propsConfig.preferAccessStyle;
|
|
1136
|
-
const flagLocalStyle = !propsConfig.allowDeclaredLocals || preferStyle === "namespace";
|
|
1137
|
-
const flagNamespaceStyle = !propsConfig.allowPropsNamespace || preferStyle === "locals";
|
|
1138
|
-
const walkNodes2 = (nodes, locals) => {
|
|
1139
|
-
for (const node of nodes) {
|
|
1140
|
-
if (node.type === "Conditional") {
|
|
1141
|
-
handleConditional(node, locals);
|
|
1142
|
-
continue;
|
|
1143
|
-
}
|
|
1144
|
-
if (node.type === "For") {
|
|
1145
|
-
handleFor(node, locals);
|
|
1146
|
-
continue;
|
|
1147
|
-
}
|
|
1148
|
-
if (node.type === "Expression") {
|
|
1149
|
-
handleExpression(node.value, node.span, locals);
|
|
1150
|
-
continue;
|
|
1151
|
-
}
|
|
1152
|
-
if (node.type === "JSXPassthrough") {
|
|
1153
|
-
handleExpression(node.expression, node.span, locals);
|
|
1154
|
-
continue;
|
|
1155
|
-
}
|
|
1156
|
-
if (node.type === "Text") {
|
|
1157
|
-
handleText(node.parts, locals);
|
|
1158
|
-
continue;
|
|
1159
|
-
}
|
|
1160
|
-
if (node.type === "Element") {
|
|
1161
|
-
handleElement(node, locals);
|
|
1162
|
-
continue;
|
|
1163
|
-
}
|
|
1164
|
-
if (node.type === "Component") {
|
|
1165
|
-
handleComponent(node, locals);
|
|
1166
|
-
continue;
|
|
1167
|
-
}
|
|
1168
|
-
}
|
|
1169
|
-
};
|
|
1170
|
-
const handleConditional = (node, locals) => {
|
|
1171
|
-
for (const branch of node.branches) {
|
|
1172
|
-
if (branch.test) {
|
|
1173
|
-
handleExpression(branch.test, branch.testSpan, locals);
|
|
1174
|
-
}
|
|
1175
|
-
walkNodes2(branch.body, locals);
|
|
1176
|
-
}
|
|
1177
|
-
};
|
|
1178
|
-
const handleFor = (node, locals) => {
|
|
1179
|
-
handleExpression(node.arrayExpr, node.arrayExprSpan, locals);
|
|
1180
|
-
const nextLocals = new Set(locals);
|
|
1181
|
-
nextLocals.add(node.itemName);
|
|
1182
|
-
walkNodes2(node.body, nextLocals);
|
|
1183
|
-
};
|
|
1184
|
-
const handleElement = (node, locals) => {
|
|
1185
|
-
if (node.guard) {
|
|
1186
|
-
handleExpression(node.guard, node.guardSpan, locals);
|
|
1187
|
-
}
|
|
1188
|
-
handleAttributes(node.attributes, locals);
|
|
1189
|
-
walkNodes2(node.children, locals);
|
|
1190
|
-
};
|
|
1191
|
-
const handleComponent = (node, locals) => {
|
|
1192
|
-
if (node.guard) {
|
|
1193
|
-
handleExpression(node.guard, node.guardSpan, locals);
|
|
1194
|
-
}
|
|
1195
|
-
handleAttributes(node.attributes, locals);
|
|
1196
|
-
if (node.slots) {
|
|
1197
|
-
for (const slot of node.slots) {
|
|
1198
|
-
walkNodes2(slot.children, locals);
|
|
1199
|
-
}
|
|
1200
|
-
}
|
|
1201
|
-
walkNodes2(node.children, locals);
|
|
1202
|
-
};
|
|
1203
|
-
const handleText = (parts, locals) => {
|
|
1204
|
-
for (const part of parts) {
|
|
1205
|
-
if (part.type === "expr") {
|
|
1206
|
-
handleExpression(part.value, part.span, locals);
|
|
1207
|
-
}
|
|
1208
|
-
}
|
|
1209
|
-
};
|
|
1210
|
-
const handleAttributes = (attributes, locals) => {
|
|
1211
|
-
for (const attr of attributes) {
|
|
1212
|
-
if (!attr.value) continue;
|
|
1213
|
-
const trimmed = attr.value.trim();
|
|
1214
|
-
if (!trimmed || trimmed.startsWith("'") || trimmed.startsWith('"')) {
|
|
1215
|
-
continue;
|
|
1216
|
-
}
|
|
1217
|
-
handleExpression(trimmed, void 0, locals);
|
|
1218
|
-
}
|
|
1219
|
-
};
|
|
1220
|
-
const handleExpression = (expression, span, locals) => {
|
|
1221
|
-
const occurrences = scanExpression(expression);
|
|
1222
|
-
for (const occurrence of occurrences) {
|
|
1223
|
-
const name = occurrence.name;
|
|
1224
|
-
if (occurrence.kind === "local" && locals.has(name)) {
|
|
1225
|
-
continue;
|
|
1226
|
-
}
|
|
1227
|
-
if (shouldIgnoreIdentifier2(name)) {
|
|
1228
|
-
continue;
|
|
1229
|
-
}
|
|
1230
|
-
const usageSpan = span ? offsetSpan(span, occurrence.index, occurrence.length) : void 0;
|
|
1231
|
-
if (occurrence.kind === "namespace") {
|
|
1232
|
-
recordUsage(usedNamespace, name, usageSpan);
|
|
1233
|
-
usedAny.add(name);
|
|
1234
|
-
if (propsConfig.requireDeclarationForLocals && !declaredProps.has(name) && !missingReported.has(name)) {
|
|
1235
|
-
const severity = levelToSeverity2(propsConfig.diagnostics.missingDeclaration);
|
|
1236
|
-
if (severity) {
|
|
1237
|
-
diagnostics.push(createMissingDeclarationDiagnostic(name, severity, usageSpan));
|
|
1238
|
-
missingReported.add(name);
|
|
1239
|
-
}
|
|
1240
|
-
}
|
|
1241
|
-
if (flagNamespaceStyle && !namespaceStyleReported.has(name)) {
|
|
1242
|
-
const severity = levelToSeverity2(propsConfig.diagnostics.style);
|
|
1243
|
-
if (severity) {
|
|
1244
|
-
diagnostics.push(
|
|
1245
|
-
createStyleDiagnostic(
|
|
1246
|
-
name,
|
|
1247
|
-
"namespace",
|
|
1248
|
-
severity,
|
|
1249
|
-
usageSpan,
|
|
1250
|
-
propsConfig.allowPropsNamespace
|
|
1251
|
-
)
|
|
1252
|
-
);
|
|
1253
|
-
namespaceStyleReported.add(name);
|
|
1254
|
-
}
|
|
1255
|
-
}
|
|
1256
|
-
continue;
|
|
1257
|
-
}
|
|
1258
|
-
recordUsage(usedLocal, name, usageSpan);
|
|
1259
|
-
usedAny.add(name);
|
|
1260
|
-
if (propsConfig.requireDeclarationForLocals && !declaredProps.has(name) && !missingReported.has(name)) {
|
|
1261
|
-
const severity = levelToSeverity2(propsConfig.diagnostics.missingDeclaration);
|
|
1262
|
-
if (severity) {
|
|
1263
|
-
diagnostics.push(createMissingDeclarationDiagnostic(name, severity, usageSpan));
|
|
1264
|
-
missingReported.add(name);
|
|
1265
|
-
}
|
|
1266
|
-
}
|
|
1267
|
-
if (flagLocalStyle && !localStyleReported.has(name)) {
|
|
1268
|
-
const severity = levelToSeverity2(propsConfig.diagnostics.style);
|
|
1269
|
-
if (severity) {
|
|
1270
|
-
diagnostics.push(
|
|
1271
|
-
createStyleDiagnostic(name, "local", severity, usageSpan, propsConfig.allowDeclaredLocals)
|
|
1272
|
-
);
|
|
1273
|
-
localStyleReported.add(name);
|
|
1274
|
-
}
|
|
1275
|
-
}
|
|
1276
|
-
}
|
|
1277
|
-
};
|
|
1278
|
-
walkNodes2(root.children, /* @__PURE__ */ new Set());
|
|
1279
|
-
if (root.props?.fields) {
|
|
1280
|
-
for (const field of root.props.fields) {
|
|
1281
|
-
if (!usedAny.has(field.name)) {
|
|
1282
|
-
const severity = levelToSeverity2(propsConfig.diagnostics.unusedDeclaration);
|
|
1283
|
-
if (severity) {
|
|
1284
|
-
diagnostics.push({
|
|
1285
|
-
severity,
|
|
1286
|
-
code: "props.unusedDeclaration",
|
|
1287
|
-
message: `Prop "${field.name}" is declared but never used.`,
|
|
1288
|
-
span: field.span
|
|
1289
|
-
});
|
|
1290
|
-
}
|
|
1291
|
-
}
|
|
1292
|
-
}
|
|
1293
|
-
}
|
|
1294
|
-
if (propsConfig.requirePropsBlockWhen.enabled && !root.props && usedAny.size >= propsConfig.requirePropsBlockWhen.minUniquePropsUsed) {
|
|
1295
|
-
const severity = levelToSeverity2(propsConfig.requirePropsBlockWhen.severity);
|
|
1296
|
-
if (severity) {
|
|
1297
|
-
diagnostics.push({
|
|
1298
|
-
severity,
|
|
1299
|
-
code: "props.block.recommendedOrRequired",
|
|
1300
|
-
message: `Props block recommended: ${usedAny.size} unique prop${usedAny.size === 1 ? "" : "s"} used.`
|
|
1301
|
-
});
|
|
1302
|
-
}
|
|
1303
|
-
}
|
|
1304
|
-
return diagnostics;
|
|
1305
|
-
}
|
|
1306
|
-
function createMissingDeclarationDiagnostic(name, severity, span) {
|
|
1307
|
-
return {
|
|
1308
|
-
severity,
|
|
1309
|
-
code: "props.missingDeclaration",
|
|
1310
|
-
message: `Prop \`${name}\` is used but not declared in \`#props\`.`,
|
|
1311
|
-
span,
|
|
1312
|
-
data: {
|
|
1313
|
-
kind: "addPropDeclaration",
|
|
1314
|
-
propName: name
|
|
1315
|
-
}
|
|
1316
|
-
};
|
|
1317
|
-
}
|
|
1318
|
-
function createStyleDiagnostic(name, kind, severity, span, allowed) {
|
|
1319
|
-
if (kind === "namespace") {
|
|
1320
|
-
const message2 = allowed ? `props.${name} is allowed but not preferred; use "${name}" instead.` : `props.${name} is disabled; use "${name}" instead.`;
|
|
1321
|
-
return {
|
|
1322
|
-
severity,
|
|
1323
|
-
code: "props.style.nonPreferred",
|
|
1324
|
-
message: message2,
|
|
1325
|
-
span
|
|
1326
|
-
};
|
|
1327
|
-
}
|
|
1328
|
-
const message = allowed ? `"${name}" is allowed but not preferred; use props.${name} instead.` : `"${name}" is disabled; use props.${name} instead.`;
|
|
1329
|
-
return {
|
|
1330
|
-
severity,
|
|
1331
|
-
code: "props.style.nonPreferred",
|
|
1332
|
-
message,
|
|
1333
|
-
span
|
|
1334
|
-
};
|
|
1335
|
-
}
|
|
1336
|
-
function recordUsage(map, name, span) {
|
|
1337
|
-
const existing = map.get(name);
|
|
1338
|
-
if (existing) {
|
|
1339
|
-
existing.count += 1;
|
|
1340
|
-
return;
|
|
1341
|
-
}
|
|
1342
|
-
map.set(name, { count: 1, span });
|
|
1343
|
-
}
|
|
1344
|
-
function scanExpression(expression) {
|
|
1345
|
-
const occurrences = [];
|
|
1346
|
-
let i = 0;
|
|
1347
|
-
let state = "code";
|
|
1348
|
-
while (i < expression.length) {
|
|
1349
|
-
const ch = expression[i];
|
|
1350
|
-
if (state === "code") {
|
|
1351
|
-
if (ch === "'" || ch === '"') {
|
|
1352
|
-
state = ch === "'" ? "single" : "double";
|
|
1353
|
-
i++;
|
|
1354
|
-
continue;
|
|
1355
|
-
}
|
|
1356
|
-
if (ch === "`") {
|
|
1357
|
-
state = "template";
|
|
1358
|
-
i++;
|
|
1359
|
-
continue;
|
|
1360
|
-
}
|
|
1361
|
-
if (ch === "/" && expression[i + 1] === "/") {
|
|
1362
|
-
state = "line";
|
|
1363
|
-
i += 2;
|
|
1364
|
-
continue;
|
|
1365
|
-
}
|
|
1366
|
-
if (ch === "/" && expression[i + 1] === "*") {
|
|
1367
|
-
state = "block";
|
|
1368
|
-
i += 2;
|
|
1369
|
-
continue;
|
|
1370
|
-
}
|
|
1371
|
-
if (isIdentifierStart2(ch)) {
|
|
1372
|
-
const start = i;
|
|
1373
|
-
i++;
|
|
1374
|
-
while (i < expression.length && isIdentifierPart2(expression[i])) {
|
|
1375
|
-
i++;
|
|
1376
|
-
}
|
|
1377
|
-
const name = expression.slice(start, i);
|
|
1378
|
-
const prevNonSpace = findPreviousNonSpace2(expression, start - 1);
|
|
1379
|
-
if (name === "props" && prevNonSpace !== ".") {
|
|
1380
|
-
const namespace = readNamespaceAccess(expression, i);
|
|
1381
|
-
if (namespace) {
|
|
1382
|
-
occurrences.push({
|
|
1383
|
-
name: namespace.name,
|
|
1384
|
-
kind: "namespace",
|
|
1385
|
-
index: namespace.index,
|
|
1386
|
-
length: namespace.name.length
|
|
1387
|
-
});
|
|
1388
|
-
i = namespace.endIndex;
|
|
1389
|
-
continue;
|
|
1390
|
-
}
|
|
1391
|
-
}
|
|
1392
|
-
if (prevNonSpace !== ".") {
|
|
1393
|
-
occurrences.push({ name, kind: "local", index: start, length: name.length });
|
|
1394
|
-
}
|
|
1395
|
-
continue;
|
|
1396
|
-
}
|
|
1397
|
-
i++;
|
|
1398
|
-
continue;
|
|
1399
|
-
}
|
|
1400
|
-
if (state === "line") {
|
|
1401
|
-
if (ch === "\n") {
|
|
1402
|
-
state = "code";
|
|
1403
|
-
}
|
|
1404
|
-
i++;
|
|
1405
|
-
continue;
|
|
1406
|
-
}
|
|
1407
|
-
if (state === "block") {
|
|
1408
|
-
if (ch === "*" && expression[i + 1] === "/") {
|
|
1409
|
-
state = "code";
|
|
1410
|
-
i += 2;
|
|
1411
|
-
continue;
|
|
1412
|
-
}
|
|
1413
|
-
i++;
|
|
1414
|
-
continue;
|
|
1415
|
-
}
|
|
1416
|
-
if (state === "single") {
|
|
1417
|
-
if (ch === "\\") {
|
|
1418
|
-
i += 2;
|
|
1419
|
-
continue;
|
|
1420
|
-
}
|
|
1421
|
-
if (ch === "'") {
|
|
1422
|
-
state = "code";
|
|
1423
|
-
}
|
|
1424
|
-
i++;
|
|
1425
|
-
continue;
|
|
1426
|
-
}
|
|
1427
|
-
if (state === "double") {
|
|
1428
|
-
if (ch === "\\") {
|
|
1429
|
-
i += 2;
|
|
1430
|
-
continue;
|
|
1431
|
-
}
|
|
1432
|
-
if (ch === '"') {
|
|
1433
|
-
state = "code";
|
|
1434
|
-
}
|
|
1435
|
-
i++;
|
|
1436
|
-
continue;
|
|
1437
|
-
}
|
|
1438
|
-
if (state === "template") {
|
|
1439
|
-
if (ch === "\\") {
|
|
1440
|
-
i += 2;
|
|
1441
|
-
continue;
|
|
1442
|
-
}
|
|
1443
|
-
if (ch === "`") {
|
|
1444
|
-
state = "code";
|
|
1445
|
-
i++;
|
|
1446
|
-
continue;
|
|
1447
|
-
}
|
|
1448
|
-
i++;
|
|
1449
|
-
continue;
|
|
1450
|
-
}
|
|
1183
|
+
}
|
|
1184
|
+
return char;
|
|
1451
1185
|
}
|
|
1452
|
-
return occurrences;
|
|
1453
1186
|
}
|
|
1454
|
-
function
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
}
|
|
1459
|
-
if (expression[i] === "?") {
|
|
1460
|
-
if (expression[i + 1] !== ".") {
|
|
1461
|
-
return null;
|
|
1462
|
-
}
|
|
1463
|
-
i += 2;
|
|
1464
|
-
} else if (expression[i] === ".") {
|
|
1465
|
-
i++;
|
|
1466
|
-
} else {
|
|
1467
|
-
return null;
|
|
1468
|
-
}
|
|
1469
|
-
while (i < expression.length && /\s/.test(expression[i])) {
|
|
1470
|
-
i++;
|
|
1471
|
-
}
|
|
1472
|
-
if (!isIdentifierStart2(expression[i])) {
|
|
1473
|
-
return null;
|
|
1187
|
+
function buildClassAliasEnvironment2(decl) {
|
|
1188
|
+
const env = /* @__PURE__ */ new Map();
|
|
1189
|
+
if (!decl) {
|
|
1190
|
+
return env;
|
|
1474
1191
|
}
|
|
1475
|
-
const
|
|
1476
|
-
|
|
1477
|
-
while (i < expression.length && isIdentifierPart2(expression[i])) {
|
|
1478
|
-
i++;
|
|
1192
|
+
for (const alias of decl.aliases) {
|
|
1193
|
+
env.set(alias.name, alias.classes);
|
|
1479
1194
|
}
|
|
1480
|
-
return
|
|
1481
|
-
name: expression.slice(propStart, i),
|
|
1482
|
-
index: propStart,
|
|
1483
|
-
endIndex: i
|
|
1484
|
-
};
|
|
1195
|
+
return env;
|
|
1485
1196
|
}
|
|
1486
|
-
function
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1197
|
+
function expandClasses2(classes, aliasEnv) {
|
|
1198
|
+
const result = [];
|
|
1199
|
+
for (const cls of classes) {
|
|
1200
|
+
const match = cls.match(/^\$([A-Za-z_][A-Za-z0-9_]*)$/);
|
|
1201
|
+
if (!match) {
|
|
1202
|
+
result.push(cls);
|
|
1203
|
+
continue;
|
|
1204
|
+
}
|
|
1205
|
+
const aliasClasses = aliasEnv.get(match[1]);
|
|
1206
|
+
if (!aliasClasses) {
|
|
1207
|
+
continue;
|
|
1491
1208
|
}
|
|
1209
|
+
result.push(...aliasClasses);
|
|
1492
1210
|
}
|
|
1493
|
-
return
|
|
1494
|
-
}
|
|
1495
|
-
function isIdentifierStart2(ch) {
|
|
1496
|
-
return /[A-Za-z_$]/.test(ch);
|
|
1497
|
-
}
|
|
1498
|
-
function isIdentifierPart2(ch) {
|
|
1499
|
-
return /[A-Za-z0-9_$]/.test(ch);
|
|
1211
|
+
return result;
|
|
1500
1212
|
}
|
|
1501
|
-
function
|
|
1502
|
-
return
|
|
1213
|
+
function escapeStaticText(value) {
|
|
1214
|
+
return value.replace(/[&<>{}]/g, (char) => {
|
|
1215
|
+
switch (char) {
|
|
1216
|
+
case "&":
|
|
1217
|
+
return "&";
|
|
1218
|
+
case "<":
|
|
1219
|
+
return "<";
|
|
1220
|
+
case ">":
|
|
1221
|
+
return ">";
|
|
1222
|
+
case "{":
|
|
1223
|
+
return "{";
|
|
1224
|
+
case "}":
|
|
1225
|
+
return "}";
|
|
1226
|
+
default:
|
|
1227
|
+
return char;
|
|
1228
|
+
}
|
|
1229
|
+
});
|
|
1503
1230
|
}
|
|
1504
|
-
function
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1231
|
+
function escapeAttributeValue(value) {
|
|
1232
|
+
return value.replace(/["&<>]/g, (char) => {
|
|
1233
|
+
switch (char) {
|
|
1234
|
+
case "&":
|
|
1235
|
+
return "&";
|
|
1236
|
+
case "<":
|
|
1237
|
+
return "<";
|
|
1238
|
+
case ">":
|
|
1239
|
+
return ">";
|
|
1240
|
+
case '"':
|
|
1241
|
+
return """;
|
|
1242
|
+
default:
|
|
1243
|
+
return char;
|
|
1244
|
+
}
|
|
1245
|
+
});
|
|
1512
1246
|
}
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1247
|
+
|
|
1248
|
+
// src/diagnostics.ts
|
|
1249
|
+
function createSpan(line, col, length, lineOffset) {
|
|
1250
|
+
const startOffset = lineOffset + col - 1;
|
|
1516
1251
|
return {
|
|
1517
|
-
start: {
|
|
1518
|
-
|
|
1519
|
-
col: startCol,
|
|
1520
|
-
offset: startOffset
|
|
1521
|
-
},
|
|
1522
|
-
end: {
|
|
1523
|
-
line: base.start.line,
|
|
1524
|
-
col: startCol + length,
|
|
1525
|
-
offset: startOffset + length
|
|
1526
|
-
}
|
|
1252
|
+
start: { line, col, offset: startOffset },
|
|
1253
|
+
end: { line, col: col + length, offset: startOffset + length }
|
|
1527
1254
|
};
|
|
1528
1255
|
}
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
}
|
|
1256
|
+
|
|
1257
|
+
// src/dialect.ts
|
|
1258
|
+
function enforceDialect(root, config) {
|
|
1533
1259
|
const diagnostics = [];
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
message: `Identifier "${name}" is used without "props." but is not declared in #props. Declare "${name}" in #props or use "props.${name}".`
|
|
1542
|
-
});
|
|
1543
|
-
}
|
|
1544
|
-
}
|
|
1545
|
-
for (const [name, decl] of declaredProps) {
|
|
1546
|
-
const usedAsBare = allUsage.usedBareAliases.has(name);
|
|
1547
|
-
const usedAsProps = allUsage.usedPropsDot.has(name);
|
|
1548
|
-
if (!usedAsBare && !usedAsProps) {
|
|
1549
|
-
diagnostics.push({
|
|
1550
|
-
severity: "warning",
|
|
1551
|
-
code: "props.unusedDeclaration",
|
|
1552
|
-
message: `Prop "${name}" is declared in #props but never used in this template.`,
|
|
1553
|
-
span: decl.span
|
|
1554
|
-
});
|
|
1555
|
-
}
|
|
1556
|
-
}
|
|
1557
|
-
for (const name of allUsage.usedPropsDot) {
|
|
1558
|
-
if (declaredProps.has(name)) {
|
|
1559
|
-
diagnostics.push({
|
|
1560
|
-
severity: "warning",
|
|
1561
|
-
code: "props.style.nonPreferred",
|
|
1562
|
-
message: `"props.${name}" is unnecessary because "${name}" is declared in #props. Use "{${name}}" instead.`
|
|
1563
|
-
});
|
|
1564
|
-
}
|
|
1565
|
-
}
|
|
1566
|
-
for (const [name, decl] of declaredProps) {
|
|
1567
|
-
const isCallable = decl.kind === "callable";
|
|
1568
|
-
const usedAsCall = allUsage.callSitesBare.has(name);
|
|
1569
|
-
const usedAsValue = allUsage.usedBareAliases.has(name) && !usedAsCall;
|
|
1570
|
-
if (isCallable && usedAsValue) {
|
|
1571
|
-
diagnostics.push({
|
|
1572
|
-
severity: "warning",
|
|
1573
|
-
code: "props.style.nonPreferred",
|
|
1574
|
-
message: `"${name}" is declared as callable in #props (${name}()) but used as a value.`
|
|
1575
|
-
});
|
|
1576
|
-
} else if (!isCallable && usedAsCall) {
|
|
1577
|
-
diagnostics.push({
|
|
1578
|
-
severity: "warning",
|
|
1579
|
-
code: "props.style.nonPreferred",
|
|
1580
|
-
message: `"${name}" is declared as a value in #props but used as a function call.`
|
|
1581
|
-
});
|
|
1582
|
-
}
|
|
1260
|
+
if (root.idToken) {
|
|
1261
|
+
diagnostics.push(
|
|
1262
|
+
...evaluateToken(
|
|
1263
|
+
{ kind: "id", token: root.idToken, span: root.idTokenSpan },
|
|
1264
|
+
config.tokens.id
|
|
1265
|
+
)
|
|
1266
|
+
);
|
|
1583
1267
|
}
|
|
1268
|
+
walkNodes(root.children, (occurrence) => {
|
|
1269
|
+
const rule = config.tokens[occurrence.kind];
|
|
1270
|
+
diagnostics.push(...evaluateToken(occurrence, rule));
|
|
1271
|
+
});
|
|
1584
1272
|
return diagnostics;
|
|
1585
1273
|
}
|
|
1586
|
-
function
|
|
1587
|
-
const
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
callSitesPropsDot: /* @__PURE__ */ new Set()
|
|
1593
|
-
};
|
|
1594
|
-
const env = createTemplateEnv(root.propsDecls);
|
|
1595
|
-
function mergeResult(result) {
|
|
1596
|
-
for (const name of result.usedBare) {
|
|
1597
|
-
usage.usedBare.add(name);
|
|
1598
|
-
}
|
|
1599
|
-
for (const name of result.rewrittenAliases) {
|
|
1600
|
-
usage.usedBareAliases.add(name);
|
|
1601
|
-
}
|
|
1602
|
-
for (const name of result.usedPropsDot) {
|
|
1603
|
-
usage.usedPropsDot.add(name);
|
|
1274
|
+
function walkNodes(nodes, onToken) {
|
|
1275
|
+
for (const node of nodes) {
|
|
1276
|
+
if (node.type === "For") {
|
|
1277
|
+
onFor(node, onToken);
|
|
1278
|
+
walkNodes(node.body, onToken);
|
|
1279
|
+
continue;
|
|
1604
1280
|
}
|
|
1605
|
-
|
|
1606
|
-
|
|
1281
|
+
if (node.type === "Conditional") {
|
|
1282
|
+
onConditional(node, onToken);
|
|
1283
|
+
continue;
|
|
1607
1284
|
}
|
|
1608
|
-
|
|
1609
|
-
|
|
1285
|
+
if (node.type === "Element" || node.type === "Component") {
|
|
1286
|
+
walkNodes(node.children, onToken);
|
|
1287
|
+
if (node.type === "Component" && node.slots) {
|
|
1288
|
+
for (const slot of node.slots) {
|
|
1289
|
+
walkNodes(slot.children, onToken);
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
continue;
|
|
1610
1293
|
}
|
|
1611
1294
|
}
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1295
|
+
}
|
|
1296
|
+
function onFor(node, onToken) {
|
|
1297
|
+
if (!node.token) {
|
|
1298
|
+
return;
|
|
1616
1299
|
}
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1300
|
+
onToken({ kind: "for", token: node.token, span: node.tokenSpan });
|
|
1301
|
+
}
|
|
1302
|
+
function onConditional(node, onToken) {
|
|
1303
|
+
for (const branch of node.branches) {
|
|
1304
|
+
onBranch(branch, onToken);
|
|
1305
|
+
walkNodes(branch.body, onToken);
|
|
1621
1306
|
}
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
if (part.type === "expr") {
|
|
1627
|
-
analyzeExpression(part.value);
|
|
1628
|
-
}
|
|
1629
|
-
}
|
|
1630
|
-
break;
|
|
1631
|
-
case "Expression":
|
|
1632
|
-
analyzeExpression(node.value);
|
|
1633
|
-
break;
|
|
1634
|
-
case "JSXPassthrough":
|
|
1635
|
-
analyzeJsxExpression(node.expression);
|
|
1636
|
-
break;
|
|
1637
|
-
case "Element":
|
|
1638
|
-
if (node.guard) {
|
|
1639
|
-
analyzeExpression(node.guard);
|
|
1640
|
-
}
|
|
1641
|
-
for (const attr of node.attributes) {
|
|
1642
|
-
if (attr.value) {
|
|
1643
|
-
analyzeAttributeValue(attr.value);
|
|
1644
|
-
}
|
|
1645
|
-
}
|
|
1646
|
-
for (const child of node.children) {
|
|
1647
|
-
walkNode(child);
|
|
1648
|
-
}
|
|
1649
|
-
break;
|
|
1650
|
-
case "Component":
|
|
1651
|
-
if (node.guard) {
|
|
1652
|
-
analyzeExpression(node.guard);
|
|
1653
|
-
}
|
|
1654
|
-
for (const attr of node.attributes) {
|
|
1655
|
-
if (attr.value) {
|
|
1656
|
-
analyzeAttributeValue(attr.value);
|
|
1657
|
-
}
|
|
1658
|
-
}
|
|
1659
|
-
if (node.slots) {
|
|
1660
|
-
for (const slot of node.slots) {
|
|
1661
|
-
for (const child of slot.children) {
|
|
1662
|
-
walkNode(child);
|
|
1663
|
-
}
|
|
1664
|
-
}
|
|
1665
|
-
}
|
|
1666
|
-
for (const child of node.children) {
|
|
1667
|
-
walkNode(child);
|
|
1668
|
-
}
|
|
1669
|
-
break;
|
|
1670
|
-
case "Conditional":
|
|
1671
|
-
for (const branch of node.branches) {
|
|
1672
|
-
if (branch.test) {
|
|
1673
|
-
analyzeExpression(branch.test);
|
|
1674
|
-
}
|
|
1675
|
-
for (const child of branch.body) {
|
|
1676
|
-
walkNode(child);
|
|
1677
|
-
}
|
|
1678
|
-
}
|
|
1679
|
-
break;
|
|
1680
|
-
case "For":
|
|
1681
|
-
analyzeExpression(node.arrayExpr);
|
|
1682
|
-
for (const child of node.body) {
|
|
1683
|
-
walkNode(child);
|
|
1684
|
-
}
|
|
1685
|
-
break;
|
|
1686
|
-
}
|
|
1307
|
+
}
|
|
1308
|
+
function onBranch(branch, onToken) {
|
|
1309
|
+
if (!branch.token || !branch.kind) {
|
|
1310
|
+
return;
|
|
1687
1311
|
}
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1312
|
+
onToken({ kind: branch.kind, token: branch.token, span: branch.tokenSpan });
|
|
1313
|
+
}
|
|
1314
|
+
function evaluateToken(occurrence, rule) {
|
|
1315
|
+
const diagnostics = [];
|
|
1316
|
+
const used = occurrence.token;
|
|
1317
|
+
const preferred = rule.preferred;
|
|
1318
|
+
const isAllowed = rule.allow.includes(used);
|
|
1319
|
+
if (!isAllowed) {
|
|
1320
|
+
const severity = levelToSeverity(rule.onDisallowed);
|
|
1321
|
+
if (severity) {
|
|
1322
|
+
diagnostics.push(
|
|
1323
|
+
createDialectDiagnostic(
|
|
1324
|
+
"dialect.token.disallowed",
|
|
1325
|
+
severity,
|
|
1326
|
+
used,
|
|
1327
|
+
preferred,
|
|
1328
|
+
occurrence.span,
|
|
1329
|
+
`Token "${used}" is not allowed for ${occurrence.kind}. Preferred: "${preferred}".`
|
|
1330
|
+
)
|
|
1331
|
+
);
|
|
1698
1332
|
}
|
|
1333
|
+
return diagnostics;
|
|
1699
1334
|
}
|
|
1700
|
-
|
|
1701
|
-
|
|
1335
|
+
if (used !== preferred) {
|
|
1336
|
+
const severity = levelToSeverity(rule.onDisallowed);
|
|
1337
|
+
if (severity) {
|
|
1338
|
+
diagnostics.push(
|
|
1339
|
+
createDialectDiagnostic(
|
|
1340
|
+
"dialect.token.nonPreferred",
|
|
1341
|
+
severity,
|
|
1342
|
+
used,
|
|
1343
|
+
preferred,
|
|
1344
|
+
occurrence.span,
|
|
1345
|
+
`Token "${used}" is allowed but not preferred for ${occurrence.kind}. Preferred: "${preferred}".`
|
|
1346
|
+
)
|
|
1347
|
+
);
|
|
1348
|
+
}
|
|
1702
1349
|
}
|
|
1703
|
-
return
|
|
1350
|
+
return diagnostics;
|
|
1351
|
+
}
|
|
1352
|
+
function createDialectDiagnostic(code, severity, used, preferred, span, message) {
|
|
1353
|
+
const fix = span ? {
|
|
1354
|
+
range: span,
|
|
1355
|
+
replacementText: preferred
|
|
1356
|
+
} : void 0;
|
|
1357
|
+
return {
|
|
1358
|
+
severity,
|
|
1359
|
+
code,
|
|
1360
|
+
message: message.replace(/\\s+/g, " "),
|
|
1361
|
+
span,
|
|
1362
|
+
fix
|
|
1363
|
+
};
|
|
1704
1364
|
}
|
|
1705
|
-
function
|
|
1706
|
-
|
|
1365
|
+
function levelToSeverity(level) {
|
|
1366
|
+
if (level === "off") {
|
|
1367
|
+
return null;
|
|
1368
|
+
}
|
|
1369
|
+
if (level === "error") {
|
|
1370
|
+
return "error";
|
|
1371
|
+
}
|
|
1372
|
+
return "warning";
|
|
1707
1373
|
}
|
|
1708
1374
|
|
|
1709
1375
|
// src/parser.ts
|
|
@@ -1883,7 +1549,7 @@ function parseTemplateBlock(lines, lineOffsets, startIndex, endIndex, options) {
|
|
|
1883
1549
|
const diagnostics = [];
|
|
1884
1550
|
const root = { type: "Root", children: [] };
|
|
1885
1551
|
const stack = [{ node: root, level: -1 }];
|
|
1886
|
-
let
|
|
1552
|
+
let inputsBlockLevel = null;
|
|
1887
1553
|
let classesBlockLevel = null;
|
|
1888
1554
|
let sawTopLevelTemplateNode = false;
|
|
1889
1555
|
const conditionalChains = /* @__PURE__ */ new Map();
|
|
@@ -1925,19 +1591,19 @@ function parseTemplateBlock(lines, lineOffsets, startIndex, endIndex, options) {
|
|
|
1925
1591
|
continue;
|
|
1926
1592
|
}
|
|
1927
1593
|
let level = indent / 2;
|
|
1928
|
-
if (
|
|
1929
|
-
|
|
1594
|
+
if (inputsBlockLevel !== null && level <= inputsBlockLevel) {
|
|
1595
|
+
inputsBlockLevel = null;
|
|
1930
1596
|
}
|
|
1931
1597
|
if (classesBlockLevel !== null && level <= classesBlockLevel) {
|
|
1932
1598
|
classesBlockLevel = null;
|
|
1933
1599
|
}
|
|
1934
|
-
const
|
|
1600
|
+
const isInInputsBlock = inputsBlockLevel !== null && level > inputsBlockLevel;
|
|
1935
1601
|
const isInClassesBlock = classesBlockLevel !== null && level > classesBlockLevel;
|
|
1936
1602
|
while (stack.length > 1 && stack[stack.length - 1].level >= level) {
|
|
1937
1603
|
stack.pop();
|
|
1938
1604
|
}
|
|
1939
1605
|
const parentLevel = stack[stack.length - 1].level;
|
|
1940
|
-
if (level > parentLevel + 1 && !
|
|
1606
|
+
if (level > parentLevel + 1 && !isInInputsBlock && !isInClassesBlock) {
|
|
1941
1607
|
pushDiag(
|
|
1942
1608
|
diagnostics,
|
|
1943
1609
|
"COLLIE003",
|
|
@@ -1983,48 +1649,35 @@ function parseTemplateBlock(lines, lineOffsets, startIndex, endIndex, options) {
|
|
|
1983
1649
|
}
|
|
1984
1650
|
continue;
|
|
1985
1651
|
}
|
|
1986
|
-
if (trimmed === "
|
|
1987
|
-
pushDiag(
|
|
1988
|
-
diagnostics,
|
|
1989
|
-
"COLLIE103",
|
|
1990
|
-
"`props` must be declared using `#props`.",
|
|
1991
|
-
lineNumber,
|
|
1992
|
-
indent + 1,
|
|
1993
|
-
lineOffset,
|
|
1994
|
-
trimmed.length
|
|
1995
|
-
);
|
|
1996
|
-
if (level === 0) {
|
|
1997
|
-
propsBlockLevel = level;
|
|
1998
|
-
}
|
|
1999
|
-
continue;
|
|
2000
|
-
}
|
|
2001
|
-
if (trimmed === "#props") {
|
|
1652
|
+
if (trimmed === "#inputs") {
|
|
2002
1653
|
if (level !== 0) {
|
|
2003
1654
|
pushDiag(
|
|
2004
1655
|
diagnostics,
|
|
2005
1656
|
"COLLIE102",
|
|
2006
|
-
"#
|
|
1657
|
+
"#inputs block must be at the top level.",
|
|
2007
1658
|
lineNumber,
|
|
2008
1659
|
indent + 1,
|
|
2009
1660
|
lineOffset,
|
|
2010
1661
|
trimmed.length
|
|
2011
1662
|
);
|
|
2012
|
-
} else if (root.
|
|
1663
|
+
} else if (root.inputs) {
|
|
2013
1664
|
pushDiag(
|
|
2014
1665
|
diagnostics,
|
|
2015
1666
|
"COLLIE101",
|
|
2016
|
-
"Only one #
|
|
1667
|
+
"Only one #inputs block is allowed per #id.",
|
|
2017
1668
|
lineNumber,
|
|
2018
1669
|
indent + 1,
|
|
2019
1670
|
lineOffset,
|
|
2020
1671
|
trimmed.length
|
|
2021
1672
|
);
|
|
2022
1673
|
} else {
|
|
2023
|
-
root.
|
|
2024
|
-
root.propsDecls = [];
|
|
1674
|
+
root.inputs = { fields: [] };
|
|
2025
1675
|
}
|
|
2026
1676
|
if (level === 0) {
|
|
2027
|
-
|
|
1677
|
+
if (!root.inputsDecls) {
|
|
1678
|
+
root.inputsDecls = [];
|
|
1679
|
+
}
|
|
1680
|
+
inputsBlockLevel = level;
|
|
2028
1681
|
}
|
|
2029
1682
|
continue;
|
|
2030
1683
|
}
|
|
@@ -2064,33 +1717,33 @@ function parseTemplateBlock(lines, lineOffsets, startIndex, endIndex, options) {
|
|
|
2064
1717
|
}
|
|
2065
1718
|
continue;
|
|
2066
1719
|
}
|
|
2067
|
-
if (
|
|
2068
|
-
if (level !==
|
|
1720
|
+
if (inputsBlockLevel !== null && level > inputsBlockLevel) {
|
|
1721
|
+
if (level !== inputsBlockLevel + 1) {
|
|
2069
1722
|
pushDiag(
|
|
2070
1723
|
diagnostics,
|
|
2071
1724
|
"COLLIE102",
|
|
2072
|
-
"#
|
|
1725
|
+
"#inputs lines must be indented two spaces under the #inputs header.",
|
|
2073
1726
|
lineNumber,
|
|
2074
1727
|
indent + 1,
|
|
2075
1728
|
lineOffset
|
|
2076
1729
|
);
|
|
2077
1730
|
continue;
|
|
2078
1731
|
}
|
|
2079
|
-
const decl =
|
|
2080
|
-
if (decl && root.
|
|
2081
|
-
const existing = root.
|
|
1732
|
+
const decl = parseInputDecl(lineContent, lineNumber, indent + 1, lineOffset, diagnostics);
|
|
1733
|
+
if (decl && root.inputsDecls) {
|
|
1734
|
+
const existing = root.inputsDecls.find((d) => d.name === decl.name);
|
|
2082
1735
|
if (existing) {
|
|
2083
1736
|
pushDiag(
|
|
2084
1737
|
diagnostics,
|
|
2085
1738
|
"COLLIE106",
|
|
2086
|
-
`Duplicate
|
|
1739
|
+
`Duplicate input declaration "${decl.name}".`,
|
|
2087
1740
|
lineNumber,
|
|
2088
1741
|
indent + 1,
|
|
2089
1742
|
lineOffset,
|
|
2090
1743
|
trimmed.length
|
|
2091
1744
|
);
|
|
2092
1745
|
} else {
|
|
2093
|
-
root.
|
|
1746
|
+
root.inputsDecls.push(decl);
|
|
2094
1747
|
}
|
|
2095
1748
|
}
|
|
2096
1749
|
continue;
|
|
@@ -2503,9 +2156,7 @@ function parseTemplateBlock(lines, lineOffsets, startIndex, endIndex, options) {
|
|
|
2503
2156
|
}
|
|
2504
2157
|
if (options.dialect) {
|
|
2505
2158
|
diagnostics.push(...enforceDialect(root, options.dialect));
|
|
2506
|
-
diagnostics.push(...enforceProps(root, options.dialect.props));
|
|
2507
2159
|
}
|
|
2508
|
-
diagnostics.push(...enforcePropAliases(root));
|
|
2509
2160
|
return { root, diagnostics };
|
|
2510
2161
|
}
|
|
2511
2162
|
function buildLineOffsets(lines) {
|
|
@@ -3665,13 +3316,13 @@ function parseAndAddAttribute(attrStr, attributes, diagnostics, lineNumber, colu
|
|
|
3665
3316
|
}
|
|
3666
3317
|
}
|
|
3667
3318
|
}
|
|
3668
|
-
function
|
|
3319
|
+
function parseInputDecl(line, lineNumber, column, lineOffset, diagnostics) {
|
|
3669
3320
|
const trimmed = line.trim();
|
|
3670
3321
|
if (trimmed.includes(":") || trimmed.includes("<") || trimmed.includes("?")) {
|
|
3671
3322
|
pushDiag(
|
|
3672
3323
|
diagnostics,
|
|
3673
3324
|
"COLLIE104",
|
|
3674
|
-
'Types are not supported in #
|
|
3325
|
+
'Types are not supported in #inputs yet. Use "name" or "name()".',
|
|
3675
3326
|
lineNumber,
|
|
3676
3327
|
column,
|
|
3677
3328
|
lineOffset,
|
|
@@ -3679,32 +3330,32 @@ function parsePropDecl(line, lineNumber, column, lineOffset, diagnostics) {
|
|
|
3679
3330
|
);
|
|
3680
3331
|
return null;
|
|
3681
3332
|
}
|
|
3682
|
-
const
|
|
3683
|
-
if (
|
|
3684
|
-
const name =
|
|
3333
|
+
const valueMatch = trimmed.match(/^([A-Za-z_$][A-Za-z0-9_$]*)$/);
|
|
3334
|
+
if (valueMatch) {
|
|
3335
|
+
const name = valueMatch[1];
|
|
3685
3336
|
const nameStart = line.indexOf(name);
|
|
3686
3337
|
const nameColumn = column + nameStart;
|
|
3687
3338
|
return {
|
|
3688
3339
|
name,
|
|
3689
|
-
kind: "
|
|
3340
|
+
kind: "value",
|
|
3690
3341
|
span: createSpan(lineNumber, nameColumn, name.length, lineOffset)
|
|
3691
3342
|
};
|
|
3692
3343
|
}
|
|
3693
|
-
const
|
|
3694
|
-
if (
|
|
3695
|
-
const name =
|
|
3344
|
+
const fnMatch = trimmed.match(/^([A-Za-z_$][A-Za-z0-9_$]*)\(\)$/);
|
|
3345
|
+
if (fnMatch) {
|
|
3346
|
+
const name = fnMatch[1];
|
|
3696
3347
|
const nameStart = line.indexOf(name);
|
|
3697
3348
|
const nameColumn = column + nameStart;
|
|
3698
3349
|
return {
|
|
3699
3350
|
name,
|
|
3700
|
-
kind: "
|
|
3351
|
+
kind: "fn",
|
|
3701
3352
|
span: createSpan(lineNumber, nameColumn, name.length, lineOffset)
|
|
3702
3353
|
};
|
|
3703
3354
|
}
|
|
3704
3355
|
pushDiag(
|
|
3705
3356
|
diagnostics,
|
|
3706
3357
|
"COLLIE105",
|
|
3707
|
-
'Invalid #
|
|
3358
|
+
'Invalid #inputs declaration. Use "name" or "name()".',
|
|
3708
3359
|
lineNumber,
|
|
3709
3360
|
column,
|
|
3710
3361
|
lineOffset,
|
|
@@ -3844,8 +3495,8 @@ function serializeRoot(root, indentSize) {
|
|
|
3844
3495
|
if (root.classAliases && root.classAliases.aliases.length > 0) {
|
|
3845
3496
|
sections.push(formatClassAliases(root.classAliases, indentSize));
|
|
3846
3497
|
}
|
|
3847
|
-
if (root.
|
|
3848
|
-
sections.push(
|
|
3498
|
+
if (root.inputs && root.inputs.fields.length > 0) {
|
|
3499
|
+
sections.push(formatInputs(root.inputs, indentSize));
|
|
3849
3500
|
}
|
|
3850
3501
|
if (root.children.length > 0) {
|
|
3851
3502
|
sections.push(formatNodes(root.children, 0, indentSize));
|
|
@@ -3874,10 +3525,10 @@ function formatClassAliases(decl, indentSize) {
|
|
|
3874
3525
|
}
|
|
3875
3526
|
return lines;
|
|
3876
3527
|
}
|
|
3877
|
-
function
|
|
3528
|
+
function formatInputs(inputs, indentSize) {
|
|
3878
3529
|
const indent = indentString(1, indentSize);
|
|
3879
|
-
const lines = ["
|
|
3880
|
-
for (const field of
|
|
3530
|
+
const lines = ["#inputs"];
|
|
3531
|
+
for (const field of inputs.fields) {
|
|
3881
3532
|
const optionalFlag = field.optional ? "?" : "";
|
|
3882
3533
|
lines.push(cleanLine(`${indent}${field.name}${optionalFlag}: ${field.typeText.trim()}`));
|
|
3883
3534
|
}
|
|
@@ -4067,19 +3718,19 @@ function convertTsxToCollie(source, options = {}) {
|
|
|
4067
3718
|
);
|
|
4068
3719
|
const warnings = [];
|
|
4069
3720
|
const ctx = { sourceFile, warnings };
|
|
4070
|
-
const
|
|
4071
|
-
const component = findComponentInfo(sourceFile,
|
|
3721
|
+
const inputDeclarations = collectInputDeclarations(sourceFile);
|
|
3722
|
+
const component = findComponentInfo(sourceFile, inputDeclarations, ctx);
|
|
4072
3723
|
if (!component) {
|
|
4073
3724
|
throw new Error("Could not find a component that returns JSX in this file.");
|
|
4074
3725
|
}
|
|
4075
|
-
const
|
|
3726
|
+
const inputsLines = buildInputsBlock(component, inputDeclarations, ctx);
|
|
4076
3727
|
const templateLines = convertJsxNode(component.jsxRoot, ctx, 0);
|
|
4077
3728
|
if (!templateLines.length) {
|
|
4078
3729
|
throw new Error("Unable to convert JSX tree to Collie template.");
|
|
4079
3730
|
}
|
|
4080
3731
|
const sections = [];
|
|
4081
|
-
if (
|
|
4082
|
-
sections.push(
|
|
3732
|
+
if (inputsLines.length) {
|
|
3733
|
+
sections.push(inputsLines.join("\n"));
|
|
4083
3734
|
}
|
|
4084
3735
|
sections.push(templateLines.join("\n"));
|
|
4085
3736
|
const collie = `${sections.join("\n\n").trimEnd()}
|
|
@@ -4094,18 +3745,18 @@ function inferScriptKind(filename) {
|
|
|
4094
3745
|
if (ext === ".ts") return ts.ScriptKind.TS;
|
|
4095
3746
|
return ts.ScriptKind.JS;
|
|
4096
3747
|
}
|
|
4097
|
-
function
|
|
3748
|
+
function collectInputDeclarations(sourceFile) {
|
|
4098
3749
|
const map = /* @__PURE__ */ new Map();
|
|
4099
3750
|
for (const statement of sourceFile.statements) {
|
|
4100
3751
|
if (ts.isInterfaceDeclaration(statement) && statement.name) {
|
|
4101
|
-
map.set(statement.name.text,
|
|
3752
|
+
map.set(statement.name.text, extractInputsFromMembers(statement.members, sourceFile));
|
|
4102
3753
|
} else if (ts.isTypeAliasDeclaration(statement) && ts.isTypeLiteralNode(statement.type)) {
|
|
4103
|
-
map.set(statement.name.text,
|
|
3754
|
+
map.set(statement.name.text, extractInputsFromMembers(statement.type.members, sourceFile));
|
|
4104
3755
|
}
|
|
4105
3756
|
}
|
|
4106
3757
|
return map;
|
|
4107
3758
|
}
|
|
4108
|
-
function
|
|
3759
|
+
function extractInputsFromMembers(members, sourceFile) {
|
|
4109
3760
|
const fields = [];
|
|
4110
3761
|
for (const member of members) {
|
|
4111
3762
|
if (!ts.isPropertySignature(member) || member.name === void 0) {
|
|
@@ -4130,11 +3781,11 @@ function findComponentInfo(sourceFile, declarations, ctx) {
|
|
|
4130
3781
|
const jsx = findJsxReturn(statement.body);
|
|
4131
3782
|
if (jsx) {
|
|
4132
3783
|
const defaults = extractDefaultsFromParameters(statement.parameters, ctx);
|
|
4133
|
-
const
|
|
3784
|
+
const inputsInfo = resolveInputsFromParameters(statement.parameters, declarations, ctx);
|
|
4134
3785
|
return {
|
|
4135
3786
|
jsxRoot: jsx,
|
|
4136
|
-
|
|
4137
|
-
|
|
3787
|
+
inputsTypeName: inputsInfo.typeName,
|
|
3788
|
+
inlineInputs: inputsInfo.inline,
|
|
4138
3789
|
defaults
|
|
4139
3790
|
};
|
|
4140
3791
|
}
|
|
@@ -4148,20 +3799,20 @@ function findComponentInfo(sourceFile, declarations, ctx) {
|
|
|
4148
3799
|
continue;
|
|
4149
3800
|
}
|
|
4150
3801
|
const defaults = extractDefaultsFromParameters(init.parameters, ctx);
|
|
4151
|
-
const
|
|
4152
|
-
if (!
|
|
4153
|
-
const inferred =
|
|
4154
|
-
if (inferred.typeName && !
|
|
4155
|
-
|
|
3802
|
+
const inputsInfo = resolveInputsFromParameters(init.parameters, declarations, ctx);
|
|
3803
|
+
if (!inputsInfo.typeName && !inputsInfo.inline && decl.type) {
|
|
3804
|
+
const inferred = resolveInputsFromTypeAnnotation(decl.type, sourceFile, declarations);
|
|
3805
|
+
if (inferred.typeName && !inputsInfo.typeName) {
|
|
3806
|
+
inputsInfo.typeName = inferred.typeName;
|
|
4156
3807
|
}
|
|
4157
|
-
if (inferred.inline && !
|
|
4158
|
-
|
|
3808
|
+
if (inferred.inline && !inputsInfo.inline) {
|
|
3809
|
+
inputsInfo.inline = inferred.inline;
|
|
4159
3810
|
}
|
|
4160
3811
|
}
|
|
4161
3812
|
return {
|
|
4162
3813
|
jsxRoot: jsx,
|
|
4163
|
-
|
|
4164
|
-
|
|
3814
|
+
inputsTypeName: inputsInfo.typeName,
|
|
3815
|
+
inlineInputs: inputsInfo.inline,
|
|
4165
3816
|
defaults
|
|
4166
3817
|
};
|
|
4167
3818
|
}
|
|
@@ -4170,13 +3821,13 @@ function findComponentInfo(sourceFile, declarations, ctx) {
|
|
|
4170
3821
|
}
|
|
4171
3822
|
return null;
|
|
4172
3823
|
}
|
|
4173
|
-
function
|
|
3824
|
+
function resolveInputsFromParameters(parameters, declarations, ctx) {
|
|
4174
3825
|
if (!parameters.length) {
|
|
4175
3826
|
return {};
|
|
4176
3827
|
}
|
|
4177
3828
|
const param = parameters[0];
|
|
4178
3829
|
if (param.type) {
|
|
4179
|
-
const inferred =
|
|
3830
|
+
const inferred = resolveInputsFromTypeAnnotation(param.type, ctx.sourceFile, declarations);
|
|
4180
3831
|
if (inferred.inline) {
|
|
4181
3832
|
return inferred;
|
|
4182
3833
|
}
|
|
@@ -4186,7 +3837,7 @@ function resolvePropsFromParameters(parameters, declarations, ctx) {
|
|
|
4186
3837
|
}
|
|
4187
3838
|
return {};
|
|
4188
3839
|
}
|
|
4189
|
-
function
|
|
3840
|
+
function resolveInputsFromTypeAnnotation(typeNode, sourceFile, declarations) {
|
|
4190
3841
|
if (ts.isTypeReferenceNode(typeNode)) {
|
|
4191
3842
|
const referenced = getTypeReferenceName(typeNode.typeName);
|
|
4192
3843
|
if (referenced && declarations.has(referenced)) {
|
|
@@ -4200,12 +3851,12 @@ function resolvePropsFromTypeAnnotation(typeNode, sourceFile, declarations) {
|
|
|
4200
3851
|
return { typeName: nested };
|
|
4201
3852
|
}
|
|
4202
3853
|
} else if (ts.isTypeLiteralNode(typeArg)) {
|
|
4203
|
-
return { inline:
|
|
3854
|
+
return { inline: extractInputsFromMembers(typeArg.members, sourceFile) };
|
|
4204
3855
|
}
|
|
4205
3856
|
}
|
|
4206
3857
|
}
|
|
4207
3858
|
if (ts.isTypeLiteralNode(typeNode)) {
|
|
4208
|
-
return { inline:
|
|
3859
|
+
return { inline: extractInputsFromMembers(typeNode.members, sourceFile) };
|
|
4209
3860
|
}
|
|
4210
3861
|
return {};
|
|
4211
3862
|
}
|
|
@@ -4261,16 +3912,16 @@ function extractDefaultsFromParameters(parameters, ctx) {
|
|
|
4261
3912
|
if (!element.initializer) {
|
|
4262
3913
|
continue;
|
|
4263
3914
|
}
|
|
4264
|
-
const
|
|
4265
|
-
if (!
|
|
3915
|
+
const inputName = getBindingElementInputName(element, ctx.sourceFile);
|
|
3916
|
+
if (!inputName) {
|
|
4266
3917
|
ctx.warnings.push("Skipping complex destructured default value.");
|
|
4267
3918
|
continue;
|
|
4268
3919
|
}
|
|
4269
|
-
defaults.set(
|
|
3920
|
+
defaults.set(inputName, element.initializer.getText(ctx.sourceFile).trim());
|
|
4270
3921
|
}
|
|
4271
3922
|
return defaults;
|
|
4272
3923
|
}
|
|
4273
|
-
function
|
|
3924
|
+
function getBindingElementInputName(element, sourceFile) {
|
|
4274
3925
|
const prop = element.propertyName;
|
|
4275
3926
|
if (prop) {
|
|
4276
3927
|
if (ts.isIdentifier(prop) || ts.isStringLiteral(prop) || ts.isNumericLiteral(prop)) {
|
|
@@ -4292,24 +3943,25 @@ function getPropertyName(name, sourceFile) {
|
|
|
4292
3943
|
}
|
|
4293
3944
|
return name.getText(sourceFile);
|
|
4294
3945
|
}
|
|
4295
|
-
function
|
|
4296
|
-
const fields = info.
|
|
3946
|
+
function buildInputsBlock(info, inputDeclarations, ctx) {
|
|
3947
|
+
const fields = info.inlineInputs ?? (info.inputsTypeName ? inputDeclarations.get(info.inputsTypeName) ?? [] : void 0) ?? [];
|
|
4297
3948
|
if (!fields.length && !info.defaults.size) {
|
|
4298
3949
|
return [];
|
|
4299
3950
|
}
|
|
4300
|
-
const lines = ["
|
|
3951
|
+
const lines = ["#inputs"];
|
|
4301
3952
|
if (fields.length) {
|
|
4302
3953
|
for (const field of fields) {
|
|
4303
3954
|
const def = info.defaults.get(field.name);
|
|
4304
|
-
let line = ` ${field.name}
|
|
3955
|
+
let line = ` ${field.name}`;
|
|
4305
3956
|
if (def) {
|
|
4306
|
-
|
|
3957
|
+
ctx.warnings.push(`Default value for "${field.name}" cannot be preserved in Collie #inputs.`);
|
|
4307
3958
|
}
|
|
4308
3959
|
lines.push(line);
|
|
4309
3960
|
}
|
|
4310
3961
|
} else {
|
|
4311
3962
|
for (const [name, defValue] of info.defaults.entries()) {
|
|
4312
|
-
|
|
3963
|
+
ctx.warnings.push(`Default value for "${name}" cannot be preserved in Collie #inputs.`);
|
|
3964
|
+
lines.push(` ${name}`);
|
|
4313
3965
|
}
|
|
4314
3966
|
}
|
|
4315
3967
|
return lines;
|
|
@@ -4590,28 +4242,28 @@ function hasErrors(diagnostics) {
|
|
|
4590
4242
|
function createStubComponent(name, flavor) {
|
|
4591
4243
|
if (flavor === "tsx") {
|
|
4592
4244
|
return [
|
|
4593
|
-
"export type
|
|
4594
|
-
`export default function ${name}(
|
|
4245
|
+
"export type Inputs = Record<string, never>;",
|
|
4246
|
+
`export default function ${name}(__inputs: Inputs) {`,
|
|
4595
4247
|
" return null;",
|
|
4596
4248
|
"}"
|
|
4597
4249
|
].join("\n");
|
|
4598
4250
|
}
|
|
4599
|
-
return [`export default function ${name}(
|
|
4251
|
+
return [`export default function ${name}(__inputs) {`, " return null;", "}"].join("\n");
|
|
4600
4252
|
}
|
|
4601
4253
|
function createStubRender(flavor) {
|
|
4602
4254
|
if (flavor === "tsx") {
|
|
4603
4255
|
return [
|
|
4604
|
-
"export type
|
|
4605
|
-
"export function render(
|
|
4256
|
+
"export type Inputs = Record<string, never>;",
|
|
4257
|
+
"export function render(__inputs: any) {",
|
|
4606
4258
|
" return null;",
|
|
4607
4259
|
"}"
|
|
4608
4260
|
].join("\n");
|
|
4609
4261
|
}
|
|
4610
|
-
return ["export function render(
|
|
4262
|
+
return ["export function render(__inputs) {", " return null;", "}"].join("\n");
|
|
4611
4263
|
}
|
|
4612
4264
|
function wrapRenderModuleAsComponent(renderModule, name, flavor) {
|
|
4613
|
-
const signature = flavor === "tsx" ? `export default function ${name}(
|
|
4614
|
-
const wrapper = [signature, " return render(
|
|
4265
|
+
const signature = flavor === "tsx" ? `export default function ${name}(__inputs: Inputs) {` : `export default function ${name}(__inputs) {`;
|
|
4266
|
+
const wrapper = [signature, " return render(__inputs);", "}"].join("\n");
|
|
4615
4267
|
return `${renderModule}
|
|
4616
4268
|
|
|
4617
4269
|
${wrapper}`;
|