@collie-lang/compiler 1.3.3 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/index.cjs +841 -1200
- 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 +841 -1200
- 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) => {
|
|
@@ -873,837 +1179,197 @@ function unescapeChar(char, quote) {
|
|
|
873
1179
|
return "'";
|
|
874
1180
|
default:
|
|
875
1181
|
if (char === quote) {
|
|
876
|
-
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
|
-
}
|
|
1182
|
+
return quote;
|
|
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;
|
|
1491
1204
|
}
|
|
1205
|
+
const aliasClasses = aliasEnv.get(match[1]);
|
|
1206
|
+
if (!aliasClasses) {
|
|
1207
|
+
continue;
|
|
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".',
|
|
3675
3326
|
lineNumber,
|
|
3676
3327
|
column,
|
|
3677
3328
|
lineOffset,
|
|
@@ -3679,17 +3330,6 @@ function parsePropDecl(line, lineNumber, column, lineOffset, diagnostics) {
|
|
|
3679
3330
|
);
|
|
3680
3331
|
return null;
|
|
3681
3332
|
}
|
|
3682
|
-
const callableMatch = trimmed.match(/^([A-Za-z_$][A-Za-z0-9_$]*)\(\)$/);
|
|
3683
|
-
if (callableMatch) {
|
|
3684
|
-
const name = callableMatch[1];
|
|
3685
|
-
const nameStart = line.indexOf(name);
|
|
3686
|
-
const nameColumn = column + nameStart;
|
|
3687
|
-
return {
|
|
3688
|
-
name,
|
|
3689
|
-
kind: "callable",
|
|
3690
|
-
span: createSpan(lineNumber, nameColumn, name.length, lineOffset)
|
|
3691
|
-
};
|
|
3692
|
-
}
|
|
3693
3333
|
const valueMatch = trimmed.match(/^([A-Za-z_$][A-Za-z0-9_$]*)$/);
|
|
3694
3334
|
if (valueMatch) {
|
|
3695
3335
|
const name = valueMatch[1];
|
|
@@ -3704,7 +3344,7 @@ function parsePropDecl(line, lineNumber, column, lineOffset, diagnostics) {
|
|
|
3704
3344
|
pushDiag(
|
|
3705
3345
|
diagnostics,
|
|
3706
3346
|
"COLLIE105",
|
|
3707
|
-
'Invalid #
|
|
3347
|
+
'Invalid #inputs declaration. Use "name".',
|
|
3708
3348
|
lineNumber,
|
|
3709
3349
|
column,
|
|
3710
3350
|
lineOffset,
|
|
@@ -3844,8 +3484,8 @@ function serializeRoot(root, indentSize) {
|
|
|
3844
3484
|
if (root.classAliases && root.classAliases.aliases.length > 0) {
|
|
3845
3485
|
sections.push(formatClassAliases(root.classAliases, indentSize));
|
|
3846
3486
|
}
|
|
3847
|
-
if (root.
|
|
3848
|
-
sections.push(
|
|
3487
|
+
if (root.inputs && root.inputs.fields.length > 0) {
|
|
3488
|
+
sections.push(formatInputs(root.inputs, indentSize));
|
|
3849
3489
|
}
|
|
3850
3490
|
if (root.children.length > 0) {
|
|
3851
3491
|
sections.push(formatNodes(root.children, 0, indentSize));
|
|
@@ -3874,10 +3514,10 @@ function formatClassAliases(decl, indentSize) {
|
|
|
3874
3514
|
}
|
|
3875
3515
|
return lines;
|
|
3876
3516
|
}
|
|
3877
|
-
function
|
|
3517
|
+
function formatInputs(inputs, indentSize) {
|
|
3878
3518
|
const indent = indentString(1, indentSize);
|
|
3879
|
-
const lines = ["
|
|
3880
|
-
for (const field of
|
|
3519
|
+
const lines = ["#inputs"];
|
|
3520
|
+
for (const field of inputs.fields) {
|
|
3881
3521
|
const optionalFlag = field.optional ? "?" : "";
|
|
3882
3522
|
lines.push(cleanLine(`${indent}${field.name}${optionalFlag}: ${field.typeText.trim()}`));
|
|
3883
3523
|
}
|
|
@@ -4067,19 +3707,19 @@ function convertTsxToCollie(source, options = {}) {
|
|
|
4067
3707
|
);
|
|
4068
3708
|
const warnings = [];
|
|
4069
3709
|
const ctx = { sourceFile, warnings };
|
|
4070
|
-
const
|
|
4071
|
-
const component = findComponentInfo(sourceFile,
|
|
3710
|
+
const inputDeclarations = collectInputDeclarations(sourceFile);
|
|
3711
|
+
const component = findComponentInfo(sourceFile, inputDeclarations, ctx);
|
|
4072
3712
|
if (!component) {
|
|
4073
3713
|
throw new Error("Could not find a component that returns JSX in this file.");
|
|
4074
3714
|
}
|
|
4075
|
-
const
|
|
3715
|
+
const inputsLines = buildInputsBlock(component, inputDeclarations, ctx);
|
|
4076
3716
|
const templateLines = convertJsxNode(component.jsxRoot, ctx, 0);
|
|
4077
3717
|
if (!templateLines.length) {
|
|
4078
3718
|
throw new Error("Unable to convert JSX tree to Collie template.");
|
|
4079
3719
|
}
|
|
4080
3720
|
const sections = [];
|
|
4081
|
-
if (
|
|
4082
|
-
sections.push(
|
|
3721
|
+
if (inputsLines.length) {
|
|
3722
|
+
sections.push(inputsLines.join("\n"));
|
|
4083
3723
|
}
|
|
4084
3724
|
sections.push(templateLines.join("\n"));
|
|
4085
3725
|
const collie = `${sections.join("\n\n").trimEnd()}
|
|
@@ -4094,18 +3734,18 @@ function inferScriptKind(filename) {
|
|
|
4094
3734
|
if (ext === ".ts") return ts.ScriptKind.TS;
|
|
4095
3735
|
return ts.ScriptKind.JS;
|
|
4096
3736
|
}
|
|
4097
|
-
function
|
|
3737
|
+
function collectInputDeclarations(sourceFile) {
|
|
4098
3738
|
const map = /* @__PURE__ */ new Map();
|
|
4099
3739
|
for (const statement of sourceFile.statements) {
|
|
4100
3740
|
if (ts.isInterfaceDeclaration(statement) && statement.name) {
|
|
4101
|
-
map.set(statement.name.text,
|
|
3741
|
+
map.set(statement.name.text, extractInputsFromMembers(statement.members, sourceFile));
|
|
4102
3742
|
} else if (ts.isTypeAliasDeclaration(statement) && ts.isTypeLiteralNode(statement.type)) {
|
|
4103
|
-
map.set(statement.name.text,
|
|
3743
|
+
map.set(statement.name.text, extractInputsFromMembers(statement.type.members, sourceFile));
|
|
4104
3744
|
}
|
|
4105
3745
|
}
|
|
4106
3746
|
return map;
|
|
4107
3747
|
}
|
|
4108
|
-
function
|
|
3748
|
+
function extractInputsFromMembers(members, sourceFile) {
|
|
4109
3749
|
const fields = [];
|
|
4110
3750
|
for (const member of members) {
|
|
4111
3751
|
if (!ts.isPropertySignature(member) || member.name === void 0) {
|
|
@@ -4130,11 +3770,11 @@ function findComponentInfo(sourceFile, declarations, ctx) {
|
|
|
4130
3770
|
const jsx = findJsxReturn(statement.body);
|
|
4131
3771
|
if (jsx) {
|
|
4132
3772
|
const defaults = extractDefaultsFromParameters(statement.parameters, ctx);
|
|
4133
|
-
const
|
|
3773
|
+
const inputsInfo = resolveInputsFromParameters(statement.parameters, declarations, ctx);
|
|
4134
3774
|
return {
|
|
4135
3775
|
jsxRoot: jsx,
|
|
4136
|
-
|
|
4137
|
-
|
|
3776
|
+
inputsTypeName: inputsInfo.typeName,
|
|
3777
|
+
inlineInputs: inputsInfo.inline,
|
|
4138
3778
|
defaults
|
|
4139
3779
|
};
|
|
4140
3780
|
}
|
|
@@ -4148,20 +3788,20 @@ function findComponentInfo(sourceFile, declarations, ctx) {
|
|
|
4148
3788
|
continue;
|
|
4149
3789
|
}
|
|
4150
3790
|
const defaults = extractDefaultsFromParameters(init.parameters, ctx);
|
|
4151
|
-
const
|
|
4152
|
-
if (!
|
|
4153
|
-
const inferred =
|
|
4154
|
-
if (inferred.typeName && !
|
|
4155
|
-
|
|
3791
|
+
const inputsInfo = resolveInputsFromParameters(init.parameters, declarations, ctx);
|
|
3792
|
+
if (!inputsInfo.typeName && !inputsInfo.inline && decl.type) {
|
|
3793
|
+
const inferred = resolveInputsFromTypeAnnotation(decl.type, sourceFile, declarations);
|
|
3794
|
+
if (inferred.typeName && !inputsInfo.typeName) {
|
|
3795
|
+
inputsInfo.typeName = inferred.typeName;
|
|
4156
3796
|
}
|
|
4157
|
-
if (inferred.inline && !
|
|
4158
|
-
|
|
3797
|
+
if (inferred.inline && !inputsInfo.inline) {
|
|
3798
|
+
inputsInfo.inline = inferred.inline;
|
|
4159
3799
|
}
|
|
4160
3800
|
}
|
|
4161
3801
|
return {
|
|
4162
3802
|
jsxRoot: jsx,
|
|
4163
|
-
|
|
4164
|
-
|
|
3803
|
+
inputsTypeName: inputsInfo.typeName,
|
|
3804
|
+
inlineInputs: inputsInfo.inline,
|
|
4165
3805
|
defaults
|
|
4166
3806
|
};
|
|
4167
3807
|
}
|
|
@@ -4170,13 +3810,13 @@ function findComponentInfo(sourceFile, declarations, ctx) {
|
|
|
4170
3810
|
}
|
|
4171
3811
|
return null;
|
|
4172
3812
|
}
|
|
4173
|
-
function
|
|
3813
|
+
function resolveInputsFromParameters(parameters, declarations, ctx) {
|
|
4174
3814
|
if (!parameters.length) {
|
|
4175
3815
|
return {};
|
|
4176
3816
|
}
|
|
4177
3817
|
const param = parameters[0];
|
|
4178
3818
|
if (param.type) {
|
|
4179
|
-
const inferred =
|
|
3819
|
+
const inferred = resolveInputsFromTypeAnnotation(param.type, ctx.sourceFile, declarations);
|
|
4180
3820
|
if (inferred.inline) {
|
|
4181
3821
|
return inferred;
|
|
4182
3822
|
}
|
|
@@ -4186,7 +3826,7 @@ function resolvePropsFromParameters(parameters, declarations, ctx) {
|
|
|
4186
3826
|
}
|
|
4187
3827
|
return {};
|
|
4188
3828
|
}
|
|
4189
|
-
function
|
|
3829
|
+
function resolveInputsFromTypeAnnotation(typeNode, sourceFile, declarations) {
|
|
4190
3830
|
if (ts.isTypeReferenceNode(typeNode)) {
|
|
4191
3831
|
const referenced = getTypeReferenceName(typeNode.typeName);
|
|
4192
3832
|
if (referenced && declarations.has(referenced)) {
|
|
@@ -4200,12 +3840,12 @@ function resolvePropsFromTypeAnnotation(typeNode, sourceFile, declarations) {
|
|
|
4200
3840
|
return { typeName: nested };
|
|
4201
3841
|
}
|
|
4202
3842
|
} else if (ts.isTypeLiteralNode(typeArg)) {
|
|
4203
|
-
return { inline:
|
|
3843
|
+
return { inline: extractInputsFromMembers(typeArg.members, sourceFile) };
|
|
4204
3844
|
}
|
|
4205
3845
|
}
|
|
4206
3846
|
}
|
|
4207
3847
|
if (ts.isTypeLiteralNode(typeNode)) {
|
|
4208
|
-
return { inline:
|
|
3848
|
+
return { inline: extractInputsFromMembers(typeNode.members, sourceFile) };
|
|
4209
3849
|
}
|
|
4210
3850
|
return {};
|
|
4211
3851
|
}
|
|
@@ -4261,16 +3901,16 @@ function extractDefaultsFromParameters(parameters, ctx) {
|
|
|
4261
3901
|
if (!element.initializer) {
|
|
4262
3902
|
continue;
|
|
4263
3903
|
}
|
|
4264
|
-
const
|
|
4265
|
-
if (!
|
|
3904
|
+
const inputName = getBindingElementInputName(element, ctx.sourceFile);
|
|
3905
|
+
if (!inputName) {
|
|
4266
3906
|
ctx.warnings.push("Skipping complex destructured default value.");
|
|
4267
3907
|
continue;
|
|
4268
3908
|
}
|
|
4269
|
-
defaults.set(
|
|
3909
|
+
defaults.set(inputName, element.initializer.getText(ctx.sourceFile).trim());
|
|
4270
3910
|
}
|
|
4271
3911
|
return defaults;
|
|
4272
3912
|
}
|
|
4273
|
-
function
|
|
3913
|
+
function getBindingElementInputName(element, sourceFile) {
|
|
4274
3914
|
const prop = element.propertyName;
|
|
4275
3915
|
if (prop) {
|
|
4276
3916
|
if (ts.isIdentifier(prop) || ts.isStringLiteral(prop) || ts.isNumericLiteral(prop)) {
|
|
@@ -4292,24 +3932,25 @@ function getPropertyName(name, sourceFile) {
|
|
|
4292
3932
|
}
|
|
4293
3933
|
return name.getText(sourceFile);
|
|
4294
3934
|
}
|
|
4295
|
-
function
|
|
4296
|
-
const fields = info.
|
|
3935
|
+
function buildInputsBlock(info, inputDeclarations, ctx) {
|
|
3936
|
+
const fields = info.inlineInputs ?? (info.inputsTypeName ? inputDeclarations.get(info.inputsTypeName) ?? [] : void 0) ?? [];
|
|
4297
3937
|
if (!fields.length && !info.defaults.size) {
|
|
4298
3938
|
return [];
|
|
4299
3939
|
}
|
|
4300
|
-
const lines = ["
|
|
3940
|
+
const lines = ["#inputs"];
|
|
4301
3941
|
if (fields.length) {
|
|
4302
3942
|
for (const field of fields) {
|
|
4303
3943
|
const def = info.defaults.get(field.name);
|
|
4304
|
-
let line = ` ${field.name}
|
|
3944
|
+
let line = ` ${field.name}`;
|
|
4305
3945
|
if (def) {
|
|
4306
|
-
|
|
3946
|
+
ctx.warnings.push(`Default value for "${field.name}" cannot be preserved in Collie #inputs.`);
|
|
4307
3947
|
}
|
|
4308
3948
|
lines.push(line);
|
|
4309
3949
|
}
|
|
4310
3950
|
} else {
|
|
4311
3951
|
for (const [name, defValue] of info.defaults.entries()) {
|
|
4312
|
-
|
|
3952
|
+
ctx.warnings.push(`Default value for "${name}" cannot be preserved in Collie #inputs.`);
|
|
3953
|
+
lines.push(` ${name}`);
|
|
4313
3954
|
}
|
|
4314
3955
|
}
|
|
4315
3956
|
return lines;
|
|
@@ -4590,28 +4231,28 @@ function hasErrors(diagnostics) {
|
|
|
4590
4231
|
function createStubComponent(name, flavor) {
|
|
4591
4232
|
if (flavor === "tsx") {
|
|
4592
4233
|
return [
|
|
4593
|
-
"export type
|
|
4594
|
-
`export default function ${name}(
|
|
4234
|
+
"export type Inputs = Record<string, never>;",
|
|
4235
|
+
`export default function ${name}(__inputs: Inputs) {`,
|
|
4595
4236
|
" return null;",
|
|
4596
4237
|
"}"
|
|
4597
4238
|
].join("\n");
|
|
4598
4239
|
}
|
|
4599
|
-
return [`export default function ${name}(
|
|
4240
|
+
return [`export default function ${name}(__inputs) {`, " return null;", "}"].join("\n");
|
|
4600
4241
|
}
|
|
4601
4242
|
function createStubRender(flavor) {
|
|
4602
4243
|
if (flavor === "tsx") {
|
|
4603
4244
|
return [
|
|
4604
|
-
"export type
|
|
4605
|
-
"export function render(
|
|
4245
|
+
"export type Inputs = Record<string, never>;",
|
|
4246
|
+
"export function render(__inputs: any) {",
|
|
4606
4247
|
" return null;",
|
|
4607
4248
|
"}"
|
|
4608
4249
|
].join("\n");
|
|
4609
4250
|
}
|
|
4610
|
-
return ["export function render(
|
|
4251
|
+
return ["export function render(__inputs) {", " return null;", "}"].join("\n");
|
|
4611
4252
|
}
|
|
4612
4253
|
function wrapRenderModuleAsComponent(renderModule, name, flavor) {
|
|
4613
|
-
const signature = flavor === "tsx" ? `export default function ${name}(
|
|
4614
|
-
const wrapper = [signature, " return render(
|
|
4254
|
+
const signature = flavor === "tsx" ? `export default function ${name}(__inputs: Inputs) {` : `export default function ${name}(__inputs) {`;
|
|
4255
|
+
const wrapper = [signature, " return render(__inputs);", "}"].join("\n");
|
|
4615
4256
|
return `${renderModule}
|
|
4616
4257
|
|
|
4617
4258
|
${wrapper}`;
|