@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.
@@ -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"]}
@@ -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
@@ -1 +1 @@
1
- {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"AAgLA;;;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,CAiSnD;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"}
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
- const output = (_top ? _top + '\n' : '') + printer.printFile(transformed) + (_bottom ? '\n' + _bottom : '');
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