@llui/compiler 0.3.1 → 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/transform.js CHANGED
@@ -976,12 +976,19 @@ const VIEW_BAG_FIELD_TO_PRIMITIVE = {
976
976
  * Idempotent — returns `call` unchanged when:
977
977
  * • the config arg is not an object literal
978
978
  * • no `view:` property exists, or its value is not an arrow/function
979
- * • the view's first parameter is not an ObjectBindingPattern
980
979
  * • the config arg already has a `__view` property (re-run safety)
981
980
  *
982
981
  * 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.
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.
985
992
  */
986
993
  function injectViewBag(call, needed, f) {
987
994
  const configArg = call.arguments[0];
@@ -1008,51 +1015,67 @@ function injectViewBag(call, needed, f) {
1008
1015
  }
1009
1016
  if (!viewFn)
1010
1017
  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
1018
  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);
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 });
1047
1049
  }
1048
- else {
1049
- bagProps.push(f.createPropertyAssignment(f.createIdentifier(e.localName), f.createIdentifier(e.primitive)));
1050
- needed.add(e.primitive);
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
+ }
1051
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
+ ]);
1052
1075
  }
1053
1076
  const viewBagFactory = f.createArrowFunction(undefined, undefined, [
1054
1077
  f.createParameterDeclaration(undefined, undefined, sendParamName, undefined, undefined, undefined),
1055
- ], undefined, f.createToken(ts.SyntaxKind.EqualsGreaterThanToken), f.createParenthesizedExpression(f.createObjectLiteralExpression(bagProps, false)));
1078
+ ], undefined, f.createToken(ts.SyntaxKind.EqualsGreaterThanToken), factoryBody);
1056
1079
  const newConfig = f.createObjectLiteralExpression([...configArg.properties, f.createPropertyAssignment('__view', viewBagFactory)], true);
1057
1080
  return f.createCallExpression(call.expression, call.typeArguments, [
1058
1081
  newConfig,