@llui/vite-plugin 0.0.29 → 0.0.31
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/compiler-cache.d.ts +20 -0
- package/dist/compiler-cache.d.ts.map +1 -0
- package/dist/compiler-cache.js +20 -0
- package/dist/compiler-cache.js.map +1 -0
- package/dist/transform.d.ts +30 -2
- package/dist/transform.d.ts.map +1 -1
- package/dist/transform.js +95 -6
- package/dist/transform.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface BindingSourceEntry {
|
|
2
|
+
bindingIndex: number;
|
|
3
|
+
file: string;
|
|
4
|
+
line: number;
|
|
5
|
+
column: number;
|
|
6
|
+
}
|
|
7
|
+
export interface CompilerCacheEntry {
|
|
8
|
+
preSource: string;
|
|
9
|
+
postSource: string;
|
|
10
|
+
msgMaskMap: Record<string, number>;
|
|
11
|
+
bindingSources: BindingSourceEntry[];
|
|
12
|
+
}
|
|
13
|
+
export declare class CompilerCache {
|
|
14
|
+
private readonly cache;
|
|
15
|
+
set(componentName: string, entry: CompilerCacheEntry): void;
|
|
16
|
+
get(componentName: string): CompilerCacheEntry | undefined;
|
|
17
|
+
has(componentName: string): boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare const compilerCache: CompilerCache;
|
|
20
|
+
//# sourceMappingURL=compiler-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compiler-cache.d.ts","sourceRoot":"","sources":["../src/compiler-cache.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAA;IACpB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAClC,cAAc,EAAE,kBAAkB,EAAE,CAAA;CACrC;AAID,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAwC;IAE9D,GAAG,CAAC,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,GAAG,IAAI;IAQ3D,GAAG,CAAC,aAAa,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAI1D,GAAG,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO;CAGpC;AAED,eAAO,MAAM,aAAa,eAAsB,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const MAX_ENTRIES = 50;
|
|
2
|
+
export class CompilerCache {
|
|
3
|
+
cache = new Map();
|
|
4
|
+
set(componentName, entry) {
|
|
5
|
+
if (this.cache.has(componentName))
|
|
6
|
+
this.cache.delete(componentName);
|
|
7
|
+
this.cache.set(componentName, entry);
|
|
8
|
+
if (this.cache.size > MAX_ENTRIES) {
|
|
9
|
+
this.cache.delete(this.cache.keys().next().value);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
get(componentName) {
|
|
13
|
+
return this.cache.get(componentName);
|
|
14
|
+
}
|
|
15
|
+
has(componentName) {
|
|
16
|
+
return this.cache.has(componentName);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export const compilerCache = new CompilerCache();
|
|
20
|
+
//# sourceMappingURL=compiler-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compiler-cache.js","sourceRoot":"","sources":["../src/compiler-cache.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,GAAG,EAAE,CAAA;AAEtB,MAAM,OAAO,aAAa;IACP,KAAK,GAAG,IAAI,GAAG,EAA8B,CAAA;IAE9D,GAAG,CAAC,aAAqB,EAAE,KAAyB;QAClD,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC;YAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,CAAA;QACnE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,EAAE,KAAK,CAAC,CAAA;QACpC,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,WAAW,EAAE,CAAC;YAClC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAM,CAAC,CAAA;QACpD,CAAC;IACH,CAAC;IAED,GAAG,CAAC,aAAqB;QACvB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;IACtC,CAAC;IAED,GAAG,CAAC,aAAqB;QACvB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;IACtC,CAAC;CACF;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,aAAa,EAAE,CAAA","sourcesContent":["export interface BindingSourceEntry {\n bindingIndex: number\n file: string\n line: number\n column: number\n}\n\nexport interface CompilerCacheEntry {\n preSource: string\n postSource: string\n msgMaskMap: Record<string, number>\n bindingSources: BindingSourceEntry[]\n}\n\nconst MAX_ENTRIES = 50\n\nexport class CompilerCache {\n private readonly cache = new Map<string, CompilerCacheEntry>()\n\n set(componentName: string, entry: CompilerCacheEntry): void {\n if (this.cache.has(componentName)) this.cache.delete(componentName)\n this.cache.set(componentName, entry)\n if (this.cache.size > MAX_ENTRIES) {\n this.cache.delete(this.cache.keys().next().value!)\n }\n }\n\n get(componentName: string): CompilerCacheEntry | undefined {\n return this.cache.get(componentName)\n }\n\n has(componentName: string): boolean {\n return this.cache.has(componentName)\n }\n}\n\nexport const compilerCache = new CompilerCache()\n"]}
|
package/dist/transform.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
1
2
|
/**
|
|
2
3
|
* Transform a source file containing @llui/dom imports.
|
|
3
4
|
* Returns the transformed source or null if no transformation needed.
|
|
@@ -33,10 +34,10 @@ export interface UseClientTransformResult {
|
|
|
33
34
|
* - `export function foo() {}` and `export class Foo {}` — rewritten
|
|
34
35
|
* as stubs but the caller may be surprised that `foo` and `Foo` are
|
|
35
36
|
* ComponentDef-shaped objects during SSR.
|
|
36
|
-
* - `export { a, b } from './other'` — re-export forms are not
|
|
37
|
+
* - `export { a, b } from './other.js'` — re-export forms are not
|
|
37
38
|
* detected; they pass through and will still pull `./other` into
|
|
38
39
|
* the SSR graph.
|
|
39
|
-
* - `export * from './other'` — same as above.
|
|
40
|
+
* - `export * from './other.js'` — same as above.
|
|
40
41
|
* - `export type ...` — type exports are erased by TS so nothing to
|
|
41
42
|
* stub; left untouched.
|
|
42
43
|
*/
|
|
@@ -47,4 +48,31 @@ export declare function transformUseClientSsr(source: string, _filename: string)
|
|
|
47
48
|
* without parsing the whole file twice.
|
|
48
49
|
*/
|
|
49
50
|
export declare function hasUseClientDirective(source: string): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Extract the view function body (the value of the `view:` property) from
|
|
53
|
+
* a component() config object literal. Uses a regex heuristic — good enough
|
|
54
|
+
* for round-tripping source for dev/agent tools.
|
|
55
|
+
*/
|
|
56
|
+
export declare function extractViewBody(code: string): string | null;
|
|
57
|
+
/**
|
|
58
|
+
* Extract the component `name:` string literal from a component() call's
|
|
59
|
+
* first argument object literal in the source text.
|
|
60
|
+
*/
|
|
61
|
+
export declare function extractComponentNameFromConfig(node: ts.CallExpression): string | null;
|
|
62
|
+
/**
|
|
63
|
+
* Generate Object.defineProperty calls for __preSource, __postSource,
|
|
64
|
+
* __msgMaskMap, and __bindingSources on a component variable. These are
|
|
65
|
+
* non-enumerable so they don't appear in JSON.stringify(componentDef) but are
|
|
66
|
+
* visible to devtools.
|
|
67
|
+
*/
|
|
68
|
+
export declare function generateCompilerCacheProps(varName: string, componentName: string): string;
|
|
69
|
+
/**
|
|
70
|
+
* After the full output string is assembled, update each cached component's
|
|
71
|
+
* postSource (extract view body from the transformed output), then append
|
|
72
|
+
* Object.defineProperty calls for all four compiler-cache properties.
|
|
73
|
+
*/
|
|
74
|
+
export declare function appendCompilerCacheProps(output: string, componentDecls: Array<{
|
|
75
|
+
varName: string;
|
|
76
|
+
componentName: string;
|
|
77
|
+
}>): string;
|
|
50
78
|
//# sourceMappingURL=transform.d.ts.map
|
package/dist/transform.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAA;AAiL3B;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,UAAQ,EACf,iBAAiB,UAAQ,EACzB,OAAO,GAAE,MAAM,GAAG,IAAW,EAC7B,OAAO,UAAQ,GACd;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,aAAa,EAAE,CAAA;CAAE,GAAG,IAAI,CA8TnD;AAwoID,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,wBAAwB,GAAG,IAAI,CAoGjC;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CA4B7D;AAID;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI3D;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,GAAG,MAAM,GAAG,IAAI,CAcrF;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CASzF;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,KAAK,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC,GAChE,MAAM,CAYR"}
|
package/dist/transform.js
CHANGED
|
@@ -5,6 +5,7 @@ import { extractMsgAnnotations } from './msg-annotations.js';
|
|
|
5
5
|
import { extractStateSchema } from './state-schema.js';
|
|
6
6
|
import { computeSchemaHash } from './schema-hash.js';
|
|
7
7
|
import { extractBindingDescriptors } from './binding-descriptors.js';
|
|
8
|
+
import { compilerCache } from './compiler-cache.js';
|
|
8
9
|
function createMaskLiteral(f, mask) {
|
|
9
10
|
if (mask >= 0)
|
|
10
11
|
return f.createNumericLiteral(mask);
|
|
@@ -323,6 +324,22 @@ export function transformLlui(source, _filename, devMode = false, emitAgentMetad
|
|
|
323
324
|
if (bindingDescriptors.length > 0) {
|
|
324
325
|
result = injectBindingDescriptors(result ?? node, bindingDescriptors, f);
|
|
325
326
|
}
|
|
327
|
+
// Populate compiler cache — preSource and msgMaskMap are known now;
|
|
328
|
+
// postSource is filled in after the full output is assembled.
|
|
329
|
+
const cachedComponentName = extractComponentNameFromConfig(node);
|
|
330
|
+
if (cachedComponentName) {
|
|
331
|
+
const preSource = extractViewBody(source) ?? '';
|
|
332
|
+
const msgMaskMap = {};
|
|
333
|
+
for (const [path, bit] of fieldBits) {
|
|
334
|
+
msgMaskMap[path] = bit;
|
|
335
|
+
}
|
|
336
|
+
compilerCache.set(cachedComponentName, {
|
|
337
|
+
preSource,
|
|
338
|
+
postSource: '',
|
|
339
|
+
msgMaskMap,
|
|
340
|
+
bindingSources: [],
|
|
341
|
+
});
|
|
342
|
+
}
|
|
326
343
|
}
|
|
327
344
|
if (devMode) {
|
|
328
345
|
result = injectComponentMeta(result ?? node, node, sourceFile, _filename, f);
|
|
@@ -350,8 +367,8 @@ export function transformLlui(source, _filename, devMode = false, emitAgentMetad
|
|
|
350
367
|
transformed = cleanupImports(transformed, lluiImport, importedHelpers, safeToRemove, usesElSplit, usesElTemplate, usesMemo, usesApplyBinding, usesCloneStaticTemplate, f);
|
|
351
368
|
if (edits.length === 0)
|
|
352
369
|
return null;
|
|
353
|
-
// Find component declarations for HMR
|
|
354
|
-
const componentDecls = devMode ? findComponentDeclarations(sourceFile, lluiImport) : [];
|
|
370
|
+
// Find component declarations for HMR and agent metadata
|
|
371
|
+
const componentDecls = devMode || emitAgentMetadata ? findComponentDeclarations(sourceFile, lluiImport) : [];
|
|
355
372
|
// Build per-statement edits by comparing original vs transformed.
|
|
356
373
|
// Only emit edits for statements that actually changed.
|
|
357
374
|
// Untouched code keeps its original positions → accurate source maps.
|
|
@@ -371,7 +388,10 @@ export function transformLlui(source, _filename, devMode = false, emitAgentMetad
|
|
|
371
388
|
const { top: _top, bottom: _bottom } = devMode
|
|
372
389
|
? generateDevCode(componentDecls, mcpPort)
|
|
373
390
|
: { top: '', bottom: '' };
|
|
374
|
-
|
|
391
|
+
let output = (_top ? _top + '\n' : '') + printer.printFile(transformed) + (_bottom ? '\n' + _bottom : '');
|
|
392
|
+
if (devMode || emitAgentMetadata) {
|
|
393
|
+
output = appendCompilerCacheProps(output, componentDecls);
|
|
394
|
+
}
|
|
375
395
|
return { output, edits: [{ start: 0, end: source.length, replacement: output }] };
|
|
376
396
|
}
|
|
377
397
|
// Compare ignoring trailing semicolons and whitespace (printer adds them)
|
|
@@ -403,6 +423,13 @@ export function transformLlui(source, _filename, devMode = false, emitAgentMetad
|
|
|
403
423
|
for (const edit of sorted) {
|
|
404
424
|
output = output.slice(0, edit.start) + edit.replacement + output.slice(edit.end);
|
|
405
425
|
}
|
|
426
|
+
// After output is assembled, update postSource in cache and emit non-enumerable props
|
|
427
|
+
if ((devMode || emitAgentMetadata) && componentDecls.length > 0) {
|
|
428
|
+
const cacheProps = appendCompilerCacheProps(output, componentDecls);
|
|
429
|
+
if (cacheProps !== output) {
|
|
430
|
+
output = cacheProps;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
406
433
|
return { output, edits: finalEdits };
|
|
407
434
|
}
|
|
408
435
|
// ── HMR ──────────────────────────────────────────────────────────
|
|
@@ -3277,10 +3304,10 @@ function resolveChain(node, paramName) {
|
|
|
3277
3304
|
* - `export function foo() {}` and `export class Foo {}` — rewritten
|
|
3278
3305
|
* as stubs but the caller may be surprised that `foo` and `Foo` are
|
|
3279
3306
|
* ComponentDef-shaped objects during SSR.
|
|
3280
|
-
* - `export { a, b } from './other'` — re-export forms are not
|
|
3307
|
+
* - `export { a, b } from './other.js'` — re-export forms are not
|
|
3281
3308
|
* detected; they pass through and will still pull `./other` into
|
|
3282
3309
|
* the SSR graph.
|
|
3283
|
-
* - `export * from './other'` — same as above.
|
|
3310
|
+
* - `export * from './other.js'` — same as above.
|
|
3284
3311
|
* - `export type ...` — type exports are erased by TS so nothing to
|
|
3285
3312
|
* stub; left untouched.
|
|
3286
3313
|
*/
|
|
@@ -3338,7 +3365,7 @@ export function transformUseClientSsr(source, _filename) {
|
|
|
3338
3365
|
hasDefaultExport = true;
|
|
3339
3366
|
continue;
|
|
3340
3367
|
}
|
|
3341
|
-
// `export { a, b }` / `export { a } from './x'` / `export * from './x'`
|
|
3368
|
+
// `export { a, b }` / `export { a } from './x.js'` / `export * from './x.js'`
|
|
3342
3369
|
if (ts.isExportDeclaration(stmt)) {
|
|
3343
3370
|
if (stmt.moduleSpecifier) {
|
|
3344
3371
|
warnings.push("[llui/use-client] `export ... from '...'` re-export forms still pull the source module into the SSR graph and bypass stubbing. Either drop the re-export or move the 'use client' directive to the source module.");
|
|
@@ -3405,4 +3432,66 @@ export function hasUseClientDirective(source) {
|
|
|
3405
3432
|
}
|
|
3406
3433
|
return source.startsWith("'use client'", i) || source.startsWith('"use client"', i);
|
|
3407
3434
|
}
|
|
3435
|
+
// ── Compiler cache helpers ────────────────────────────────────────
|
|
3436
|
+
/**
|
|
3437
|
+
* Extract the view function body (the value of the `view:` property) from
|
|
3438
|
+
* a component() config object literal. Uses a regex heuristic — good enough
|
|
3439
|
+
* for round-tripping source for dev/agent tools.
|
|
3440
|
+
*/
|
|
3441
|
+
export function extractViewBody(code) {
|
|
3442
|
+
const match = /\bview\s*:\s*([\s\S]*?)(?=,\s*(?:onEffect|update|init|name|onMsg)\s*:|}\s*\))/m.exec(code);
|
|
3443
|
+
return match?.[1]?.trim() ?? null;
|
|
3444
|
+
}
|
|
3445
|
+
/**
|
|
3446
|
+
* Extract the component `name:` string literal from a component() call's
|
|
3447
|
+
* first argument object literal in the source text.
|
|
3448
|
+
*/
|
|
3449
|
+
export function extractComponentNameFromConfig(node) {
|
|
3450
|
+
const configArg = node.arguments[0];
|
|
3451
|
+
if (!configArg || !ts.isObjectLiteralExpression(configArg))
|
|
3452
|
+
return null;
|
|
3453
|
+
for (const prop of configArg.properties) {
|
|
3454
|
+
if (ts.isPropertyAssignment(prop) &&
|
|
3455
|
+
ts.isIdentifier(prop.name) &&
|
|
3456
|
+
prop.name.text === 'name' &&
|
|
3457
|
+
ts.isStringLiteral(prop.initializer)) {
|
|
3458
|
+
return prop.initializer.text;
|
|
3459
|
+
}
|
|
3460
|
+
}
|
|
3461
|
+
return null;
|
|
3462
|
+
}
|
|
3463
|
+
/**
|
|
3464
|
+
* Generate Object.defineProperty calls for __preSource, __postSource,
|
|
3465
|
+
* __msgMaskMap, and __bindingSources on a component variable. These are
|
|
3466
|
+
* non-enumerable so they don't appear in JSON.stringify(componentDef) but are
|
|
3467
|
+
* visible to devtools.
|
|
3468
|
+
*/
|
|
3469
|
+
export function generateCompilerCacheProps(varName, componentName) {
|
|
3470
|
+
const entry = compilerCache.get(componentName);
|
|
3471
|
+
if (!entry)
|
|
3472
|
+
return '';
|
|
3473
|
+
return (`\nObject.defineProperty(${varName}, '__preSource', { value: ${JSON.stringify(entry.preSource)}, enumerable: false, configurable: true })` +
|
|
3474
|
+
`\nObject.defineProperty(${varName}, '__postSource', { value: ${JSON.stringify(entry.postSource)}, enumerable: false, configurable: true })` +
|
|
3475
|
+
`\nObject.defineProperty(${varName}, '__msgMaskMap', { value: ${JSON.stringify(entry.msgMaskMap)}, enumerable: false, configurable: true })` +
|
|
3476
|
+
`\nObject.defineProperty(${varName}, '__bindingSources', { value: ${JSON.stringify(entry.bindingSources)}, enumerable: false, configurable: true })`);
|
|
3477
|
+
}
|
|
3478
|
+
/**
|
|
3479
|
+
* After the full output string is assembled, update each cached component's
|
|
3480
|
+
* postSource (extract view body from the transformed output), then append
|
|
3481
|
+
* Object.defineProperty calls for all four compiler-cache properties.
|
|
3482
|
+
*/
|
|
3483
|
+
export function appendCompilerCacheProps(output, componentDecls) {
|
|
3484
|
+
let result = output;
|
|
3485
|
+
for (const { varName, componentName } of componentDecls) {
|
|
3486
|
+
const existing = compilerCache.get(componentName);
|
|
3487
|
+
if (!existing)
|
|
3488
|
+
continue;
|
|
3489
|
+
// Update the cache entry with the post-transform view body
|
|
3490
|
+
const postSource = extractViewBody(output) ?? '';
|
|
3491
|
+
compilerCache.set(componentName, { ...existing, postSource });
|
|
3492
|
+
// Append non-enumerable property definitions
|
|
3493
|
+
result += generateCompilerCacheProps(varName, componentName);
|
|
3494
|
+
}
|
|
3495
|
+
return result;
|
|
3496
|
+
}
|
|
3408
3497
|
//# sourceMappingURL=transform.js.map
|