@llui/compiler 0.3.2 → 0.5.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/emit-names.d.ts +42 -0
- package/dist/emit-names.d.ts.map +1 -0
- package/dist/emit-names.js +73 -0
- package/dist/emit-names.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lint-modules.d.ts.map +1 -1
- package/dist/lint-modules.js +4 -0
- package/dist/lint-modules.js.map +1 -1
- package/dist/modules/no-repeated-item-current.d.ts +3 -0
- package/dist/modules/no-repeated-item-current.d.ts.map +1 -0
- package/dist/modules/no-repeated-item-current.js +164 -0
- package/dist/modules/no-repeated-item-current.js.map +1 -0
- package/dist/modules/no-sample-in-event-handler.d.ts +3 -0
- package/dist/modules/no-sample-in-event-handler.d.ts.map +1 -0
- package/dist/modules/no-sample-in-event-handler.js +101 -0
- package/dist/modules/no-sample-in-event-handler.js.map +1 -0
- package/dist/transform.d.ts.map +1 -1
- package/dist/transform.js +87 -45
- package/dist/transform.js.map +1 -1
- package/package.json +1 -1
package/dist/transform.js
CHANGED
|
@@ -718,6 +718,20 @@ export function transformLlui(source, _filename, devMode = false, emitAgentMetad
|
|
|
718
718
|
? generateDevCode(componentDecls, mcpPort)
|
|
719
719
|
: { top: '', bottom: '' };
|
|
720
720
|
let output = (_top ? _top + '\n' : '') + printer.printFile(transformed) + (_bottom ? '\n' + _bottom : '');
|
|
721
|
+
// Inject the `@llui/dom/internal` import on the fallback path too.
|
|
722
|
+
// The per-statement edit loop (where the normal injection lives)
|
|
723
|
+
// never ran to completion in this branch, so do it inline.
|
|
724
|
+
const internalEditFb = buildInternalImportEdit(lluiImport, usesBindUncertain, usesCloneStaticTemplate, usesApplyBinding, scopeRegistrationsInjected);
|
|
725
|
+
if (internalEditFb) {
|
|
726
|
+
// Place right after the public `@llui/dom` import in the
|
|
727
|
+
// printed output. The printer normalizes the import to a
|
|
728
|
+
// single line; locate it by string match.
|
|
729
|
+
const m = output.match(/import\s*\{[^}]*\}\s*from\s*['"]@llui\/dom['"];?\n/);
|
|
730
|
+
if (m && m.index !== undefined) {
|
|
731
|
+
const insertAt = m.index + m[0].length;
|
|
732
|
+
output = output.slice(0, insertAt) + internalEditFb.replacement + output.slice(insertAt);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
721
735
|
if (devMode || emitAgentMetadata) {
|
|
722
736
|
output = appendCompilerCacheProps(output, componentDecls);
|
|
723
737
|
}
|
|
@@ -738,6 +752,14 @@ export function transformLlui(source, _filename, devMode = false, emitAgentMetad
|
|
|
738
752
|
finalEdits.push({ start: origStart, end: origEnd, replacement });
|
|
739
753
|
}
|
|
740
754
|
}
|
|
755
|
+
// Compiler-emitted internal helpers ride on `@llui/dom/internal`,
|
|
756
|
+
// not on the public `@llui/dom` barrel. Insert the import as a
|
|
757
|
+
// text-level edit (not an AST statement) so it doesn't disturb the
|
|
758
|
+
// origin↔transformed index pairing the per-statement diff relies on.
|
|
759
|
+
// See cleanupImports' NOTE and buildInternalImportEdit's docstring.
|
|
760
|
+
const internalEdit = buildInternalImportEdit(lluiImport, usesBindUncertain, usesCloneStaticTemplate, usesApplyBinding, scopeRegistrationsInjected);
|
|
761
|
+
if (internalEdit)
|
|
762
|
+
finalEdits.push(internalEdit);
|
|
741
763
|
// Dev setup: enable* must run BEFORE user's mountApp (top of file),
|
|
742
764
|
// but import.meta.hot.accept needs to reference user's component vars
|
|
743
765
|
// (bottom of file). So split the injection.
|
|
@@ -1204,50 +1226,37 @@ function cleanupImports(sf, lluiImport, _helpers, compiled, usesElSplit, usesElT
|
|
|
1204
1226
|
const clause = lluiImport.importClause;
|
|
1205
1227
|
if (!clause?.namedBindings || !ts.isNamedImports(clause.namedBindings))
|
|
1206
1228
|
return sf;
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
const
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
const
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
}
|
|
1220
|
-
const hasCloneStaticTemplate = clause.namedBindings.elements.some((s) => s.name.text === '__cloneStaticTemplate');
|
|
1221
|
-
if (!hasCloneStaticTemplate && usesCloneStaticTemplate) {
|
|
1222
|
-
remaining.push(f.createImportSpecifier(false, undefined, f.createIdentifier('__cloneStaticTemplate')));
|
|
1223
|
-
}
|
|
1224
|
-
const hasMemo = clause.namedBindings.elements.some((s) => s.name.text === 'memo');
|
|
1225
|
-
if (!hasMemo && usesMemo) {
|
|
1226
|
-
remaining.push(f.createImportSpecifier(false, undefined, f.createIdentifier('memo')));
|
|
1227
|
-
}
|
|
1228
|
-
if (usesApplyBinding) {
|
|
1229
|
-
if (!clause.namedBindings.elements.some((s) => s.name.text === '__runPhase2')) {
|
|
1230
|
-
remaining.push(f.createImportSpecifier(false, undefined, f.createIdentifier('__runPhase2')));
|
|
1231
|
-
}
|
|
1232
|
-
if (!clause.namedBindings.elements.some((s) => s.name.text === '__handleMsg')) {
|
|
1233
|
-
remaining.push(f.createImportSpecifier(false, undefined, f.createIdentifier('__handleMsg')));
|
|
1229
|
+
// Public-surface imports stay on `from '@llui/dom'`. Compiler-emitted
|
|
1230
|
+
// runtime helpers go on a separate `from '@llui/dom/internal'`
|
|
1231
|
+
// declaration so the vite-plugin's post-bundle property-rename pass
|
|
1232
|
+
// never rewrites an import specifier against a public export name.
|
|
1233
|
+
// See emit-names.ts § COMPILER_DOM_INTERNAL_IMPORTS for the contract.
|
|
1234
|
+
const namedBindings = clause.namedBindings;
|
|
1235
|
+
const remaining = namedBindings.elements.filter((spec) => !compiled.has(spec.name.text));
|
|
1236
|
+
const publicHas = (name) => remaining.some((s) => s.name.text === name) ||
|
|
1237
|
+
namedBindings.elements.some((s) => s.name.text === name);
|
|
1238
|
+
const addPublic = (name) => {
|
|
1239
|
+
if (!publicHas(name)) {
|
|
1240
|
+
remaining.push(f.createImportSpecifier(false, undefined, f.createIdentifier(name)));
|
|
1234
1241
|
}
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
if (
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
//
|
|
1245
|
-
//
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1242
|
+
};
|
|
1243
|
+
if (usesElSplit)
|
|
1244
|
+
addPublic('elSplit');
|
|
1245
|
+
if (usesElTemplate)
|
|
1246
|
+
addPublic('elTemplate');
|
|
1247
|
+
if (usesMemo)
|
|
1248
|
+
addPublic('memo');
|
|
1249
|
+
for (const prim of viewBagPrimitivesNeeded)
|
|
1250
|
+
addPublic(prim);
|
|
1251
|
+
// NOTE: the compiler-emitted internal helpers (`__bindUncertain`,
|
|
1252
|
+
// `__cloneStaticTemplate`, `__runPhase2`, `__handleMsg`,
|
|
1253
|
+
// `__registerScopeVariants`) are NOT added here. They live on
|
|
1254
|
+
// `@llui/dom/internal`, and the outer transform pipeline inserts a
|
|
1255
|
+
// separate `from '@llui/dom/internal'` import via a text-level edit
|
|
1256
|
+
// (see `buildInternalImportEdit`). Inserting a new ImportDeclaration
|
|
1257
|
+
// here would break the caller's per-statement origin↔transformed
|
|
1258
|
+
// index pairing — the statement count would change and trailing
|
|
1259
|
+
// statements would silently drop out of the edit list.
|
|
1251
1260
|
const newBindings = f.createNamedImports(remaining);
|
|
1252
1261
|
// New TS 6 signature: first arg is `phaseModifier` (undefined =
|
|
1253
1262
|
// regular import; `ts.SyntaxKind.TypeKeyword` = `import type`).
|
|
@@ -1261,8 +1270,7 @@ function cleanupImports(sf, lluiImport, _helpers, compiled, usesElSplit, usesElT
|
|
|
1261
1270
|
ts.isStringLiteral(stmt.moduleSpecifier) &&
|
|
1262
1271
|
stmt.moduleSpecifier.text === '@llui/dom' &&
|
|
1263
1272
|
// `phaseModifier === ts.SyntaxKind.TypeKeyword` is `import type
|
|
1264
|
-
// …`; we only want to rewrite value imports.
|
|
1265
|
-
// `isTypeOnly` from the TS<6 API.
|
|
1273
|
+
// …`; we only want to rewrite value imports.
|
|
1266
1274
|
stmt.importClause?.phaseModifier !== ts.SyntaxKind.TypeKeyword) {
|
|
1267
1275
|
replaced = true;
|
|
1268
1276
|
return newImportDecl;
|
|
@@ -1271,6 +1279,40 @@ function cleanupImports(sf, lluiImport, _helpers, compiled, usesElSplit, usesElT
|
|
|
1271
1279
|
});
|
|
1272
1280
|
return f.updateSourceFile(sf, statements);
|
|
1273
1281
|
}
|
|
1282
|
+
/**
|
|
1283
|
+
* Build a single text-insert edit that places
|
|
1284
|
+
* `import { ... } from '@llui/dom/internal'` immediately after the
|
|
1285
|
+
* existing `import { ... } from '@llui/dom'` statement (or appends it
|
|
1286
|
+
* at the start of the file if no @llui/dom import is found, though
|
|
1287
|
+
* the caller has already short-circuited in that case).
|
|
1288
|
+
*
|
|
1289
|
+
* Returns null when no internal helpers are needed. The edit is text-
|
|
1290
|
+
* level (not AST) so it does NOT alter `transformed.statements.length`,
|
|
1291
|
+
* keeping the per-statement origin↔transformed pairing intact.
|
|
1292
|
+
*/
|
|
1293
|
+
function buildInternalImportEdit(lluiImport, usesBindUncertain, usesCloneStaticTemplate, usesApplyBinding, usesRegisterScopeVariants) {
|
|
1294
|
+
const names = new Set();
|
|
1295
|
+
if (usesBindUncertain)
|
|
1296
|
+
names.add('__bindUncertain');
|
|
1297
|
+
if (usesCloneStaticTemplate)
|
|
1298
|
+
names.add('__cloneStaticTemplate');
|
|
1299
|
+
if (usesApplyBinding) {
|
|
1300
|
+
names.add('__runPhase2');
|
|
1301
|
+
names.add('__handleMsg');
|
|
1302
|
+
}
|
|
1303
|
+
if (usesRegisterScopeVariants)
|
|
1304
|
+
names.add('__registerScopeVariants');
|
|
1305
|
+
if (names.size === 0)
|
|
1306
|
+
return null;
|
|
1307
|
+
const sortedNames = [...names].sort();
|
|
1308
|
+
const importLine = `import { ${sortedNames.join(', ')} } from '@llui/dom/internal'\n`;
|
|
1309
|
+
const insertAt = lluiImport.getEnd();
|
|
1310
|
+
// The lluiImport's getEnd() points to the position right after the
|
|
1311
|
+
// statement's trailing `;` or `'\n'`. Emit the new import on a fresh
|
|
1312
|
+
// line — `\n` prefix guarantees that even if the original import had
|
|
1313
|
+
// no trailing newline.
|
|
1314
|
+
return { start: insertAt, end: insertAt, replacement: '\n' + importLine };
|
|
1315
|
+
}
|
|
1274
1316
|
// ── __msgSchema injection ────────────────────────────────────────
|
|
1275
1317
|
// `injectStateSchema` was the inline emitter for `__stateSchema`.
|
|
1276
1318
|
// Migrated to `stateSchemaModule` + the registry bridge (v2c/decomp-3).
|