@llui/compiler 0.3.0 → 0.3.2
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/collect-deps.d.ts +12 -0
- package/dist/collect-deps.d.ts.map +1 -1
- package/dist/collect-deps.js +6 -1
- package/dist/collect-deps.js.map +1 -1
- package/dist/cross-file-walker.d.ts +10 -0
- package/dist/cross-file-walker.d.ts.map +1 -1
- package/dist/cross-file-walker.js +81 -24
- package/dist/cross-file-walker.js.map +1 -1
- 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 +191 -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,141 @@ 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 config arg already has a `__view` property (re-run safety)
|
|
980
|
+
*
|
|
981
|
+
* Bag fields that aren't in `VIEW_BAG_FIELD_TO_PRIMITIVE` (e.g. unknown
|
|
982
|
+
* names from a user-typed View extension) are skipped — the runtime
|
|
983
|
+
* cannot fabricate them, so accessing them at runtime is the user's
|
|
984
|
+
* problem (matches dev-mode behavior).
|
|
985
|
+
*
|
|
986
|
+
* Identifier-style view params (`view: (h) => ...` or `view: (send) => ...`)
|
|
987
|
+
* can't be statically narrowed to a known subset of primitives — `h` may
|
|
988
|
+
* be passed to helpers, destructured later, or read dynamically. For
|
|
989
|
+
* those we emit `__view: ($send) => createView($send)` so the runtime
|
|
990
|
+
* gets the full bag. The instance-level `_viewBag` cache on
|
|
991
|
+
* `getInstanceViewBag` means this is still one allocation per mount.
|
|
992
|
+
*/
|
|
993
|
+
function injectViewBag(call, needed, f) {
|
|
994
|
+
const configArg = call.arguments[0];
|
|
995
|
+
if (!configArg || !ts.isObjectLiteralExpression(configArg))
|
|
996
|
+
return call;
|
|
997
|
+
// Skip if a `__view` is already present (idempotency for re-runs).
|
|
998
|
+
for (const prop of configArg.properties) {
|
|
999
|
+
if (ts.isPropertyAssignment(prop) &&
|
|
1000
|
+
ts.isIdentifier(prop.name) &&
|
|
1001
|
+
prop.name.text === '__view') {
|
|
1002
|
+
return call;
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
// Find view: arrow/function.
|
|
1006
|
+
let viewFn = null;
|
|
1007
|
+
for (const prop of configArg.properties) {
|
|
1008
|
+
if (ts.isPropertyAssignment(prop) &&
|
|
1009
|
+
ts.isIdentifier(prop.name) &&
|
|
1010
|
+
prop.name.text === 'view' &&
|
|
1011
|
+
(ts.isArrowFunction(prop.initializer) || ts.isFunctionExpression(prop.initializer))) {
|
|
1012
|
+
viewFn = prop.initializer;
|
|
1013
|
+
break;
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
if (!viewFn)
|
|
1017
|
+
return call;
|
|
1018
|
+
const sendParamName = f.createIdentifier('$send');
|
|
1019
|
+
// Build the __view factory body. Two shapes:
|
|
1020
|
+
//
|
|
1021
|
+
// Destructured param — `view: ({ send, text, each }) => ...`
|
|
1022
|
+
// emit `__view: ($send) => ({ send: $send, text, each })`
|
|
1023
|
+
// (tree-shakes unused primitives — the Tier 1.2 size cut).
|
|
1024
|
+
//
|
|
1025
|
+
// Identifier / no param — `view: (h) => ...`, `view: () => ...`,
|
|
1026
|
+
// `view: (send) => ...`, etc.
|
|
1027
|
+
// emit `__view: ($send) => createView($send)`
|
|
1028
|
+
// The compiler can't see which fields `h` is accessed on (it
|
|
1029
|
+
// may be passed to a helper, destructured later, read by
|
|
1030
|
+
// name dynamically). Full bag, instance-cached.
|
|
1031
|
+
const firstParam = viewFn.parameters[0];
|
|
1032
|
+
const isDestructured = !!firstParam && ts.isObjectBindingPattern(firstParam.name);
|
|
1033
|
+
let factoryBody;
|
|
1034
|
+
if (isDestructured) {
|
|
1035
|
+
const entries = [];
|
|
1036
|
+
for (const elem of firstParam.name.elements) {
|
|
1037
|
+
const localName = ts.isIdentifier(elem.name) ? elem.name.text : null;
|
|
1038
|
+
const sourceName = elem.propertyName && ts.isIdentifier(elem.propertyName) ? elem.propertyName.text : localName;
|
|
1039
|
+
if (!localName || !sourceName)
|
|
1040
|
+
continue;
|
|
1041
|
+
if (sourceName === 'send') {
|
|
1042
|
+
entries.push({ localName, primitive: null });
|
|
1043
|
+
continue;
|
|
1044
|
+
}
|
|
1045
|
+
const primitive = VIEW_BAG_FIELD_TO_PRIMITIVE[sourceName];
|
|
1046
|
+
if (!primitive)
|
|
1047
|
+
continue; // unknown name — accessing it at runtime is the user's problem
|
|
1048
|
+
entries.push({ localName, primitive });
|
|
1049
|
+
}
|
|
1050
|
+
const bagProps = [];
|
|
1051
|
+
for (const e of entries) {
|
|
1052
|
+
if (e.primitive === null) {
|
|
1053
|
+
bagProps.push(e.localName === '$send'
|
|
1054
|
+
? f.createShorthandPropertyAssignment(sendParamName)
|
|
1055
|
+
: f.createPropertyAssignment(f.createIdentifier(e.localName), sendParamName));
|
|
1056
|
+
}
|
|
1057
|
+
else if (e.localName === e.primitive) {
|
|
1058
|
+
bagProps.push(f.createShorthandPropertyAssignment(f.createIdentifier(e.localName)));
|
|
1059
|
+
needed.add(e.primitive);
|
|
1060
|
+
}
|
|
1061
|
+
else {
|
|
1062
|
+
bagProps.push(f.createPropertyAssignment(f.createIdentifier(e.localName), f.createIdentifier(e.primitive)));
|
|
1063
|
+
needed.add(e.primitive);
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
factoryBody = f.createParenthesizedExpression(f.createObjectLiteralExpression(bagProps, false));
|
|
1067
|
+
}
|
|
1068
|
+
else {
|
|
1069
|
+
// Identifier-style or zero-arg view: emit `createView($send)` and
|
|
1070
|
+
// pull `createView` into the file imports via cleanupImports.
|
|
1071
|
+
needed.add('createView');
|
|
1072
|
+
factoryBody = f.createCallExpression(f.createIdentifier('createView'), undefined, [
|
|
1073
|
+
sendParamName,
|
|
1074
|
+
]);
|
|
1075
|
+
}
|
|
1076
|
+
const viewBagFactory = f.createArrowFunction(undefined, undefined, [
|
|
1077
|
+
f.createParameterDeclaration(undefined, undefined, sendParamName, undefined, undefined, undefined),
|
|
1078
|
+
], undefined, f.createToken(ts.SyntaxKind.EqualsGreaterThanToken), factoryBody);
|
|
1079
|
+
const newConfig = f.createObjectLiteralExpression([...configArg.properties, f.createPropertyAssignment('__view', viewBagFactory)], true);
|
|
1080
|
+
return f.createCallExpression(call.expression, call.typeArguments, [
|
|
1081
|
+
newConfig,
|
|
1082
|
+
...call.arguments.slice(1),
|
|
1083
|
+
]);
|
|
1084
|
+
}
|
|
1010
1085
|
function collectViewHelperAliases(sf, lluiImport, helperNames) {
|
|
1011
1086
|
const aliases = new Map();
|
|
1012
1087
|
function addFromBindingPattern(pattern) {
|
|
@@ -1115,14 +1190,16 @@ export function isHelperCall(expr, name, helperNames, aliases) {
|
|
|
1115
1190
|
// `structuralMaskModule` (v2c/decomp-14). Module fires top-down
|
|
1116
1191
|
// (transformCallEnter) so the visitor sees the masked options literal.
|
|
1117
1192
|
// ── Pass 3: Import cleanup ───────────────────────────────────────
|
|
1118
|
-
function cleanupImports(sf, lluiImport, _helpers, compiled, usesElSplit, usesElTemplate, usesMemo, usesApplyBinding, usesCloneStaticTemplate, usesRegisterScopeVariants, f) {
|
|
1193
|
+
function cleanupImports(sf, lluiImport, _helpers, compiled, usesElSplit, usesElTemplate, usesMemo, usesApplyBinding, usesCloneStaticTemplate, usesRegisterScopeVariants, viewBagPrimitivesNeeded, usesBindUncertain, f) {
|
|
1119
1194
|
if (compiled.size === 0 &&
|
|
1120
1195
|
!usesElTemplate &&
|
|
1121
1196
|
!usesElSplit &&
|
|
1122
1197
|
!usesMemo &&
|
|
1123
1198
|
!usesApplyBinding &&
|
|
1124
1199
|
!usesCloneStaticTemplate &&
|
|
1125
|
-
!usesRegisterScopeVariants
|
|
1200
|
+
!usesRegisterScopeVariants &&
|
|
1201
|
+
viewBagPrimitivesNeeded.size === 0 &&
|
|
1202
|
+
!usesBindUncertain)
|
|
1126
1203
|
return sf;
|
|
1127
1204
|
const clause = lluiImport.importClause;
|
|
1128
1205
|
if (!clause?.namedBindings || !ts.isNamedImports(clause.namedBindings))
|
|
@@ -1132,6 +1209,10 @@ function cleanupImports(sf, lluiImport, _helpers, compiled, usesElSplit, usesElT
|
|
|
1132
1209
|
if (!hasElSplit && usesElSplit) {
|
|
1133
1210
|
remaining.push(f.createImportSpecifier(false, undefined, f.createIdentifier('elSplit')));
|
|
1134
1211
|
}
|
|
1212
|
+
const hasBindUncertain = clause.namedBindings.elements.some((s) => s.name.text === '__bindUncertain');
|
|
1213
|
+
if (!hasBindUncertain && usesBindUncertain) {
|
|
1214
|
+
remaining.push(f.createImportSpecifier(false, undefined, f.createIdentifier('__bindUncertain')));
|
|
1215
|
+
}
|
|
1135
1216
|
const hasElTemplate = clause.namedBindings.elements.some((s) => s.name.text === 'elTemplate');
|
|
1136
1217
|
if (!hasElTemplate && usesElTemplate) {
|
|
1137
1218
|
remaining.push(f.createImportSpecifier(false, undefined, f.createIdentifier('elTemplate')));
|
|
@@ -1159,8 +1240,19 @@ function cleanupImports(sf, lluiImport, _helpers, compiled, usesElSplit, usesElT
|
|
|
1159
1240
|
if (!hasRegisterScopeVariants && usesRegisterScopeVariants) {
|
|
1160
1241
|
remaining.push(f.createImportSpecifier(false, undefined, f.createIdentifier('__registerScopeVariants')));
|
|
1161
1242
|
}
|
|
1243
|
+
// v0.4 size-cut (Tier 1.2): add @llui/dom imports for each primitive
|
|
1244
|
+
// referenced by synthesized __view factories. `ctx` is the destructured
|
|
1245
|
+
// bag name; its primitive is `useContext` (the only rename pair).
|
|
1246
|
+
for (const prim of viewBagPrimitivesNeeded) {
|
|
1247
|
+
if (!clause.namedBindings.elements.some((s) => s.name.text === prim)) {
|
|
1248
|
+
remaining.push(f.createImportSpecifier(false, undefined, f.createIdentifier(prim)));
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1162
1251
|
const newBindings = f.createNamedImports(remaining);
|
|
1163
|
-
|
|
1252
|
+
// New TS 6 signature: first arg is `phaseModifier` (undefined =
|
|
1253
|
+
// regular import; `ts.SyntaxKind.TypeKeyword` = `import type`).
|
|
1254
|
+
// The legacy boolean overload is deprecated.
|
|
1255
|
+
const newClause = f.createImportClause(undefined, undefined, newBindings);
|
|
1164
1256
|
const newImportDecl = f.createImportDeclaration(undefined, newClause, lluiImport.moduleSpecifier);
|
|
1165
1257
|
let replaced = false;
|
|
1166
1258
|
const statements = sf.statements.map((stmt) => {
|
|
@@ -1168,7 +1260,10 @@ function cleanupImports(sf, lluiImport, _helpers, compiled, usesElSplit, usesElT
|
|
|
1168
1260
|
ts.isImportDeclaration(stmt) &&
|
|
1169
1261
|
ts.isStringLiteral(stmt.moduleSpecifier) &&
|
|
1170
1262
|
stmt.moduleSpecifier.text === '@llui/dom' &&
|
|
1171
|
-
|
|
1263
|
+
// `phaseModifier === ts.SyntaxKind.TypeKeyword` is `import type
|
|
1264
|
+
// …`; we only want to rewrite value imports. Replaces deprecated
|
|
1265
|
+
// `isTypeOnly` from the TS<6 API.
|
|
1266
|
+
stmt.importClause?.phaseModifier !== ts.SyntaxKind.TypeKeyword) {
|
|
1172
1267
|
replaced = true;
|
|
1173
1268
|
return newImportDecl;
|
|
1174
1269
|
}
|