@vobs/vite-plugin 1.2.1 → 1.3.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/dist/index.js CHANGED
@@ -1,1146 +1,14 @@
1
- import { readFile } from 'fs/promises';
2
- import path from 'path';
3
- import ts from 'typescript';
4
- import { VobsError } from '@vobs/runtime/error';
5
- import { parseFragment } from 'parse5';
6
-
7
1
  var __defProp = Object.defineProperty;
8
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
9
- function compileWithSourceMap(code, options = {}) {
10
- const filename = options.filename ?? "component.tsx";
11
- let sourceFile = ts.createSourceFile(
12
- filename,
13
- code,
14
- ts.ScriptTarget.Latest,
15
- true,
16
- ts.ScriptKind.TSX
17
- );
18
- const state = {
19
- generatedId: 0,
20
- filename,
21
- sourceFile,
22
- statementSources: /* @__PURE__ */ new WeakMap(),
23
- takenNames: collectDeclaredNames(sourceFile),
24
- helperAliases: /* @__PURE__ */ new Map(),
25
- templates: /* @__PURE__ */ new Map(),
26
- sourceLocation: options.sourceLocation ?? true,
27
- stateAliases: collectStateAliases(sourceFile),
28
- localBindings: collectLocallyDeclaredNames(sourceFile),
29
- diagnostics: []
30
- };
31
- const cleanFilename = filename.split(/[?#]/u, 1)[0] || filename;
32
- const diagnostics = ts.transpileModule(code, {
33
- // Vite appends query strings (for example `?direct`) to module IDs;
34
- // strip them so TypeScript still recognizes TSX syntax for diagnostics.
35
- fileName: cleanFilename,
36
- reportDiagnostics: true,
37
- compilerOptions: { jsx: ts.JsxEmit.Preserve, target: ts.ScriptTarget.Latest }
38
- }).diagnostics?.map((diagnostic) => toCompilerDiagnostic(diagnostic, sourceFile, cleanFilename)) ?? [];
39
- const plugins = options.plugins ?? [];
40
- validatePlugins(plugins);
41
- const context = {
42
- filename,
43
- factory: ts.factory,
44
- addRuntimeImport(name) {
45
- resolveHelperName(state, name);
46
- },
47
- helperRef: /* @__PURE__ */ __name((name) => helperRef(state, name), "helperRef")
48
- };
49
- for (const plugin of plugins) plugin.analyze?.(sourceFile, context);
50
- for (const plugin of plugins) {
51
- sourceFile = plugin.transform?.program?.(sourceFile, context) ?? sourceFile;
52
- }
53
- for (const plugin of plugins) sourceFile = transformPluginNodes(sourceFile, plugin, context);
54
- const statements = sourceFile.statements.map(
55
- (statement) => ts.isImportDeclaration(statement) ? rebuildImport(state, statement) : transformStatement(state, statement)
56
- );
57
- const templateDeclarations = createTemplateDeclarations(state);
58
- const resultFile = ts.factory.updateSourceFile(sourceFile, [
59
- ...createRuntimeImports(state),
60
- ...templateDeclarations,
61
- ...statements
62
- ]);
63
- const generated = ts.createPrinter().printFile(resultFile);
64
- return {
65
- code: generated,
66
- map: buildSourceMap(state, filename, code, generated, resultFile),
67
- diagnostics: [...diagnostics, ...state.diagnostics]
68
- };
69
- }
70
- __name(compileWithSourceMap, "compileWithSourceMap");
71
- function toCompilerDiagnostic(diagnostic, sourceFile, filename) {
72
- const start = diagnostic.start ?? 0;
73
- const length = diagnostic.length ?? 1;
74
- const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n");
75
- const { line, column, codeFrame } = buildCodeFrame(sourceFile, start, length);
76
- return {
77
- code: `VOBS_C${String(diagnostic.code).padStart(3, "0")}`,
78
- severity: diagnostic.category === ts.DiagnosticCategory.Warning ? "warning" : "error",
79
- message,
80
- location: { file: filename, line, column },
81
- codeFrame
82
- };
83
- }
84
- __name(toCompilerDiagnostic, "toCompilerDiagnostic");
85
- function buildCodeFrame(sourceFile, start, length) {
86
- const position = sourceFile.getLineAndCharacterOfPosition(start);
87
- const lineText = sourceFile.text.split(/\r?\n/u)[position.line] ?? "";
88
- const markerLength = Math.max(1, Math.min(length, Math.max(1, lineText.length - position.character)));
89
- return {
90
- line: position.line + 1,
91
- column: position.character + 1,
92
- codeFrame: `${position.line + 1} | ${lineText}
93
- ${" ".repeat(String(position.line + 1).length + 3 + position.character)}${"^".repeat(markerLength)}`
94
- };
95
- }
96
- __name(buildCodeFrame, "buildCodeFrame");
97
- function reportUnsupportedTag(state, tagName) {
98
- const sourceFile = tagName.getSourceFile() ?? state.sourceFile;
99
- if (!sourceFile) return;
100
- const label = tagName.getText();
101
- const kindNote = tagName.kind === ts.SyntaxKind.JsxNamespacedName ? "\uFF08JSX \u547D\u540D\u7A7A\u95F4\u6807\u7B7E\uFF09" : "";
102
- const { line, column, codeFrame } = buildCodeFrame(sourceFile, tagName.getStart(sourceFile), tagName.getWidth(sourceFile));
103
- state.diagnostics.push({
104
- code: "VOBS_C101",
105
- severity: "error",
106
- message: `\u4E0D\u652F\u6301\u7684 JSX \u6807\u7B7E\u5F62\u6001\uFF1A<${label}>${kindNote}\u3002\u7EC4\u4EF6\u5FC5\u987B\u662F\u5927\u5199\u5F00\u5934\u7684\u6807\u8BC6\u7B26\uFF0CDOM \u5143\u7D20\u5FC5\u987B\u662F\u5C0F\u5199\u6807\u7B7E\u540D\u3002`,
107
- location: { file: state.filename, line, column },
108
- codeFrame,
109
- fix: `\u628A <${label}> \u6539\u4E3A <Component /> \u5F62\u5F0F\u7684\u7EC4\u4EF6\u6216\u5C0F\u5199 DOM \u6807\u7B7E\uFF1BFragment \u8BF7\u4F7F\u7528 <Fragment> \u6216 <>...</>\u3002`
110
- });
111
- }
112
- __name(reportUnsupportedTag, "reportUnsupportedTag");
113
- function buildSourceMap(state, filename, source, generated, resultFile) {
114
- const reparsed = ts.createSourceFile(filename, generated, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
115
- const segments = [];
116
- walkPairedTrees(state, resultFile, reparsed, reparsed, segments);
117
- segments.sort((a, b) => a.genLine - b.genLine || a.genCol - b.genCol);
118
- return {
119
- version: 3,
120
- file: filename,
121
- sources: [filename],
122
- sourcesContent: [source],
123
- names: [],
124
- mappings: encodeMappings(segments, generated.split("\n").length)
125
- };
126
- }
127
- __name(buildSourceMap, "buildSourceMap");
128
- function statementLists(node) {
129
- if (ts.isSourceFile(node) || ts.isBlock(node) || ts.isModuleBlock(node)) return node.statements;
130
- if (ts.isCaseClause(node) || ts.isDefaultClause(node)) return node.statements;
131
- return null;
132
- }
133
- __name(statementLists, "statementLists");
134
- function walkPairedTrees(state, original, generated, reparsed, segments) {
135
- const originalStatements = statementLists(original);
136
- const generatedStatements = statementLists(generated);
137
- if (originalStatements && generatedStatements) {
138
- if (originalStatements.length !== generatedStatements.length) return;
139
- for (let index = 0; index < originalStatements.length; index++) {
140
- const originalStatement = originalStatements[index];
141
- const generatedStatement = generatedStatements[index];
142
- recordSegment(state, originalStatement, generatedStatement, reparsed, segments);
143
- walkPairedTrees(state, originalStatement, generatedStatement, reparsed, segments);
144
- }
145
- return;
146
- }
147
- const originalChildren = [];
148
- const generatedChildren = [];
149
- ts.forEachChild(original, (node) => {
150
- originalChildren.push(node);
151
- });
152
- ts.forEachChild(generated, (node) => {
153
- generatedChildren.push(node);
154
- });
155
- if (originalChildren.length !== generatedChildren.length) return;
156
- for (let index = 0; index < originalChildren.length; index++) {
157
- walkPairedTrees(state, originalChildren[index], generatedChildren[index], reparsed, segments);
158
- }
159
- }
160
- __name(walkPairedTrees, "walkPairedTrees");
161
- function recordSegment(state, originalStatement, generatedStatement, reparsed, segments) {
162
- const source = state.statementSources.get(originalStatement) ?? positionOfOriginalStatement(state, originalStatement);
163
- if (!source) return;
164
- const position = reparsed.getLineAndCharacterOfPosition(generatedStatement.getStart(reparsed));
165
- segments.push({
166
- genLine: position.line,
167
- genCol: position.character,
168
- srcLine: source.line,
169
- srcCol: source.column
170
- });
171
- }
172
- __name(recordSegment, "recordSegment");
173
- function positionOfOriginalStatement(state, statement) {
174
- if (statement.pos < 0 || !state.sourceFile) return null;
175
- const { line, character } = state.sourceFile.getLineAndCharacterOfPosition(
176
- statement.getStart(state.sourceFile)
177
- );
178
- return { line, column: character };
179
- }
180
- __name(positionOfOriginalStatement, "positionOfOriginalStatement");
181
- function encodeMappings(segments, lineCount) {
182
- const lines = Array.from({ length: lineCount }, () => []);
183
- let prevGenLine = -1;
184
- let prevGenCol = 0;
185
- let prevSrcLine = 0;
186
- let prevSrcCol = 0;
187
- for (const segment of segments) {
188
- if (segment.genLine !== prevGenLine) {
189
- prevGenCol = 0;
190
- prevGenLine = segment.genLine;
191
- }
192
- const values = [
193
- segment.genCol - prevGenCol,
194
- 0,
195
- segment.srcLine - prevSrcLine,
196
- segment.srcCol - prevSrcCol
197
- ];
198
- lines[segment.genLine].push(values.map(encodeVlq).join(""));
199
- prevGenCol = segment.genCol;
200
- prevSrcLine = segment.srcLine;
201
- prevSrcCol = segment.srcCol;
202
- }
203
- return lines.map((line) => line.join(",")).join(";");
204
- }
205
- __name(encodeMappings, "encodeMappings");
206
- var base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
207
- function encodeVlq(value) {
208
- let encoded = value < 0 ? -value << 1 | 1 : value << 1;
209
- let result = "";
210
- do {
211
- let digit = encoded & 31;
212
- encoded >>>= 5;
213
- if (encoded > 0) digit |= 32;
214
- result += base64Chars[digit];
215
- } while (encoded > 0);
216
- return result;
217
- }
218
- __name(encodeVlq, "encodeVlq");
219
- function validatePlugins(plugins) {
220
- const names = /* @__PURE__ */ new Set();
221
- for (const plugin of plugins) {
222
- if (!plugin.name) throw new VobsError({ code: "VOBS_C007", layer: "compiler", message: "\u7F16\u8BD1\u5668\u63D2\u4EF6\u5FC5\u987B\u63D0\u4F9B name", fix: "\u4E3A\u63D2\u4EF6\u6DFB\u52A0\u7A33\u5B9A\u4E14\u552F\u4E00\u7684 name\u3002" });
223
- if (names.has(plugin.name)) throw new VobsError({ code: "VOBS_C007", layer: "compiler", message: `\u68C0\u6D4B\u5230\u91CD\u590D\u63D2\u4EF6: ${plugin.name}`, fix: "\u4E3A\u6BCF\u4E2A\u7F16\u8BD1\u5668\u63D2\u4EF6\u4F7F\u7528\u552F\u4E00\u7684 name\u3002" });
224
- names.add(plugin.name);
225
- }
226
- }
227
- __name(validatePlugins, "validatePlugins");
228
- function transformPluginNodes(sourceFile, plugin, context) {
229
- const transformNode = plugin.transform?.node ?? plugin.transformNode;
230
- if (!transformNode) return sourceFile;
231
- const transformer = /* @__PURE__ */ __name((transformContext) => (root) => {
232
- const visit = /* @__PURE__ */ __name((node) => {
233
- const replacement = transformNode(node, context);
234
- if (replacement === null) return void 0;
235
- return ts.visitEachChild(replacement ?? node, visit, transformContext);
236
- }, "visit");
237
- return ts.visitNode(root, visit);
238
- }, "transformer");
239
- const result = ts.transform(sourceFile, [transformer]);
240
- try {
241
- return result.transformed[0];
242
- } finally {
243
- result.dispose();
244
- }
245
- }
246
- __name(transformPluginNodes, "transformPluginNodes");
247
- function collectDeclaredNames(sourceFile) {
248
- const names = /* @__PURE__ */ new Set();
249
- const visit = /* @__PURE__ */ __name((node) => {
250
- if (ts.isIdentifier(node) && isBindingName(node)) names.add(node.text);
251
- ts.forEachChild(node, visit);
252
- }, "visit");
253
- visit(sourceFile);
254
- return names;
255
- }
256
- __name(collectDeclaredNames, "collectDeclaredNames");
257
- function collectStateAliases(sourceFile) {
258
- const aliases = /* @__PURE__ */ new Set();
259
- for (const statement of sourceFile.statements) {
260
- if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier)) continue;
261
- const module = statement.moduleSpecifier.text;
262
- if (module !== "@vobs/reactivity" && module !== "@vobs/vobs") continue;
263
- const clause = statement.importClause;
264
- if (!clause?.namedBindings || !ts.isNamedImports(clause.namedBindings)) continue;
265
- for (const element of clause.namedBindings.elements) {
266
- if (element.propertyName ? element.propertyName.text === "state" : element.name.text === "state") {
267
- aliases.add(element.name.text);
268
- }
269
- }
270
- }
271
- return aliases;
272
- }
273
- __name(collectStateAliases, "collectStateAliases");
274
- function collectLocallyDeclaredNames(sourceFile) {
275
- const names = /* @__PURE__ */ new Set();
276
- const visit = /* @__PURE__ */ __name((node) => {
277
- if (ts.isImportDeclaration(node)) return;
278
- if (ts.isIdentifier(node) && isBindingName(node)) names.add(node.text);
279
- ts.forEachChild(node, visit);
280
- }, "visit");
281
- visit(sourceFile);
282
- return names;
283
- }
284
- __name(collectLocallyDeclaredNames, "collectLocallyDeclaredNames");
285
- function isBindingName(node) {
286
- const parent = node.parent;
287
- if (!parent) return false;
288
- if (ts.isPropertyAccessExpression(parent) && parent.name === node) return false;
289
- if (ts.isQualifiedName(parent) && parent.right === node) return false;
290
- if (ts.isJsxAttribute(parent)) return false;
291
- return parent.name === node;
292
- }
293
- __name(isBindingName, "isBindingName");
294
- function resolveHelperName(state, name) {
295
- const existing = state.helperAliases.get(name);
296
- if (existing) return existing;
297
- let alias = name;
298
- if (state.takenNames.has(alias)) {
299
- alias = `_vobs_${name}`;
300
- let suffix = 1;
301
- while (state.takenNames.has(alias)) alias = `_vobs_${name}_${suffix++}`;
302
- }
303
- state.helperAliases.set(name, alias);
304
- return alias;
305
- }
306
- __name(resolveHelperName, "resolveHelperName");
307
- function helperRef(state, name) {
308
- return ts.factory.createIdentifier(resolveHelperName(state, name));
309
- }
310
- __name(helperRef, "helperRef");
311
- function createRuntimeImports(state) {
312
- const modules = /* @__PURE__ */ new Map();
313
- for (const [name, alias] of state.helperAliases) {
314
- const module = name === "insertResourceBoundary" ? "@vobs/resource" : "@vobs/vobs";
315
- const imported = modules.get(module) ?? [];
316
- imported.push(ts.factory.createImportSpecifier(
317
- false,
318
- alias === name ? void 0 : ts.factory.createIdentifier(name),
319
- ts.factory.createIdentifier(alias)
320
- ));
321
- modules.set(module, imported);
322
- }
323
- return [...modules.entries()].map(([module, imported]) => ts.factory.createImportDeclaration(
324
- void 0,
325
- ts.factory.createImportClause(
326
- false,
327
- void 0,
328
- ts.factory.createNamedImports(imported)
329
- ),
330
- ts.factory.createStringLiteral(module)
331
- ));
332
- }
333
- __name(createRuntimeImports, "createRuntimeImports");
334
- function rebuildImport(state, node) {
335
- if (!ts.isStringLiteral(node.moduleSpecifier)) return node;
336
- return tagStatement(state, ts.factory.createImportDeclaration(
337
- node.modifiers,
338
- node.importClause,
339
- ts.factory.createStringLiteral(node.moduleSpecifier.text),
340
- node.attributes
341
- ), node);
342
- }
343
- __name(rebuildImport, "rebuildImport");
344
- function transformStatement(state, node) {
345
- if (ts.isFunctionDeclaration(node) && node.body) {
346
- return tagStatement(state, ts.factory.updateFunctionDeclaration(
347
- node,
348
- node.modifiers,
349
- node.asteriskToken,
350
- node.name,
351
- node.typeParameters,
352
- node.parameters,
353
- node.type,
354
- transformBlock(state, node.body)
355
- ), node);
356
- }
357
- if (ts.isVariableStatement(node)) return transformVariableStatement(state, node);
358
- if (ts.isExportAssignment(node) && containsJsx(node.expression)) {
359
- return tagStatement(state, ts.factory.updateExportAssignment(node, node.modifiers, transformEmbeddedExpression(state, node.expression)), node);
360
- }
361
- if (ts.isExpressionStatement(node) && containsJsx(node.expression)) {
362
- return tagStatement(state, ts.factory.updateExpressionStatement(node, transformEmbeddedExpression(state, node.expression)), node);
363
- }
364
- if (ts.isReturnStatement(node) && node.expression && containsJsx(node.expression)) {
365
- return tagStatement(state, ts.factory.updateReturnStatement(node, transformEmbeddedExpression(state, node.expression)), node);
366
- }
367
- return node;
368
- }
369
- __name(transformStatement, "transformStatement");
370
- function transformVariableStatement(state, node) {
371
- let changed = false;
372
- const declarations = node.declarationList.declarations.map((declaration) => {
373
- const initializer = declaration.initializer;
374
- if (!initializer) return declaration;
375
- let nextInitializer = inferStateDebugName(state, declaration, initializer) ?? initializer;
376
- if (containsJsx(nextInitializer)) {
377
- nextInitializer = transformEmbeddedExpression(state, nextInitializer);
378
- }
379
- if (nextInitializer === initializer) return declaration;
380
- changed = true;
381
- return ts.factory.updateVariableDeclaration(
382
- declaration,
383
- declaration.name,
384
- declaration.exclamationToken,
385
- declaration.type,
386
- nextInitializer
387
- );
388
- });
389
- if (!changed) return node;
390
- return tagStatement(state, ts.factory.updateVariableStatement(
391
- node,
392
- node.modifiers,
393
- ts.factory.updateVariableDeclarationList(node.declarationList, declarations)
394
- ), node);
395
- }
396
- __name(transformVariableStatement, "transformVariableStatement");
397
- function inferStateDebugName(state, declaration, initializer) {
398
- if (state.stateAliases.size === 0) return void 0;
399
- if (!ts.isIdentifier(declaration.name)) return void 0;
400
- let call = initializer;
401
- while (ts.isParenthesizedExpression(call) || ts.isAsExpression(call) || ts.isTypeAssertionExpression(call) || ts.isSatisfiesExpression(call)) {
402
- call = call.expression;
403
- }
404
- if (!ts.isCallExpression(call)) return void 0;
405
- const callee = call.expression;
406
- if (!ts.isIdentifier(callee) || !state.stateAliases.has(callee.text)) return void 0;
407
- if (state.localBindings.has(callee.text)) return void 0;
408
- if (call.arguments.length !== 1) return void 0;
409
- return ts.factory.createCallExpression(callee, call.typeArguments, [
410
- ...call.arguments,
411
- ts.factory.createStringLiteral(declaration.name.text)
412
- ]);
413
- }
414
- __name(inferStateDebugName, "inferStateDebugName");
415
- function containsJsx(expression) {
416
- let found = false;
417
- const visit = /* @__PURE__ */ __name((node) => {
418
- if (isJsxExpression(node)) {
419
- found = true;
420
- return;
421
- }
422
- ts.forEachChild(node, visit);
423
- }, "visit");
424
- visit(expression);
425
- return found;
426
- }
427
- __name(containsJsx, "containsJsx");
428
- function transformBlock(state, block) {
429
- const statements = block.statements.map((statement) => {
430
- if (!ts.isReturnStatement(statement) || !statement.expression) return transformStatement(state, statement);
431
- const expression = ts.isParenthesizedExpression(statement.expression) ? statement.expression.expression : statement.expression;
432
- return isJsxExpression(expression) ? tagStatement(state, ts.factory.updateReturnStatement(statement, transformJsxExpression(state, expression)), statement) : statement;
433
- });
434
- return ts.factory.updateBlock(block, statements);
435
- }
436
- __name(transformBlock, "transformBlock");
437
- function isJsxExpression(node) {
438
- return ts.isJsxElement(node) || ts.isJsxSelfClosingElement(node) || ts.isJsxFragment(node);
439
- }
440
- __name(isJsxExpression, "isJsxExpression");
441
- function transformJsxExpression(state, node) {
442
- if (ts.isJsxFragment(node)) return transformFragment(state, node.children);
443
- if (ts.isJsxElement(node)) {
444
- return transformElement(state, node, node.openingElement.tagName, node.openingElement.attributes, node.children);
445
- }
446
- return transformElement(state, node, node.tagName, node.attributes, []);
447
- }
448
- __name(transformJsxExpression, "transformJsxExpression");
449
- function transformElement(state, node, tagName, attributes, children) {
450
- if (isFragmentTag(tagName)) return transformFragment(state, children);
451
- if (!ts.isIdentifier(tagName)) {
452
- reportUnsupportedTag(state, tagName);
453
- }
454
- if (ts.isIdentifier(tagName) && tagName.text === "ResourceBoundary") {
455
- return transformResourceBoundary(state, node, attributes, children);
456
- }
457
- if (ts.isIdentifier(tagName) && tagName.text === "AsyncBoundary") {
458
- return transformAsyncBoundary(state, node, attributes, children);
459
- }
460
- if (ts.isIdentifier(tagName) && tagName.text === "ErrorBoundary") {
461
- return transformErrorBoundary(state, node, attributes, children);
462
- }
463
- if (ts.isIdentifier(tagName) && tagName.text === "Profiler") {
464
- return transformProfiler(state, node, attributes, children);
465
- }
466
- if (ts.isIdentifier(tagName) && /^[A-Z]/.test(tagName.text)) {
467
- const args = [
468
- ts.factory.createCallExpression(helperRef(state, "resolveComponent"), void 0, [
469
- tagName,
470
- ts.factory.createStringLiteral(state.filename),
471
- ts.factory.createStringLiteral(tagName.text)
472
- ]),
473
- createComponentProps(state, attributes, children)
474
- ];
475
- if (state.sourceLocation) args.push(createSourceLocation(tagName));
476
- return ts.factory.createCallExpression(helperRef(state, "createComponent"), void 0, args);
477
- }
478
- if (isStaticElement(tagName, attributes, children)) {
479
- return ts.factory.createCallExpression(
480
- helperRef(state, "cloneTemplate"),
481
- void 0,
482
- [registerTemplate(state, serializeStaticHtml(node))]
483
- );
484
- }
485
- const elementName = tagName.getText();
486
- const elementId = nextIdentifier(state, "_el");
487
- const statements = [
488
- createConstStatement(
489
- state,
490
- elementId,
491
- ts.factory.createCallExpression(
492
- helperRef(state, "createElement"),
493
- void 0,
494
- [ts.factory.createStringLiteral(elementName)]
495
- ),
496
- node
497
- )
498
- ];
499
- appendAttributes(state, statements, elementId, attributes);
500
- appendChildren(state, statements, elementId, children);
501
- statements.push(tagStatement(state, ts.factory.createReturnStatement(elementId), node));
502
- return ts.factory.createCallExpression(
503
- ts.factory.createArrowFunction(
504
- void 0,
505
- void 0,
506
- [],
507
- void 0,
508
- ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
509
- ts.factory.createBlock(statements, true)
510
- ),
511
- void 0,
512
- []
513
- );
514
- }
515
- __name(transformElement, "transformElement");
516
- function isFragmentTag(tagName) {
517
- return tagName.getText() === "Fragment" || tagName.getText() === "Vobs.Fragment";
518
- }
519
- __name(isFragmentTag, "isFragmentTag");
520
- function transformFragment(state, children) {
521
- const parent = nextIdentifier(state, "_fragmentParent");
522
- const anchor = nextIdentifier(state, "_fragmentAnchor");
523
- const statements = [];
524
- appendChildren(state, statements, parent, children, anchor);
525
- return ts.factory.createCallExpression(
526
- helperRef(state, "createFragment"),
527
- void 0,
528
- [ts.factory.createArrowFunction(
529
- void 0,
530
- void 0,
531
- [
532
- ts.factory.createParameterDeclaration(void 0, void 0, parent),
533
- ts.factory.createParameterDeclaration(void 0, void 0, anchor)
534
- ],
535
- void 0,
536
- ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
537
- ts.factory.createBlock(statements, true)
538
- )]
539
- );
540
- }
541
- __name(transformFragment, "transformFragment");
542
- function transformResourceBoundary(state, node, attributes, children) {
543
- const resource = getAttributeExpression(attributes, "resource");
544
- if (!resource) throw new VobsError({ code: "VOBS_C002", layer: "compiler", message: "ResourceBoundary \u5FC5\u987B\u63D0\u4F9B resource \u5C5E\u6027", fix: "\u4E3A ResourceBoundary \u6DFB\u52A0 resource={resource}\u3002" });
545
- const options = [
546
- ts.factory.createPropertyAssignment("resource", transformEmbeddedExpression(state, resource)),
547
- ts.factory.createPropertyAssignment("children", createBoundaryFactory(state, children))
548
- ];
549
- appendBoundaryOptionalProperty(state, options, attributes, "loading");
550
- appendBoundaryOptionalProperty(state, options, attributes, "empty");
551
- appendBoundaryOptionalProperty(state, options, attributes, "fallback");
552
- return createBoundaryFragment(state, node, "insertResourceBoundary", options);
553
- }
554
- __name(transformResourceBoundary, "transformResourceBoundary");
555
- function transformErrorBoundary(state, node, attributes, children) {
556
- const fallback = getAttributeExpression(attributes, "fallback");
557
- if (!fallback) throw new VobsError({ code: "VOBS_C002", layer: "compiler", message: "ErrorBoundary \u5FC5\u987B\u63D0\u4F9B fallback \u5C5E\u6027", fix: "\u4E3A ErrorBoundary \u6DFB\u52A0 fallback={(error, retry) => ...}\u3002" });
558
- return createBoundaryFragment(state, node, "insertErrorBoundary", [
559
- ts.factory.createPropertyAssignment("children", createBoundaryFactory(state, children)),
560
- ts.factory.createPropertyAssignment("fallback", transformEmbeddedExpression(state, fallback))
561
- ]);
562
- }
563
- __name(transformErrorBoundary, "transformErrorBoundary");
564
- function transformAsyncBoundary(state, node, attributes, children) {
565
- const promise = getAttributeExpression(attributes, "promise");
566
- if (!promise) throw new VobsError({ code: "VOBS_C002", layer: "compiler", message: "AsyncBoundary \u5FC5\u987B\u63D0\u4F9B promise \u5C5E\u6027", fix: "\u4E3A AsyncBoundary \u6DFB\u52A0 promise={promise}\u3002" });
567
- const options = [
568
- ts.factory.createPropertyAssignment("promise", transformEmbeddedExpression(state, promise)),
569
- ts.factory.createPropertyAssignment("children", createAsyncFactory(state, children))
570
- ];
571
- appendBoundaryOptionalProperty(state, options, attributes, "loading");
572
- appendBoundaryOptionalProperty(state, options, attributes, "fallback");
573
- const resetKey = getAttributeExpression(attributes, "resetKey");
574
- if (resetKey) options.push(ts.factory.createPropertyAssignment("resetKey", createGetter(resetKey)));
575
- return createBoundaryFragment(state, node, "insertAsyncBoundary", options);
576
- }
577
- __name(transformAsyncBoundary, "transformAsyncBoundary");
578
- function transformProfiler(state, node, attributes, children) {
579
- const idAttribute = attributes.properties.find((attribute) => ts.isJsxAttribute(attribute) && attribute.name.getText() === "id");
580
- const id = idAttribute && ts.isJsxAttribute(idAttribute) && idAttribute.initializer && ts.isStringLiteral(idAttribute.initializer) ? ts.factory.createStringLiteral(idAttribute.initializer.text) : idAttribute && ts.isJsxAttribute(idAttribute) && idAttribute.initializer && ts.isJsxExpression(idAttribute.initializer) ? idAttribute.initializer.expression : null;
581
- if (!id) throw new VobsError({ code: "VOBS_C002", layer: "compiler", message: "Profiler \u5FC5\u987B\u63D0\u4F9B id \u5C5E\u6027", fix: '\u4E3A Profiler \u6DFB\u52A0 id="ComponentName"\u3002' });
582
- const options = [
583
- ts.factory.createPropertyAssignment("id", transformEmbeddedExpression(state, id)),
584
- ts.factory.createPropertyAssignment("children", createBoundaryFactory(state, children))
585
- ];
586
- appendBoundaryOptionalProperty(state, options, attributes, "onRender");
587
- return createBoundaryFragment(state, node, "insertProfiler", options);
588
- }
589
- __name(transformProfiler, "transformProfiler");
590
- function createBoundaryFragment(state, node, helper, options) {
591
- const parent = nextIdentifier(state, "_boundaryParent");
592
- const anchor = nextIdentifier(state, "_boundaryAnchor");
593
- return ts.factory.createCallExpression(
594
- helperRef(state, "createFragment"),
595
- void 0,
596
- [ts.factory.createArrowFunction(
597
- void 0,
598
- void 0,
599
- [
600
- ts.factory.createParameterDeclaration(void 0, void 0, parent),
601
- ts.factory.createParameterDeclaration(void 0, void 0, anchor)
602
- ],
603
- void 0,
604
- ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
605
- ts.factory.createBlock([callStatement(state, helper, [
606
- parent,
607
- anchor,
608
- ts.factory.createObjectLiteralExpression(options, true)
609
- ], node)], true)
610
- )]
611
- );
612
- }
613
- __name(createBoundaryFragment, "createBoundaryFragment");
614
- function createBoundaryFactory(state, children) {
615
- const content = transformFragment(state, children);
616
- return ts.factory.createArrowFunction(
617
- void 0,
618
- void 0,
619
- [],
620
- void 0,
621
- ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
622
- content
623
- );
624
- }
625
- __name(createBoundaryFactory, "createBoundaryFactory");
626
- function createAsyncFactory(state, children) {
627
- const value = ts.factory.createIdentifier("value");
628
- const expressionChild = children.length === 1 && children[0].kind === ts.SyntaxKind.JsxExpression ? children[0].expression : void 0;
629
- if (expressionChild && ts.isArrowFunction(expressionChild)) {
630
- const transformed = transformEmbeddedExpression(state, expressionChild);
631
- return transformed;
632
- }
633
- const content = transformFragment(state, children);
634
- return ts.factory.createArrowFunction(void 0, void 0, [
635
- ts.factory.createParameterDeclaration(void 0, void 0, value)
636
- ], void 0, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), content);
637
- }
638
- __name(createAsyncFactory, "createAsyncFactory");
639
- function appendBoundaryOptionalProperty(state, properties, attributes, name) {
640
- const expression = getAttributeExpression(attributes, name);
641
- if (expression) {
642
- const transformed = transformEmbeddedExpression(state, expression);
643
- const value = isJsxExpression(unwrapExpression(expression)) ? createGetter(transformed) : transformed;
644
- properties.push(ts.factory.createPropertyAssignment(name, value));
645
- }
646
- }
647
- __name(appendBoundaryOptionalProperty, "appendBoundaryOptionalProperty");
648
- function getAttributeExpression(attributes, name) {
649
- for (const attribute of attributes.properties) {
650
- if (!ts.isJsxAttribute(attribute) || attribute.name.getText() !== name) continue;
651
- if (attribute.initializer && ts.isJsxExpression(attribute.initializer)) {
652
- return attribute.initializer.expression ?? null;
653
- }
654
- }
655
- return null;
656
- }
657
- __name(getAttributeExpression, "getAttributeExpression");
658
- function transformEmbeddedExpression(state, expression) {
659
- const result = ts.transform(expression, [(context) => (root) => {
660
- const visit = /* @__PURE__ */ __name((node) => {
661
- if (ts.isJsxElement(node) || ts.isJsxSelfClosingElement(node) || ts.isJsxFragment(node)) {
662
- return transformJsxExpression(state, node);
663
- }
664
- return ts.visitEachChild(node, visit, context);
665
- }, "visit");
666
- return ts.visitNode(root, visit);
667
- }]);
668
- try {
669
- return result.transformed[0];
670
- } finally {
671
- result.dispose();
672
- }
673
- }
674
- __name(transformEmbeddedExpression, "transformEmbeddedExpression");
675
- function isStaticElement(tagName, attributes, children) {
676
- if (!ts.isIdentifier(tagName) || !/^[a-z]/.test(tagName.text)) return false;
677
- for (const attribute of attributes.properties) {
678
- if (ts.isJsxSpreadAttribute(attribute)) return false;
679
- if (!ts.isJsxAttribute(attribute)) return false;
680
- const name = attribute.name.getText();
681
- if (name === "key" || name === "ref" || name.startsWith("on")) return false;
682
- if (isPropertyAttribute(name)) return false;
683
- const initializer = attribute.initializer;
684
- if (initializer && !ts.isStringLiteral(initializer)) return false;
685
- }
686
- for (const child of children) {
687
- if (ts.isJsxText(child)) continue;
688
- if (ts.isJsxElement(child) || ts.isJsxSelfClosingElement(child)) {
689
- const nested = ts.isJsxElement(child) ? { tagName: child.openingElement.tagName, attributes: child.openingElement.attributes, children: child.children } : { tagName: child.tagName, attributes: child.attributes, children: [] };
690
- if (!isStaticElement(nested.tagName, nested.attributes, nested.children)) return false;
691
- continue;
692
- }
693
- return false;
694
- }
695
- return true;
696
- }
697
- __name(isStaticElement, "isStaticElement");
698
- function serializeStaticHtml(node) {
699
- const { tagName, attributes, children } = ts.isJsxElement(node) ? { tagName: node.openingElement.tagName, attributes: node.openingElement.attributes, children: node.children } : { tagName: node.tagName, attributes: node.attributes, children: [] };
700
- return serializeStaticElement(tagName, attributes, children);
701
- }
702
- __name(serializeStaticHtml, "serializeStaticHtml");
703
- function serializeStaticElement(tagName, attributes, children) {
704
- const name = tagName.getText();
705
- let html = `<${name}`;
706
- for (const attribute of attributes.properties) {
707
- if (!ts.isJsxAttribute(attribute)) continue;
708
- const attributeName = attribute.name.getText() === "className" ? "class" : attribute.name.getText();
709
- const initializer = attribute.initializer;
710
- if (!initializer) {
711
- html += ` ${attributeName}=""`;
712
- continue;
713
- }
714
- if (ts.isStringLiteral(initializer)) {
715
- html += ` ${attributeName}="${escapeHtmlAttribute(initializer.text)}"`;
716
- }
717
- }
718
- html += ">";
719
- for (const child of children) {
720
- if (ts.isJsxText(child)) {
721
- const text = child.text.replace(/\s+/g, " ").trimStart();
722
- if (text.trim()) html += escapeHtmlText(text);
723
- continue;
724
- }
725
- if (ts.isJsxElement(child)) {
726
- html += serializeStaticElement(
727
- child.openingElement.tagName,
728
- child.openingElement.attributes,
729
- child.children
730
- );
731
- continue;
732
- }
733
- if (ts.isJsxSelfClosingElement(child)) {
734
- html += serializeStaticElement(child.tagName, child.attributes, []);
735
- }
736
- }
737
- html += `</${name}>`;
738
- return html;
739
- }
740
- __name(serializeStaticElement, "serializeStaticElement");
741
- function escapeHtmlAttribute(value) {
742
- return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;");
743
- }
744
- __name(escapeHtmlAttribute, "escapeHtmlAttribute");
745
- function escapeHtmlText(value) {
746
- return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
747
- }
748
- __name(escapeHtmlText, "escapeHtmlText");
749
- function registerTemplate(state, html) {
750
- const existing = state.templates.get(html);
751
- if (existing) return existing;
752
- const identifier = nextIdentifier(state, "_tpl");
753
- state.templates.set(html, identifier);
754
- return identifier;
755
- }
756
- __name(registerTemplate, "registerTemplate");
757
- function createTemplateDeclarations(state) {
758
- return [...state.templates.entries()].map(
759
- ([html, identifier]) => ts.factory.createVariableStatement(void 0, ts.factory.createVariableDeclarationList([
760
- ts.factory.createVariableDeclaration(identifier, void 0, void 0, ts.factory.createCallExpression(
761
- helperRef(state, "createTemplate"),
762
- void 0,
763
- [ts.factory.createStringLiteral(html)]
764
- ))
765
- ], ts.NodeFlags.Const))
766
- );
767
- }
768
- __name(createTemplateDeclarations, "createTemplateDeclarations");
769
- function appendAttributes(state, statements, element, attributes) {
770
- const staticProps = [];
771
- const hasSpread = attributes.properties.some((attribute) => ts.isJsxSpreadAttribute(attribute));
772
- for (const attribute of attributes.properties) {
773
- if (ts.isJsxSpreadAttribute(attribute)) {
774
- statements.push(callStatement(state, "spreadProps", [element, transformEmbeddedExpression(state, attribute.expression)], attribute));
775
- continue;
776
- }
777
- if (!ts.isJsxAttribute(attribute)) continue;
778
- const name = attribute.name.getText();
779
- if (name === "key") continue;
780
- if (name === "ref") {
781
- const initializer2 = attribute.initializer;
782
- if (initializer2 && ts.isJsxExpression(initializer2) && initializer2.expression) {
783
- statements.push(callStatement(state, "setRef", [element, transformEmbeddedExpression(state, initializer2.expression)], attribute));
784
- }
785
- continue;
786
- }
787
- const initializer = attribute.initializer;
788
- if (name.startsWith("on") && initializer && ts.isJsxExpression(initializer) && initializer.expression) {
789
- statements.push(callStatement(state, "addEventListener", [
790
- element,
791
- ts.factory.createStringLiteral(name.slice(2).toLowerCase()),
792
- initializer.expression
793
- ], attribute));
794
- continue;
795
- }
796
- if (!initializer) {
797
- if (hasSpread) {
798
- statements.push(callStatement(state, isPropertyAttribute(name) ? "setProperty" : "setAttribute", [element, ts.factory.createStringLiteral(isPropertyAttribute(name) ? name : name === "className" ? "class" : name), isPropertyAttribute(name) ? ts.factory.createTrue() : ts.factory.createStringLiteral("")], attribute));
799
- continue;
800
- }
801
- if (isPropertyAttribute(name)) staticProps.push(createStaticProperty(name, ts.factory.createTrue()));
802
- else staticProps.push(createStaticProperty(name === "className" ? "class" : name, ts.factory.createStringLiteral("")));
803
- continue;
804
- }
805
- if (ts.isStringLiteral(initializer)) {
806
- if (hasSpread) {
807
- statements.push(callStatement(state, isPropertyAttribute(name) ? "setProperty" : "setAttribute", [element, ts.factory.createStringLiteral(isPropertyAttribute(name) ? name : name === "className" ? "class" : name), ts.factory.createStringLiteral(initializer.text)], attribute));
808
- continue;
809
- }
810
- staticProps.push(createStaticProperty(
811
- isPropertyAttribute(name) ? name : name === "className" ? "class" : name,
812
- ts.factory.createStringLiteral(initializer.text)
813
- ));
814
- continue;
815
- }
816
- const attributeName = name === "className" ? "class" : name;
817
- const propertyAttribute = isPropertyAttribute(name);
818
- if (ts.isJsxExpression(initializer) && initializer.expression) {
819
- statements.push(callStatement(state, propertyAttribute ? "bindProperty" : "bindAttribute", [
820
- element,
821
- ts.factory.createStringLiteral(propertyAttribute ? name : attributeName),
822
- createGetter(initializer.expression)
823
- ], attribute));
824
- }
825
- }
826
- if (staticProps.length) statements.splice(1, 0, callStatement(state, "setStaticProps", [
827
- element,
828
- ts.factory.createObjectLiteralExpression(staticProps, true)
829
- ], attributes));
830
- }
831
- __name(appendAttributes, "appendAttributes");
832
- function createStaticProperty(name, value) {
833
- return ts.factory.createPropertyAssignment(ts.factory.createStringLiteral(name), value);
834
- }
835
- __name(createStaticProperty, "createStaticProperty");
836
- function isPropertyAttribute(name) {
837
- return name === "value" || name === "checked" || name === "selected" || name === "disabled" || name === "multiple" || name === "readOnly" || name === "required" || name === "autofocus" || name === "hidden" || name === "tabIndex";
838
- }
839
- __name(isPropertyAttribute, "isPropertyAttribute");
840
- function appendChildren(state, statements, element, children, anchor = ts.factory.createNull()) {
841
- for (const child of children) {
842
- if (ts.isJsxText(child)) {
843
- const text = child.text.replace(/\s+/g, " ").trimStart();
844
- if (text.trim()) {
845
- statements.push(callStatement(state, "insertBefore", [
846
- element,
847
- ts.factory.createCallExpression(helperRef(state, "createText"), void 0, [
848
- ts.factory.createStringLiteral(text)
849
- ]),
850
- anchor
851
- ], child));
852
- }
853
- continue;
854
- }
855
- if (ts.isJsxElement(child) || ts.isJsxSelfClosingElement(child) || ts.isJsxFragment(child)) {
856
- statements.push(callStatement(state, "insertBefore", [
857
- element,
858
- transformJsxExpression(state, child),
859
- anchor
860
- ], child));
861
- continue;
862
- }
863
- if (child.kind === ts.SyntaxKind.JsxExpression) {
864
- const expression = child.expression;
865
- if (!expression) continue;
866
- const list = transformListExpression(state, element, expression, anchor);
867
- if (list) {
868
- statements.push(callStatement(state, "insertList", list, child));
869
- continue;
870
- }
871
- const dynamic = transformDynamicExpression(state, expression);
872
- if (dynamic) {
873
- statements.push(callStatement(state, "insertDynamic", [element, anchor, dynamic], child));
874
- continue;
875
- }
876
- if (!containsJsx(expression) && !ts.isIdentifier(expression)) {
877
- const textId = nextIdentifier(state, "_text");
878
- statements.push(createConstStatement(state, textId, ts.factory.createCallExpression(helperRef(state, "createText"), void 0, [ts.factory.createStringLiteral("")]), child));
879
- statements.push(callStatement(state, "insertBefore", [element, textId, anchor], child));
880
- statements.push(callStatement(state, "bindText", [textId, createGetter(expression)], child));
881
- continue;
882
- }
883
- const value = transformEmbeddedExpression(state, expression);
884
- statements.push(callStatement(state, "insertDynamicValue", [element, anchor, createGetter(value)], child));
885
- }
886
- }
887
- }
888
- __name(appendChildren, "appendChildren");
889
- function createComponentProps(state, attributes, children) {
890
- const properties = [];
891
- for (const attribute of attributes.properties) {
892
- if (ts.isJsxSpreadAttribute(attribute)) {
893
- properties.push(ts.factory.createSpreadAssignment(attribute.expression));
894
- continue;
895
- }
896
- const name = propertyName(attribute.name.getText());
897
- if (attribute.name.getText() === "key") continue;
898
- const initializer = attribute.initializer;
899
- if (!initializer) {
900
- properties.push(ts.factory.createPropertyAssignment(name, ts.factory.createTrue()));
901
- } else if (ts.isStringLiteral(initializer)) {
902
- properties.push(ts.factory.createPropertyAssignment(name, ts.factory.createStringLiteral(initializer.text)));
903
- } else if (ts.isJsxExpression(initializer) && initializer.expression) {
904
- properties.push(createGetterProperty(name, transformEmbeddedExpression(state, initializer.expression)));
905
- }
906
- }
907
- const childExpressions = children.flatMap((child) => childToComponentExpression(state, child));
908
- if (childExpressions.length === 1) {
909
- properties.push(createGetterProperty("children", childExpressions[0]));
910
- } else if (childExpressions.length > 1) {
911
- properties.push(createGetterProperty("children", ts.factory.createArrayLiteralExpression(childExpressions)));
912
- }
913
- return ts.factory.createObjectLiteralExpression(properties, true);
914
- }
915
- __name(createComponentProps, "createComponentProps");
916
- function createSourceLocation(node) {
917
- const sourceFile = node.getSourceFile();
918
- const position = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
919
- return ts.factory.createObjectLiteralExpression([
920
- ts.factory.createPropertyAssignment("file", ts.factory.createStringLiteral(sourceFile.fileName)),
921
- ts.factory.createPropertyAssignment("line", ts.factory.createNumericLiteral(position.line + 1)),
922
- ts.factory.createPropertyAssignment("column", ts.factory.createNumericLiteral(position.character + 1))
923
- ], true);
924
- }
925
- __name(createSourceLocation, "createSourceLocation");
926
- function transformDynamicExpression(state, expression) {
927
- if (ts.isBinaryExpression(expression) && expression.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken) {
928
- const right = unwrapExpression(expression.right);
929
- if (!isJsxExpression(right)) return null;
930
- return createGetter(ts.factory.createConditionalExpression(
931
- expression.left,
932
- ts.factory.createToken(ts.SyntaxKind.QuestionToken),
933
- transformJsxExpression(state, right),
934
- ts.factory.createToken(ts.SyntaxKind.ColonToken),
935
- ts.factory.createNull()
936
- ));
937
- }
938
- if (ts.isConditionalExpression(expression)) {
939
- const whenTrue = transformDynamicBranch(state, expression.whenTrue);
940
- const whenFalse = transformDynamicBranch(state, expression.whenFalse);
941
- if (!whenTrue && !whenFalse) return null;
942
- return createGetter(ts.factory.createConditionalExpression(
943
- expression.condition,
944
- ts.factory.createToken(ts.SyntaxKind.QuestionToken),
945
- whenTrue ?? ts.factory.createNull(),
946
- ts.factory.createToken(ts.SyntaxKind.ColonToken),
947
- whenFalse ?? ts.factory.createNull()
948
- ));
949
- }
950
- return null;
951
- }
952
- __name(transformDynamicExpression, "transformDynamicExpression");
953
- function transformDynamicBranch(state, expression) {
954
- const branch = unwrapExpression(expression);
955
- if (isJsxExpression(branch)) return transformJsxExpression(state, branch);
956
- if (branch.kind === ts.SyntaxKind.NullKeyword || branch.kind === ts.SyntaxKind.FalseKeyword) return branch;
957
- return null;
958
- }
959
- __name(transformDynamicBranch, "transformDynamicBranch");
960
- function transformListExpression(state, parent, expression, anchor) {
961
- if (!ts.isCallExpression(expression) || expression.arguments.length !== 1) return null;
962
- if (!ts.isPropertyAccessExpression(expression.expression) || expression.expression.name.text !== "map") return null;
963
- const callback = expression.arguments[0];
964
- if (!ts.isArrowFunction(callback) && !ts.isFunctionExpression(callback)) return null;
965
- const body = unwrapExpression(callback.body);
966
- if (!isJsxExpression(body) || ts.isJsxFragment(body)) return null;
967
- const key = findKeyExpression(body);
968
- const renderItem = transformListCallback(callback, transformJsxExpression(state, body));
969
- const args = [
970
- parent,
971
- anchor,
972
- createGetter(expression.expression.expression),
973
- renderItem
974
- ];
975
- if (key) args.push(createKeyCallback(callback, key));
976
- return args;
977
- }
978
- __name(transformListExpression, "transformListExpression");
979
- function transformListCallback(callback, body) {
980
- if (ts.isArrowFunction(callback)) {
981
- return ts.factory.updateArrowFunction(
982
- callback,
983
- callback.modifiers,
984
- callback.typeParameters,
985
- callback.parameters,
986
- callback.type,
987
- callback.equalsGreaterThanToken,
988
- body
989
- );
990
- }
991
- return ts.factory.updateFunctionExpression(
992
- callback,
993
- callback.modifiers,
994
- callback.asteriskToken,
995
- callback.name,
996
- callback.typeParameters,
997
- callback.parameters,
998
- callback.type,
999
- ts.factory.createBlock([ts.factory.createReturnStatement(body)], true)
1000
- );
1001
- }
1002
- __name(transformListCallback, "transformListCallback");
1003
- function createKeyCallback(callback, key) {
1004
- return ts.factory.createArrowFunction(
1005
- void 0,
1006
- void 0,
1007
- callback.parameters,
1008
- void 0,
1009
- ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
1010
- key
1011
- );
1012
- }
1013
- __name(createKeyCallback, "createKeyCallback");
1014
- function findKeyExpression(node) {
1015
- const attributes = ts.isJsxElement(node) ? node.openingElement.attributes : node.attributes;
1016
- for (const attribute of attributes.properties) {
1017
- if (!ts.isJsxAttribute(attribute) || attribute.name.getText() !== "key") continue;
1018
- if (attribute.initializer && ts.isJsxExpression(attribute.initializer)) {
1019
- return attribute.initializer.expression ?? null;
1020
- }
1021
- }
1022
- return null;
1023
- }
1024
- __name(findKeyExpression, "findKeyExpression");
1025
- function unwrapExpression(node) {
1026
- return ts.isParenthesizedExpression(node) ? node.expression : node;
1027
- }
1028
- __name(unwrapExpression, "unwrapExpression");
1029
- function childToComponentExpression(state, child) {
1030
- if (ts.isJsxText(child)) {
1031
- const text = child.text.replace(/\s+/g, " ").trim();
1032
- return text ? [ts.factory.createStringLiteral(text)] : [];
1033
- }
1034
- if (ts.isJsxElement(child) || ts.isJsxSelfClosingElement(child) || ts.isJsxFragment(child)) {
1035
- return [transformJsxExpression(state, child)];
1036
- }
1037
- if (child.kind === ts.SyntaxKind.JsxExpression) {
1038
- const expression = child.expression;
1039
- return expression ? [transformEmbeddedExpression(state, expression)] : [];
1040
- }
1041
- return [];
1042
- }
1043
- __name(childToComponentExpression, "childToComponentExpression");
1044
- function propertyName(name) {
1045
- return /^[$A-Z_a-z][$\w]*$/u.test(name) ? ts.factory.createIdentifier(name) : ts.factory.createStringLiteral(name);
1046
- }
1047
- __name(propertyName, "propertyName");
1048
- function createGetter(expression) {
1049
- return ts.factory.createArrowFunction(
1050
- void 0,
1051
- void 0,
1052
- [],
1053
- void 0,
1054
- ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
1055
- expression
1056
- );
1057
- }
1058
- __name(createGetter, "createGetter");
1059
- function createGetterProperty(name, expression) {
1060
- return ts.factory.createGetAccessorDeclaration(
1061
- void 0,
1062
- typeof name === "string" ? propertyName(name) : name,
1063
- [],
1064
- void 0,
1065
- ts.factory.createBlock([ts.factory.createReturnStatement(expression)], true)
1066
- );
1067
- }
1068
- __name(createGetterProperty, "createGetterProperty");
1069
- function callStatement(state, name, args, source) {
1070
- const statement = ts.factory.createExpressionStatement(
1071
- ts.factory.createCallExpression(helperRef(state, name), void 0, args)
1072
- );
1073
- return source ? tagStatement(state, statement, source) : statement;
1074
- }
1075
- __name(callStatement, "callStatement");
1076
- function createConstStatement(state, name, initializer, source) {
1077
- const statement = ts.factory.createVariableStatement(
1078
- void 0,
1079
- ts.factory.createVariableDeclarationList([
1080
- ts.factory.createVariableDeclaration(name, void 0, void 0, initializer)
1081
- ], ts.NodeFlags.Const)
1082
- );
1083
- return source ? tagStatement(state, statement, source) : statement;
1084
- }
1085
- __name(createConstStatement, "createConstStatement");
1086
- function tagStatement(state, statement, source) {
1087
- const position = positionOfNode(state, source);
1088
- if (position) state.statementSources.set(statement, position);
1089
- return statement;
1090
- }
1091
- __name(tagStatement, "tagStatement");
1092
- function positionOfNode(state, node) {
1093
- const sourceFile = node.getSourceFile() ?? state.sourceFile;
1094
- if (!sourceFile || node.pos < 0) return null;
1095
- const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
1096
- return { line, column: character };
1097
- }
1098
- __name(positionOfNode, "positionOfNode");
1099
- function nextIdentifier(state, prefix) {
1100
- let name;
1101
- do {
1102
- name = `${prefix}${state.generatedId++}`;
1103
- } while (state.takenNames.has(name));
1104
- return ts.factory.createIdentifier(name);
1105
- }
1106
- __name(nextIdentifier, "nextIdentifier");
1107
- function createI18nExtractor(options = {}) {
1108
- const names = new Set(options.functions ?? ["t"]);
1109
- const keys = /* @__PURE__ */ new Set();
1110
- const plugin = {
1111
- name: "i18n-extractor",
1112
- analyze(program, context) {
1113
- const visit = /* @__PURE__ */ __name((node) => {
1114
- if (ts.isCallExpression(node) && isTranslationCall(node.expression, names)) {
1115
- const key = readStaticKey(node.arguments[0]);
1116
- if (key) {
1117
- keys.add(key);
1118
- options.onKey?.(key, context.filename);
1119
- }
1120
- }
1121
- ts.forEachChild(node, visit);
1122
- }, "visit");
1123
- visit(program);
1124
- }
1125
- };
1126
- return {
1127
- plugin,
1128
- getKeys: /* @__PURE__ */ __name(() => [...keys].sort(), "getKeys"),
1129
- reset: /* @__PURE__ */ __name(() => keys.clear(), "reset")
1130
- };
1131
- }
1132
- __name(createI18nExtractor, "createI18nExtractor");
1133
- function isTranslationCall(expression, names) {
1134
- if (ts.isIdentifier(expression)) return names.has(expression.text);
1135
- return ts.isPropertyAccessExpression(expression) && names.has(expression.name.text);
1136
- }
1137
- __name(isTranslationCall, "isTranslationCall");
1138
- function readStaticKey(argument) {
1139
- if (!argument) return void 0;
1140
- if (ts.isStringLiteral(argument) || ts.isNoSubstitutionTemplateLiteral(argument)) return argument.text;
1141
- return void 0;
1142
- }
1143
- __name(readStaticKey, "readStaticKey");
3
+
4
+ // packages/vite-plugin/src/index.ts
5
+ import { readFile } from "fs/promises";
6
+ import path from "path";
7
+ import { compileWithSourceMap, createI18nExtractor } from "@vobs/compiler";
8
+ import { VobsError } from "@vobs/runtime/error";
9
+
10
+ // packages/vite-plugin/src/html-component.ts
11
+ import { parseFragment } from "parse5";
1144
12
  var blockedTags = /* @__PURE__ */ new Set(["script", "iframe", "object", "embed", "base", "meta", "link", "style"]);
