@llui/compiler 0.3.0 → 0.3.1
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/lint-modules.d.ts +10 -0
- package/dist/lint-modules.d.ts.map +1 -0
- package/dist/lint-modules.js +108 -0
- package/dist/lint-modules.js.map +1 -0
- package/dist/module.d.ts +33 -1
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +2 -1
- package/dist/module.js.map +1 -1
- package/dist/modules/_msg-variants.d.ts +10 -0
- package/dist/modules/_msg-variants.d.ts.map +1 -1
- package/dist/modules/_msg-variants.js +18 -1
- package/dist/modules/_msg-variants.js.map +1 -1
- package/dist/modules/agent-emits-drift.d.ts.map +1 -1
- package/dist/modules/agent-emits-drift.js +36 -6
- package/dist/modules/agent-emits-drift.js.map +1 -1
- package/dist/modules/core-synthesis.js +15 -123
- package/dist/modules/core-synthesis.js.map +1 -1
- package/dist/modules/element-rewrite.d.ts +6 -0
- package/dist/modules/element-rewrite.d.ts.map +1 -1
- package/dist/modules/element-rewrite.js +54 -11
- package/dist/modules/element-rewrite.js.map +1 -1
- package/dist/transform.d.ts.map +1 -1
- package/dist/transform.js +168 -96
- package/dist/transform.js.map +1 -1
- package/package.json +1 -1
package/dist/transform.js
CHANGED
|
@@ -28,47 +28,7 @@ import { itemDedupModule } from './modules/item-dedup.js';
|
|
|
28
28
|
import { elementRewriteModule, ELEMENT_REWRITE_SLOT, } from './modules/element-rewrite.js';
|
|
29
29
|
import { rowFactoryModule } from './modules/row-factory.js';
|
|
30
30
|
import { coreSynthesisModule, CORE_SYNTHESIS_SLOT, } from './modules/core-synthesis.js';
|
|
31
|
-
import {
|
|
32
|
-
import { asyncUpdateModule } from './modules/async-update.js';
|
|
33
|
-
import { mapOnStateArrayModule } from './modules/map-on-state-array.js';
|
|
34
|
-
import { nestedSendInUpdateModule } from './modules/nested-send-in-update.js';
|
|
35
|
-
import { directStateInViewModule } from './modules/direct-state-in-view.js';
|
|
36
|
-
import { imperativeDomInViewModule } from './modules/imperative-dom-in-view.js';
|
|
37
|
-
import { accessorSideEffectModule } from './modules/accessor-side-effect.js';
|
|
38
|
-
import { stateMutationModule } from './modules/state-mutation.js';
|
|
39
|
-
import { effectWithoutHandlerModule } from './modules/effect-without-handler.js';
|
|
40
|
-
import { exhaustiveEffectHandlingModule } from './modules/exhaustive-effect-handling.js';
|
|
41
|
-
import { noEagerItemAccessorModule } from './modules/no-eager-item-accessor.js';
|
|
42
|
-
import { pureUpdateFunctionModule } from './modules/pure-update-function.js';
|
|
43
|
-
import { exhaustiveUpdateModule } from './modules/exhaustive-update.js';
|
|
44
|
-
import { noLetReactiveAccessorModule } from './modules/no-let-reactive-accessor.js';
|
|
45
|
-
import { eachClosureViolationModule } from './modules/each-closure-violation.js';
|
|
46
|
-
import { stringEffectCallbackModule } from './modules/string-effect-callback.js';
|
|
47
|
-
import { agentMissingIntentModule } from './modules/agent-missing-intent.js';
|
|
48
|
-
import { agentWarningOnConfirmModule } from './modules/agent-warning-on-confirm.js';
|
|
49
|
-
import { agentExampleOnPayloadModule } from './modules/agent-example-on-payload.js';
|
|
50
|
-
import { agentExclusiveAnnotationsModule } from './modules/agent-exclusive-annotations.js';
|
|
51
|
-
import { agentOptionalFieldUndocumentedModule } from './modules/agent-optional-field-undocumented.js';
|
|
52
|
-
import { agentTagsendTranslatorMissingModule } from './modules/agent-tagsend-translator-missing.js';
|
|
53
|
-
import { agentNonextractableHandlerModule } from './modules/agent-nonextractable-handler.js';
|
|
54
|
-
import { subappRequiresReasonModule } from './modules/subapp-requires-reason.js';
|
|
55
|
-
import { emptyPropsModule } from './modules/empty-props.js';
|
|
56
|
-
import { forgottenSpreadModule } from './modules/forgotten-spread.js';
|
|
57
|
-
import { accessibilityModule } from './modules/accessibility.js';
|
|
58
|
-
import { viewBagImportModule } from './modules/view-bag-import.js';
|
|
59
|
-
import { controlledInputModule } from './modules/controlled-input.js';
|
|
60
|
-
import { missingMemoModule } from './modules/missing-memo.js';
|
|
61
|
-
import { namespaceImportModule } from './modules/namespace-import.js';
|
|
62
|
-
import { noBarrelImportWhenSubpathExistsModule } from './modules/no-barrel-import-when-subpath-exists.js';
|
|
63
|
-
import { formBoilerplateModule } from './modules/form-boilerplate.js';
|
|
64
|
-
import { spreadInChildrenModule } from './modules/spread-in-children.js';
|
|
65
|
-
import { staticItemsModule } from './modules/static-items.js';
|
|
66
|
-
import { staticOnModule } from './modules/static-on.js';
|
|
67
|
-
import { noListRenderInSampleModule } from './modules/no-list-render-in-sample.js';
|
|
68
|
-
import { noSampleInAccessorModule } from './modules/no-sample-in-accessor.js';
|
|
69
|
-
import { noSampleInReactivePositionModule } from './modules/no-sample-in-reactive-position.js';
|
|
70
|
-
import { agentEmitsDriftModule } from './modules/agent-emits-drift.js';
|
|
71
|
-
import { agentMsgResolvableModule } from './modules/agent-msg-resolvable.js';
|
|
31
|
+
import { createLintModules } from './lint-modules.js';
|
|
72
32
|
export function createMaskLiteral(f, mask) {
|
|
73
33
|
if (mask >= 0)
|
|
74
34
|
return f.createNumericLiteral(mask);
|
|
@@ -227,6 +187,16 @@ export function transformLlui(source, _filename, devMode = false, emitAgentMetad
|
|
|
227
187
|
let usesElSplit = false;
|
|
228
188
|
let usesMemo = false;
|
|
229
189
|
let usesApplyBinding = false;
|
|
190
|
+
// v0.4 size-cut: element-rewrite emits `__bindUncertain` for prop values
|
|
191
|
+
// it can't statically classify (e.g. function-parameter identifiers).
|
|
192
|
+
// The flag drives the cleanupImports pass to add the runtime import.
|
|
193
|
+
let usesBindUncertain = false;
|
|
194
|
+
// v0.4 size-cut (Tier 1.2): per-file set of primitive imports needed by
|
|
195
|
+
// the `__view` factories we synthesize alongside each `component()` call.
|
|
196
|
+
// The runtime calls `def.__view(send)` instead of `createView(send)`, so
|
|
197
|
+
// each component only pulls in the primitives it actually destructures —
|
|
198
|
+
// killing the view-bag tree-shaking leak that pulled all primitives.
|
|
199
|
+
const viewBagPrimitivesNeeded = new Set();
|
|
230
200
|
let usesCloneStaticTemplate = false;
|
|
231
201
|
const f = ts.factory;
|
|
232
202
|
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
|
|
@@ -320,55 +290,13 @@ export function transformLlui(source, _filename, devMode = false, emitAgentMetad
|
|
|
320
290
|
// the umbrella's last remaining inline injector
|
|
321
291
|
// (`injectCompilerEmittedMarker`, deleted below).
|
|
322
292
|
activeModules.push(compilerStampModule);
|
|
323
|
-
//
|
|
324
|
-
//
|
|
325
|
-
//
|
|
326
|
-
//
|
|
327
|
-
|
|
328
|
-
//
|
|
329
|
-
|
|
330
|
-
// signals; ESLint warnings are silently ignored by LLM agents and
|
|
331
|
-
// may not even be installed in a downstream project.
|
|
332
|
-
activeModules.push(asyncUpdateModule());
|
|
333
|
-
activeModules.push(mapOnStateArrayModule());
|
|
334
|
-
activeModules.push(nestedSendInUpdateModule());
|
|
335
|
-
activeModules.push(directStateInViewModule());
|
|
336
|
-
activeModules.push(imperativeDomInViewModule());
|
|
337
|
-
activeModules.push(accessorSideEffectModule());
|
|
338
|
-
activeModules.push(stateMutationModule());
|
|
339
|
-
activeModules.push(effectWithoutHandlerModule());
|
|
340
|
-
activeModules.push(exhaustiveEffectHandlingModule());
|
|
341
|
-
activeModules.push(noEagerItemAccessorModule());
|
|
342
|
-
activeModules.push(pureUpdateFunctionModule());
|
|
343
|
-
activeModules.push(exhaustiveUpdateModule());
|
|
344
|
-
activeModules.push(noLetReactiveAccessorModule());
|
|
345
|
-
activeModules.push(eachClosureViolationModule());
|
|
346
|
-
activeModules.push(stringEffectCallbackModule());
|
|
347
|
-
activeModules.push(agentMissingIntentModule());
|
|
348
|
-
activeModules.push(agentWarningOnConfirmModule());
|
|
349
|
-
activeModules.push(agentExampleOnPayloadModule());
|
|
350
|
-
activeModules.push(agentExclusiveAnnotationsModule());
|
|
351
|
-
activeModules.push(agentOptionalFieldUndocumentedModule());
|
|
352
|
-
activeModules.push(agentTagsendTranslatorMissingModule());
|
|
353
|
-
activeModules.push(agentNonextractableHandlerModule());
|
|
354
|
-
activeModules.push(subappRequiresReasonModule());
|
|
355
|
-
activeModules.push(emptyPropsModule());
|
|
356
|
-
activeModules.push(forgottenSpreadModule());
|
|
357
|
-
activeModules.push(accessibilityModule());
|
|
358
|
-
activeModules.push(viewBagImportModule());
|
|
359
|
-
activeModules.push(controlledInputModule());
|
|
360
|
-
activeModules.push(missingMemoModule());
|
|
361
|
-
activeModules.push(namespaceImportModule());
|
|
362
|
-
activeModules.push(noBarrelImportWhenSubpathExistsModule());
|
|
363
|
-
activeModules.push(formBoilerplateModule());
|
|
364
|
-
activeModules.push(spreadInChildrenModule());
|
|
365
|
-
activeModules.push(staticItemsModule());
|
|
366
|
-
activeModules.push(staticOnModule());
|
|
367
|
-
activeModules.push(noListRenderInSampleModule());
|
|
368
|
-
activeModules.push(noSampleInAccessorModule());
|
|
369
|
-
activeModules.push(noSampleInReactivePositionModule());
|
|
370
|
-
activeModules.push(agentEmitsDriftModule());
|
|
371
|
-
activeModules.push(agentMsgResolvableModule());
|
|
293
|
+
// Always-on lint rules. Single source of truth lives in
|
|
294
|
+
// `./lint-modules.ts` so adding/removing a rule propagates to both
|
|
295
|
+
// the transform pipeline and the rule-docs generator
|
|
296
|
+
// (`scripts/generate-rule-docs.ts`). LLM-first authoring requires
|
|
297
|
+
// non-bypassable correctness signals: every rule emits at
|
|
298
|
+
// `severity: error`.
|
|
299
|
+
activeModules.push(...createLintModules());
|
|
372
300
|
// eachMemoModule wraps allocating each() items accessors in
|
|
373
301
|
// `memo(...)` via `transformCallEnter`. Activated when the file
|
|
374
302
|
// has any reactive paths (mirrors the inline call's gating).
|
|
@@ -455,7 +383,10 @@ export function transformLlui(source, _filename, devMode = false, emitAgentMetad
|
|
|
455
383
|
lluiImport,
|
|
456
384
|
}));
|
|
457
385
|
const registry = new ModuleRegistry(activeModules);
|
|
458
|
-
|
|
386
|
+
// `typeSources` flows through to lint modules that need cross-file
|
|
387
|
+
// visibility (e.g. agent-emits-drift's imported-Msg case). Same
|
|
388
|
+
// shape as `ModuleExternalTypes`.
|
|
389
|
+
const registryResult = registry.run(sourceFile, undefined, typeSources);
|
|
459
390
|
// The registry phases (preTransform v2c/decomp-7, transformCall
|
|
460
391
|
// v2c/decomp-11/12) may have mutated the source file — replace our
|
|
461
392
|
// local reference so all subsequent code (fieldBits, visitor,
|
|
@@ -496,6 +427,8 @@ export function transformLlui(source, _filename, devMode = false, emitAgentMetad
|
|
|
496
427
|
usesElTemplate = true;
|
|
497
428
|
if (erState.usesCloneStaticTemplate)
|
|
498
429
|
usesCloneStaticTemplate = true;
|
|
430
|
+
if (erState.usesBindUncertain)
|
|
431
|
+
usesBindUncertain = true;
|
|
499
432
|
if (erState.compiled.size > 0 ||
|
|
500
433
|
erState.usesElSplit ||
|
|
501
434
|
erState.usesElTemplate ||
|
|
@@ -716,6 +649,13 @@ export function transformLlui(source, _filename, devMode = false, emitAgentMetad
|
|
|
716
649
|
// the prior `if (devMode)` guard. When `devMode` is false the
|
|
717
650
|
// registry is empty and this call is a no-op.
|
|
718
651
|
result = applyRegistryEmissions(result ?? node, node);
|
|
652
|
+
// v0.4 size-cut (Tier 1.2): synthesize __view = (send) => ({ send, ... })
|
|
653
|
+
// containing ONLY the primitives this component's view callback
|
|
654
|
+
// destructures. The runtime prefers __view over createView for compiled
|
|
655
|
+
// components, eliminating the all-primitives reference chain through
|
|
656
|
+
// view-helpers.ts. Each primitive becomes its own top-level import,
|
|
657
|
+
// tree-shaken by Rollup when no component destructures it.
|
|
658
|
+
result = injectViewBag(result ?? node, viewBagPrimitivesNeeded, f);
|
|
719
659
|
// __schemaHash: migrated to schemaHashModule (v2c/decomp-5).
|
|
720
660
|
// When shouldEmitAgentMetadata is true, schemaHashModule is in
|
|
721
661
|
// the active module list and produces the emission via the
|
|
@@ -745,7 +685,7 @@ export function transformLlui(source, _filename, devMode = false, emitAgentMetad
|
|
|
745
685
|
// Pass 3: Clean up imports — use the old cleanupImports approach
|
|
746
686
|
// which operates on the transformed SourceFile safely
|
|
747
687
|
const safeToRemove = new Set([...compiledHelpers].filter((h) => !bailedHelpers.has(h)));
|
|
748
|
-
transformed = cleanupImports(transformed, lluiImport, importedHelpers, safeToRemove, usesElSplit, usesElTemplate, usesMemo, usesApplyBinding, usesCloneStaticTemplate, scopeRegistrationsInjected, f);
|
|
688
|
+
transformed = cleanupImports(transformed, lluiImport, importedHelpers, safeToRemove, usesElSplit, usesElTemplate, usesMemo, usesApplyBinding, usesCloneStaticTemplate, scopeRegistrationsInjected, viewBagPrimitivesNeeded, usesBindUncertain, f);
|
|
749
689
|
if (edits.length === 0) {
|
|
750
690
|
// No element-helper rewrites — but registry may still have
|
|
751
691
|
// collected diagnostics (e.g. agent-rule errors on Msg variants
|
|
@@ -1007,6 +947,118 @@ const VIEW_HELPER_PRIMITIVES = new Set([
|
|
|
1007
947
|
'slice',
|
|
1008
948
|
'send',
|
|
1009
949
|
]);
|
|
950
|
+
// v0.4 size-cut (Tier 1.2): bag-field → runtime-primitive map. `ctx` is
|
|
951
|
+
// the only rename — every other destructured name maps 1:1 to its
|
|
952
|
+
// primitive's exported identifier from `@llui/dom`. Fields not in this
|
|
953
|
+
// map (e.g. `send`) are handled separately or omitted.
|
|
954
|
+
const VIEW_BAG_FIELD_TO_PRIMITIVE = {
|
|
955
|
+
show: 'show',
|
|
956
|
+
branch: 'branch',
|
|
957
|
+
scope: 'scope',
|
|
958
|
+
each: 'each',
|
|
959
|
+
text: 'text',
|
|
960
|
+
unsafeHtml: 'unsafeHtml',
|
|
961
|
+
memo: 'memo',
|
|
962
|
+
selector: 'selector',
|
|
963
|
+
sample: 'sample',
|
|
964
|
+
clientOnly: 'clientOnly',
|
|
965
|
+
ctx: 'useContext',
|
|
966
|
+
};
|
|
967
|
+
/**
|
|
968
|
+
* Splice a `__view: (send) => ({ send, name1, name2, ... })` property into
|
|
969
|
+
* a `component({...})` call's config-arg literal. The synthesized factory
|
|
970
|
+
* lets the runtime build a minimal view bag that references only the
|
|
971
|
+
* primitives this component's view destructures — replacing the static
|
|
972
|
+
* `createView` call in mount.ts and eliminating its all-primitives import
|
|
973
|
+
* chain. Bag-field names other than `send` are added to `needed` so
|
|
974
|
+
* `cleanupImports` injects matching `@llui/dom` imports at the file level.
|
|
975
|
+
*
|
|
976
|
+
* Idempotent — returns `call` unchanged when:
|
|
977
|
+
* • the config arg is not an object literal
|
|
978
|
+
* • no `view:` property exists, or its value is not an arrow/function
|
|
979
|
+
* • the view's first parameter is not an ObjectBindingPattern
|
|
980
|
+
* • the config arg already has a `__view` property (re-run safety)
|
|
981
|
+
*
|
|
982
|
+
* Bag fields that aren't in `VIEW_BAG_FIELD_TO_PRIMITIVE` (e.g. unknown
|
|
983
|
+
* names from a user-typed View extension) are skipped so the runtime falls
|
|
984
|
+
* back to `createView` for any access to them.
|
|
985
|
+
*/
|
|
986
|
+
function injectViewBag(call, needed, f) {
|
|
987
|
+
const configArg = call.arguments[0];
|
|
988
|
+
if (!configArg || !ts.isObjectLiteralExpression(configArg))
|
|
989
|
+
return call;
|
|
990
|
+
// Skip if a `__view` is already present (idempotency for re-runs).
|
|
991
|
+
for (const prop of configArg.properties) {
|
|
992
|
+
if (ts.isPropertyAssignment(prop) &&
|
|
993
|
+
ts.isIdentifier(prop.name) &&
|
|
994
|
+
prop.name.text === '__view') {
|
|
995
|
+
return call;
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
// Find view: arrow/function.
|
|
999
|
+
let viewFn = null;
|
|
1000
|
+
for (const prop of configArg.properties) {
|
|
1001
|
+
if (ts.isPropertyAssignment(prop) &&
|
|
1002
|
+
ts.isIdentifier(prop.name) &&
|
|
1003
|
+
prop.name.text === 'view' &&
|
|
1004
|
+
(ts.isArrowFunction(prop.initializer) || ts.isFunctionExpression(prop.initializer))) {
|
|
1005
|
+
viewFn = prop.initializer;
|
|
1006
|
+
break;
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
if (!viewFn)
|
|
1010
|
+
return call;
|
|
1011
|
+
// Inspect the first parameter — must be an ObjectBindingPattern.
|
|
1012
|
+
const firstParam = viewFn.parameters[0];
|
|
1013
|
+
if (!firstParam || !ts.isObjectBindingPattern(firstParam.name))
|
|
1014
|
+
return call;
|
|
1015
|
+
const entries = [];
|
|
1016
|
+
for (const elem of firstParam.name.elements) {
|
|
1017
|
+
const localName = ts.isIdentifier(elem.name) ? elem.name.text : null;
|
|
1018
|
+
const sourceName = elem.propertyName && ts.isIdentifier(elem.propertyName) ? elem.propertyName.text : localName;
|
|
1019
|
+
if (!localName || !sourceName)
|
|
1020
|
+
continue;
|
|
1021
|
+
if (sourceName === 'send') {
|
|
1022
|
+
entries.push({ localName, primitive: null });
|
|
1023
|
+
continue;
|
|
1024
|
+
}
|
|
1025
|
+
const primitive = VIEW_BAG_FIELD_TO_PRIMITIVE[sourceName];
|
|
1026
|
+
if (!primitive)
|
|
1027
|
+
continue; // unknown name — let the runtime fail at runtime if accessed
|
|
1028
|
+
entries.push({ localName, primitive });
|
|
1029
|
+
}
|
|
1030
|
+
if (entries.length === 0)
|
|
1031
|
+
return call;
|
|
1032
|
+
// Synthesize: __view: ($send) => ({ localA: $send, localB: text, localC: each, ... })
|
|
1033
|
+
// We use a fixed parameter name `$send` to avoid shadowing — the bag
|
|
1034
|
+
// entries that map to send use this identifier.
|
|
1035
|
+
const sendParamName = f.createIdentifier('$send');
|
|
1036
|
+
const bagProps = [];
|
|
1037
|
+
for (const e of entries) {
|
|
1038
|
+
if (e.primitive === null) {
|
|
1039
|
+
// local name → send parameter
|
|
1040
|
+
bagProps.push(e.localName === '$send'
|
|
1041
|
+
? f.createShorthandPropertyAssignment(sendParamName)
|
|
1042
|
+
: f.createPropertyAssignment(f.createIdentifier(e.localName), sendParamName));
|
|
1043
|
+
}
|
|
1044
|
+
else if (e.localName === e.primitive) {
|
|
1045
|
+
bagProps.push(f.createShorthandPropertyAssignment(f.createIdentifier(e.localName)));
|
|
1046
|
+
needed.add(e.primitive);
|
|
1047
|
+
}
|
|
1048
|
+
else {
|
|
1049
|
+
bagProps.push(f.createPropertyAssignment(f.createIdentifier(e.localName), f.createIdentifier(e.primitive)));
|
|
1050
|
+
needed.add(e.primitive);
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
const viewBagFactory = f.createArrowFunction(undefined, undefined, [
|
|
1054
|
+
f.createParameterDeclaration(undefined, undefined, sendParamName, undefined, undefined, undefined),
|
|
1055
|
+
], undefined, f.createToken(ts.SyntaxKind.EqualsGreaterThanToken), f.createParenthesizedExpression(f.createObjectLiteralExpression(bagProps, false)));
|
|
1056
|
+
const newConfig = f.createObjectLiteralExpression([...configArg.properties, f.createPropertyAssignment('__view', viewBagFactory)], true);
|
|
1057
|
+
return f.createCallExpression(call.expression, call.typeArguments, [
|
|
1058
|
+
newConfig,
|
|
1059
|
+
...call.arguments.slice(1),
|
|
1060
|
+
]);
|
|
1061
|
+
}
|
|
1010
1062
|
function collectViewHelperAliases(sf, lluiImport, helperNames) {
|
|
1011
1063
|
const aliases = new Map();
|
|
1012
1064
|
function addFromBindingPattern(pattern) {
|
|
@@ -1115,14 +1167,16 @@ export function isHelperCall(expr, name, helperNames, aliases) {
|
|
|
1115
1167
|
// `structuralMaskModule` (v2c/decomp-14). Module fires top-down
|
|
1116
1168
|
// (transformCallEnter) so the visitor sees the masked options literal.
|
|
1117
1169
|
// ── Pass 3: Import cleanup ───────────────────────────────────────
|
|
1118
|
-
function cleanupImports(sf, lluiImport, _helpers, compiled, usesElSplit, usesElTemplate, usesMemo, usesApplyBinding, usesCloneStaticTemplate, usesRegisterScopeVariants, f) {
|
|
1170
|
+
function cleanupImports(sf, lluiImport, _helpers, compiled, usesElSplit, usesElTemplate, usesMemo, usesApplyBinding, usesCloneStaticTemplate, usesRegisterScopeVariants, viewBagPrimitivesNeeded, usesBindUncertain, f) {
|
|
1119
1171
|
if (compiled.size === 0 &&
|
|
1120
1172
|
!usesElTemplate &&
|
|
1121
1173
|
!usesElSplit &&
|
|
1122
1174
|
!usesMemo &&
|
|
1123
1175
|
!usesApplyBinding &&
|
|
1124
1176
|
!usesCloneStaticTemplate &&
|
|
1125
|
-
!usesRegisterScopeVariants
|
|
1177
|
+
!usesRegisterScopeVariants &&
|
|
1178
|
+
viewBagPrimitivesNeeded.size === 0 &&
|
|
1179
|
+
!usesBindUncertain)
|
|
1126
1180
|
return sf;
|
|
1127
1181
|
const clause = lluiImport.importClause;
|
|
1128
1182
|
if (!clause?.namedBindings || !ts.isNamedImports(clause.namedBindings))
|
|
@@ -1132,6 +1186,10 @@ function cleanupImports(sf, lluiImport, _helpers, compiled, usesElSplit, usesElT
|
|
|
1132
1186
|
if (!hasElSplit && usesElSplit) {
|
|
1133
1187
|
remaining.push(f.createImportSpecifier(false, undefined, f.createIdentifier('elSplit')));
|
|
1134
1188
|
}
|
|
1189
|
+
const hasBindUncertain = clause.namedBindings.elements.some((s) => s.name.text === '__bindUncertain');
|
|
1190
|
+
if (!hasBindUncertain && usesBindUncertain) {
|
|
1191
|
+
remaining.push(f.createImportSpecifier(false, undefined, f.createIdentifier('__bindUncertain')));
|
|
1192
|
+
}
|
|
1135
1193
|
const hasElTemplate = clause.namedBindings.elements.some((s) => s.name.text === 'elTemplate');
|
|
1136
1194
|
if (!hasElTemplate && usesElTemplate) {
|
|
1137
1195
|
remaining.push(f.createImportSpecifier(false, undefined, f.createIdentifier('elTemplate')));
|
|
@@ -1159,8 +1217,19 @@ function cleanupImports(sf, lluiImport, _helpers, compiled, usesElSplit, usesElT
|
|
|
1159
1217
|
if (!hasRegisterScopeVariants && usesRegisterScopeVariants) {
|
|
1160
1218
|
remaining.push(f.createImportSpecifier(false, undefined, f.createIdentifier('__registerScopeVariants')));
|
|
1161
1219
|
}
|
|
1220
|
+
// v0.4 size-cut (Tier 1.2): add @llui/dom imports for each primitive
|
|
1221
|
+
// referenced by synthesized __view factories. `ctx` is the destructured
|
|
1222
|
+
// bag name; its primitive is `useContext` (the only rename pair).
|
|
1223
|
+
for (const prim of viewBagPrimitivesNeeded) {
|
|
1224
|
+
if (!clause.namedBindings.elements.some((s) => s.name.text === prim)) {
|
|
1225
|
+
remaining.push(f.createImportSpecifier(false, undefined, f.createIdentifier(prim)));
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1162
1228
|
const newBindings = f.createNamedImports(remaining);
|
|
1163
|
-
|
|
1229
|
+
// New TS 6 signature: first arg is `phaseModifier` (undefined =
|
|
1230
|
+
// regular import; `ts.SyntaxKind.TypeKeyword` = `import type`).
|
|
1231
|
+
// The legacy boolean overload is deprecated.
|
|
1232
|
+
const newClause = f.createImportClause(undefined, undefined, newBindings);
|
|
1164
1233
|
const newImportDecl = f.createImportDeclaration(undefined, newClause, lluiImport.moduleSpecifier);
|
|
1165
1234
|
let replaced = false;
|
|
1166
1235
|
const statements = sf.statements.map((stmt) => {
|
|
@@ -1168,7 +1237,10 @@ function cleanupImports(sf, lluiImport, _helpers, compiled, usesElSplit, usesElT
|
|
|
1168
1237
|
ts.isImportDeclaration(stmt) &&
|
|
1169
1238
|
ts.isStringLiteral(stmt.moduleSpecifier) &&
|
|
1170
1239
|
stmt.moduleSpecifier.text === '@llui/dom' &&
|
|
1171
|
-
|
|
1240
|
+
// `phaseModifier === ts.SyntaxKind.TypeKeyword` is `import type
|
|
1241
|
+
// …`; we only want to rewrite value imports. Replaces deprecated
|
|
1242
|
+
// `isTypeOnly` from the TS<6 API.
|
|
1243
|
+
stmt.importClause?.phaseModifier !== ts.SyntaxKind.TypeKeyword) {
|
|
1172
1244
|
replaced = true;
|
|
1173
1245
|
return newImportDecl;
|
|
1174
1246
|
}
|