1145
13
  var blockedAttributes = /^(?:on[a-z]+|srcdoc|style)$/iu;
1146
14
  var urlAttributes = /* @__PURE__ */ new Set(["href", "src", "action", "formaction", "poster", "xlink:href"]);
@@ -1275,11 +143,13 @@ function vobsPlugin(options = {}) {
1275
143
  const include = options.include ?? /\.tsx(?:$|\?)/;
1276
144
  const htmlModules = /* @__PURE__ */ new Set();
1277
145
  let productionBuild = false;
146
+ let hmrStateEnabled = (options.hmr ?? true) && (options.hmrState ?? true);
1278
147
  return {
1279
148
  name: "vobs",
1280
149
  enforce: "pre",
1281
150
  configResolved(config) {
1282
151
  productionBuild = config.command === "build";
152
+ hmrStateEnabled = (options.hmr ?? true) && !productionBuild && (options.hmrState ?? true);
1283
153
  },
1284
154
  resolveId(source, importer) {
1285
155
  if (!importer || !isHtmlComponent(source, options.html) || !isRelativeModule(source)) return null;
@@ -1294,14 +164,24 @@ function vobsPlugin(options = {}) {
1294
164
  return compileHtmlComponent(await readFile(id, "utf8"), { filename: id });
1295
165
  },
1296
166
  transform(code, id) {
1297
- include.lastIndex = 0;
1298
- if (!include.test(id)) return null;
167
+ const cleanId = id.split(/[?#]/u, 1)[0];
168
+ const isTsx = cleanId.endsWith(".tsx");
169
+ const isStateTs = isStateModulePath(cleanId);
170
+ if (!isTsx && !isStateTs) return null;
171
+ if (options.include) {
172
+ include.lastIndex = 0;
173
+ if (!include.test(id)) return null;
174
+ }
175
+ if (!isTsx && (!hmrStateEnabled || !isStatefulModule(code))) return null;
1299
176
  const extractor = options.extractI18n ? createI18nExtractor({ onKey: options.extractI18n }) : void 0;
177
+ const hmr = options.hmr ?? !productionBuild;
1300
178
  const result = compileWithSourceMap(code, {
1301
179
  ...options.compiler,
1302
180
  // 生产构建默认剔除组件源码位置(错误定位走 source map);显式配置优先。
1303
181
  sourceLocation: options.compiler?.sourceLocation ?? !productionBuild,
1304
182
  filename: id,
183
+ // HMR 模块标识必须跨 ?t= 查询稳定(registry 复用语义依赖它),用干净路径。
184
+ hmrModuleId: hmr ? cleanId : options.compiler?.hmrModuleId,
1305
185
  plugins: [
1306
186
  ...options.compiler?.plugins ?? [],
1307
187
  ...extractor ? [extractor.plugin] : []
@@ -1318,8 +198,7 @@ function vobsPlugin(options = {}) {
1318
198
  fix: diagnostic.fix
1319
199
  });
1320
200
  }
1321
- const hmr = options.hmr ?? !productionBuild;
1322
- const hmrCode = hmr ? createHmrCode(id) : "";
201
+ const hmrCode = hmr ? createHmrCode(cleanId) : "";
1323
202
  return {
1324
203
  code: `${result.code}${hmrCode}`,
1325
204
  map: result.map
@@ -1328,6 +207,17 @@ function vobsPlugin(options = {}) {
1328
207
  };
1329
208
  }
1330
209
  __name(vobsPlugin, "vobsPlugin");
210
+ function isStatefulModule(code) {
211
+ return /\bimport\s+(?:type\s+)?\{[^}]*\bstate\b[^}]*\}\s*from\s*['"]@vobs\/(?:reactivity|vobs)['"]/u.test(code) && /(?<![\w$.])state\s*\(/u.test(code);
212
+ }
213
+ __name(isStatefulModule, "isStatefulModule");
214
+ function isStateModulePath(cleanId) {
215
+ if (!cleanId.endsWith(".ts")) return false;
216
+ if (cleanId.endsWith(".d.ts")) return false;
217
+ if (cleanId.includes("node_modules")) return false;
218
+ return true;
219
+ }
220
+ __name(isStateModulePath, "isStateModulePath");
1331
221
  function isRelativeModule(source) {
1332
222
  return source.startsWith("./") || source.startsWith("../");
1333
223
  }
@@ -1353,7 +243,7 @@ if (import.meta.hot) {
1353
243
  `;
1354
244
  }
1355
245
  __name(createHmrCode, "createHmrCode");
1356
-
1357
- export { vobsPlugin };
1358
- //# sourceMappingURL=index.js.map
246
+ export {
247
+ vobsPlugin
248
+ };
1359
249
  //# sourceMappingURL=index.js.map