@fictjs/compiler 0.2.2 → 0.2.3

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/index.cjs CHANGED
@@ -185,7 +185,7 @@ var require_generated = __commonJS({
185
185
  exports2.isExpression = isExpression2;
186
186
  exports2.isExpressionStatement = isExpressionStatement2;
187
187
  exports2.isExpressionWrapper = isExpressionWrapper;
188
- exports2.isFile = isFile;
188
+ exports2.isFile = isFile2;
189
189
  exports2.isFlow = isFlow;
190
190
  exports2.isFlowBaseAnnotation = isFlowBaseAnnotation;
191
191
  exports2.isFlowDeclaration = isFlowDeclaration;
@@ -495,7 +495,7 @@ var require_generated = __commonJS({
495
495
  if (node.type !== "ExpressionStatement") return false;
496
496
  return opts == null || (0, _shallowEqual.default)(node, opts);
497
497
  }
498
- function isFile(node, opts) {
498
+ function isFile2(node, opts) {
499
499
  if (!node) return false;
500
500
  if (node.type !== "File") return false;
501
501
  return opts == null || (0, _shallowEqual.default)(node, opts);
@@ -7328,7 +7328,7 @@ var require_lowercase = __commonJS({
7328
7328
  exports2.restElement = restElement;
7329
7329
  exports2.restProperty = RestProperty;
7330
7330
  exports2.returnStatement = returnStatement2;
7331
- exports2.sequenceExpression = sequenceExpression;
7331
+ exports2.sequenceExpression = sequenceExpression2;
7332
7332
  exports2.spreadElement = spreadElement;
7333
7333
  exports2.spreadProperty = SpreadProperty;
7334
7334
  exports2.staticBlock = staticBlock;
@@ -7882,7 +7882,7 @@ var require_lowercase = __commonJS({
7882
7882
  validate(defs.argument, node, "argument", argument, 1);
7883
7883
  return node;
7884
7884
  }
7885
- function sequenceExpression(expressions) {
7885
+ function sequenceExpression2(expressions) {
7886
7886
  const node = {
7887
7887
  type: "SequenceExpression",
7888
7888
  expressions
@@ -11976,7 +11976,7 @@ var require_cloneNode = __commonJS({
11976
11976
  Object.defineProperty(exports2, "__esModule", {
11977
11977
  value: true
11978
11978
  });
11979
- exports2.default = cloneNode;
11979
+ exports2.default = cloneNode2;
11980
11980
  var _index = require_definitions();
11981
11981
  var _index2 = require_generated();
11982
11982
  var {
@@ -11996,7 +11996,7 @@ var require_cloneNode = __commonJS({
11996
11996
  }
11997
11997
  return cloneIfNode(obj, deep, withoutLoc, commentsCache);
11998
11998
  }
11999
- function cloneNode(node, deep = true, withoutLoc = false) {
11999
+ function cloneNode2(node, deep = true, withoutLoc = false) {
12000
12000
  return cloneNodeInternal(node, deep, withoutLoc, /* @__PURE__ */ new Map());
12001
12001
  }
12002
12002
  function cloneNodeInternal(node, deep = true, withoutLoc = false, commentsCache) {
@@ -14115,8 +14115,11 @@ var require_lib3 = __commonJS({
14115
14115
  // src/index.ts
14116
14116
  var index_exports = {};
14117
14117
  __export(index_exports, {
14118
+ clearModuleMetadata: () => clearModuleMetadata,
14118
14119
  createFictPlugin: () => createFictPlugin,
14119
- default: () => index_default
14120
+ default: () => index_default,
14121
+ resolveModuleMetadata: () => resolveModuleMetadata,
14122
+ setModuleMetadata: () => setModuleMetadata
14120
14123
  });
14121
14124
  module.exports = __toCommonJS(index_exports);
14122
14125
  var import_helper_plugin_utils = require("@babel/helper-plugin-utils");
@@ -14319,6 +14322,7 @@ function debugWarn(flag, message, data) {
14319
14322
  // src/ir/build-hir.ts
14320
14323
  var import_core = require("@babel/core");
14321
14324
  var import_plugin_transform_destructuring = __toESM(require("@babel/plugin-transform-destructuring"), 1);
14325
+ var import_traverse = __toESM(require("@babel/traverse"), 1);
14322
14326
  var t = __toESM(require_lib3(), 1);
14323
14327
 
14324
14328
  // src/ir/hir.ts
@@ -14405,9 +14409,9 @@ function extractDependencyPath(expr) {
14405
14409
  }
14406
14410
  return void 0;
14407
14411
  }
14408
- function pathToString(path) {
14409
- let result = path.base;
14410
- for (const seg of path.segments) {
14412
+ function pathToString(path2) {
14413
+ let result = path2.base;
14414
+ for (const seg of path2.segments) {
14411
14415
  if (seg.optional) {
14412
14416
  result += "?.";
14413
14417
  } else {
@@ -14432,42 +14436,56 @@ var resolveDestructuringPlugin = () => {
14432
14436
  const mod = import_plugin_transform_destructuring.default;
14433
14437
  return mod?.default ?? mod;
14434
14438
  };
14435
- var createAssignmentDestructuringPlugin = () => {
14436
- const pluginFactory = resolveDestructuringPlugin();
14437
- if (typeof pluginFactory !== "function") {
14438
- throw new Error("Expected @babel/plugin-transform-destructuring to export a function");
14439
- }
14440
- const plugin = pluginFactory(
14441
- {
14442
- assertVersion() {
14443
- },
14444
- assumption() {
14445
- return void 0;
14446
- },
14447
- types: t
14448
- },
14449
- {}
14450
- );
14451
- return {
14452
- visitor: {
14453
- AssignmentExpression(path, state) {
14454
- if (!t.isObjectPattern(path.node.left) && !t.isArrayPattern(path.node.left)) return;
14455
- const visitor = plugin.visitor?.AssignmentExpression;
14456
- if (!visitor) return;
14457
- visitor.call(this, path, state);
14439
+ var resolveTraverse = () => {
14440
+ const mod = import_traverse.default;
14441
+ return mod?.default ?? mod;
14442
+ };
14443
+ var OBJECT_REST_HELPERS = /* @__PURE__ */ new Set(["_objectWithoutProperties", "_objectWithoutPropertiesLoose"]);
14444
+ var OBJECT_DESTRUCTURING_EMPTY_HELPER = "_objectDestructuringEmpty";
14445
+ var EXTENDS_HELPER = "_extends";
14446
+ var isSameIdentifier = (left, right) => {
14447
+ return t.isIdentifier(left) && t.isIdentifier(right) && left.name === right.name;
14448
+ };
14449
+ var rewriteObjectRestHelpers = (ast) => {
14450
+ const traverse = resolveTraverse();
14451
+ traverse(ast, {
14452
+ CallExpression(path2) {
14453
+ const { callee, arguments: args } = path2.node;
14454
+ if (t.isIdentifier(callee) && OBJECT_REST_HELPERS.has(callee.name)) {
14455
+ path2.node.callee = t.identifier("__fictPropsRest");
14456
+ return;
14457
+ }
14458
+ if (t.isIdentifier(callee) && callee.name === EXTENDS_HELPER && args.length === 2 && t.isObjectExpression(args[0]) && args[0].properties.length === 0 && t.isSequenceExpression(args[1]) && args[1].expressions.length === 2) {
14459
+ const [checkExpr, sourceExpr] = args[1].expressions;
14460
+ if (t.isCallExpression(checkExpr) && t.isIdentifier(checkExpr.callee) && checkExpr.callee.name === OBJECT_DESTRUCTURING_EMPTY_HELPER && checkExpr.arguments.length === 1) {
14461
+ const [checkArg] = checkExpr.arguments;
14462
+ if (checkArg && isSameIdentifier(checkArg, sourceExpr)) {
14463
+ const restCall = t.callExpression(t.identifier("__fictPropsRest"), [
14464
+ t.cloneNode(sourceExpr, true),
14465
+ t.arrayExpression([])
14466
+ ]);
14467
+ path2.replaceWith(t.sequenceExpression([checkExpr, restCall]));
14468
+ }
14469
+ }
14458
14470
  }
14459
14471
  }
14460
- };
14472
+ });
14461
14473
  };
14462
14474
  var expandDestructuringAssignments = (ast) => {
14475
+ const pluginFactory = resolveDestructuringPlugin();
14476
+ if (typeof pluginFactory !== "function") {
14477
+ throw new Error("Expected @babel/plugin-transform-destructuring to export a function");
14478
+ }
14463
14479
  const result = (0, import_core.transformFromAstSync)(ast, void 0, {
14464
14480
  configFile: false,
14465
14481
  babelrc: false,
14466
14482
  ast: true,
14467
14483
  code: false,
14468
- plugins: [createAssignmentDestructuringPlugin()]
14484
+ plugins: [pluginFactory]
14469
14485
  });
14470
- return result?.ast ?? ast;
14486
+ const expanded = result?.ast ?? ast;
14487
+ rewriteObjectRestHelpers(expanded);
14488
+ return expanded;
14471
14489
  };
14472
14490
  var reportUnsupportedExpression = (node, overrideMessage) => {
14473
14491
  const loc = getLoc(node);
@@ -16377,6 +16395,70 @@ function shouldMemoizeRegion(region) {
16377
16395
  return false;
16378
16396
  }
16379
16397
 
16398
+ // src/module-metadata.ts
16399
+ var import_node_path = __toESM(require("path"), 1);
16400
+ var import_node_fs = require("fs");
16401
+ var globalMetadata = /* @__PURE__ */ new Map();
16402
+ var MODULE_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"];
16403
+ function normalizeFileName(fileName) {
16404
+ return import_node_path.default.resolve(fileName);
16405
+ }
16406
+ function getMetadataStore(options) {
16407
+ return options?.moduleMetadata ?? globalMetadata;
16408
+ }
16409
+ function isFile(pathName) {
16410
+ try {
16411
+ return (0, import_node_fs.statSync)(pathName).isFile();
16412
+ } catch {
16413
+ return false;
16414
+ }
16415
+ }
16416
+ function resolveImportSource(source, importer, store) {
16417
+ if (!importer) return void 0;
16418
+ const isAbsolute = import_node_path.default.isAbsolute(source);
16419
+ if (!isAbsolute && !source.startsWith(".")) return void 0;
16420
+ const base = isAbsolute ? source : import_node_path.default.resolve(import_node_path.default.dirname(importer), source);
16421
+ const normalized = normalizeFileName(base);
16422
+ if (store.has(normalized)) return normalized;
16423
+ if ((0, import_node_fs.existsSync)(normalized) && isFile(normalized)) return normalized;
16424
+ const ext = import_node_path.default.extname(normalized);
16425
+ if (!ext) {
16426
+ for (const suffix of MODULE_EXTENSIONS) {
16427
+ const candidate = `${normalized}${suffix}`;
16428
+ if (store.has(candidate)) return candidate;
16429
+ if ((0, import_node_fs.existsSync)(candidate) && isFile(candidate)) return candidate;
16430
+ }
16431
+ }
16432
+ for (const suffix of MODULE_EXTENSIONS) {
16433
+ const candidate = import_node_path.default.join(normalized, `index${suffix}`);
16434
+ if (store.has(candidate)) return candidate;
16435
+ if ((0, import_node_fs.existsSync)(candidate) && isFile(candidate)) return candidate;
16436
+ }
16437
+ return void 0;
16438
+ }
16439
+ function resolveModuleMetadata(source, importer, options) {
16440
+ if (options?.resolveModuleMetadata) {
16441
+ const resolved = options.resolveModuleMetadata(source, importer);
16442
+ if (resolved) return resolved;
16443
+ }
16444
+ const store = getMetadataStore(options);
16445
+ const resolvedKey = resolveImportSource(source, importer, store);
16446
+ if (resolvedKey) {
16447
+ return store.get(resolvedKey);
16448
+ }
16449
+ if (store.has(source)) return store.get(source);
16450
+ return void 0;
16451
+ }
16452
+ function setModuleMetadata(fileName, metadata, options) {
16453
+ if (!fileName) return;
16454
+ const store = getMetadataStore(options);
16455
+ store.set(normalizeFileName(fileName), metadata);
16456
+ }
16457
+ function clearModuleMetadata(options) {
16458
+ const store = getMetadataStore(options);
16459
+ store.clear();
16460
+ }
16461
+
16380
16462
  // src/validation.ts
16381
16463
  var DiagnosticMessages = {
16382
16464
  ["FICT-P001" /* FICT_P001 */]: "Props destructuring falls back to non-reactive binding.",
@@ -16569,6 +16651,23 @@ function buildPropsPlan(attributes, children, ctx, helpers) {
16569
16651
  }
16570
16652
  return false;
16571
16653
  };
16654
+ const getBaseIdentifier2 = (expr) => {
16655
+ if (expr.kind === "Identifier") return expr.name;
16656
+ if (expr.kind === "MemberExpression" || expr.kind === "OptionalMemberExpression") {
16657
+ return getBaseIdentifier2(expr.object);
16658
+ }
16659
+ return null;
16660
+ };
16661
+ const isDynamicStoreMember = (expr) => {
16662
+ if (expr.kind !== "MemberExpression" && expr.kind !== "OptionalMemberExpression") return false;
16663
+ if (!expr.computed) return false;
16664
+ if (expr.property.kind === "Literal" && (typeof expr.property.value === "string" || typeof expr.property.value === "number")) {
16665
+ return false;
16666
+ }
16667
+ const base = getBaseIdentifier2(expr.object);
16668
+ if (!base) return false;
16669
+ return ctx.storeVars?.has(helpers.deSSAVarName(base)) ?? false;
16670
+ };
16572
16671
  const flushBucket = () => {
16573
16672
  if (bucket.length === 0) return;
16574
16673
  segments.push({ kind: "object", properties: bucket });
@@ -16640,13 +16739,15 @@ function buildPropsPlan(attributes, children, ctx, helpers) {
16640
16739
  ctx
16641
16740
  ) : null;
16642
16741
  const useMemoProp = usesTracked && trackedExpr && t4.isExpression(trackedExpr) && !t4.isIdentifier(trackedExpr) && !t4.isMemberExpression(trackedExpr) && !t4.isLiteral(trackedExpr);
16742
+ const forceMemoProp = usesTracked && isDynamicStoreMember(attr.value);
16743
+ const shouldMemoProp = useMemoProp || forceMemoProp;
16643
16744
  const valueExpr = !isFunctionLike && isAccessorBase && baseIdent ? (() => {
16644
16745
  ctx.helpersUsed.add("propGetter");
16645
16746
  return t4.callExpression(t4.identifier(RUNTIME_ALIASES.propGetter), [
16646
16747
  t4.arrowFunctionExpression([], t4.callExpression(t4.identifier(baseIdent), []))
16647
16748
  ]);
16648
16749
  })() : usesTracked && t4.isExpression(lowered) ? (() => {
16649
- if (useMemoProp) {
16750
+ if (shouldMemoProp) {
16650
16751
  ctx.helpersUsed.add("prop");
16651
16752
  return t4.callExpression(t4.identifier(RUNTIME_ALIASES.prop), [
16652
16753
  t4.arrowFunctionExpression([], trackedExpr ?? lowered)
@@ -16839,7 +16940,13 @@ function rewriteExprWithMap(expr, rewrites) {
16839
16940
  return {
16840
16941
  ...expr,
16841
16942
  object: rewriteExprWithMap(expr.object, rewrites),
16842
- property: rewriteExprWithMap(expr.property, rewrites)
16943
+ property: expr.computed ? rewriteExprWithMap(expr.property, rewrites) : expr.property
16944
+ };
16945
+ case "OptionalMemberExpression":
16946
+ return {
16947
+ ...expr,
16948
+ object: rewriteExprWithMap(expr.object, rewrites),
16949
+ property: expr.computed ? rewriteExprWithMap(expr.property, rewrites) : expr.property
16843
16950
  };
16844
16951
  case "BinaryExpression":
16845
16952
  case "LogicalExpression":
@@ -16862,11 +16969,12 @@ function rewriteExprWithMap(expr, rewrites) {
16862
16969
  case "ObjectExpression":
16863
16970
  return {
16864
16971
  ...expr,
16865
- properties: expr.properties.map((p) => ({
16866
- ...p,
16867
- key: rewriteExprWithMap(p.key, rewrites),
16868
- value: rewriteExprWithMap(p.value, rewrites)
16869
- }))
16972
+ properties: expr.properties.map((p) => {
16973
+ if (p.kind === "SpreadElement") {
16974
+ return { ...p, argument: rewriteExprWithMap(p.argument, rewrites) };
16975
+ }
16976
+ return { ...p, value: rewriteExprWithMap(p.value, rewrites) };
16977
+ })
16870
16978
  };
16871
16979
  case "ImportExpression":
16872
16980
  return {
@@ -16980,7 +17088,17 @@ function toSSA(fn) {
16980
17088
  arguments: expr.arguments.map((a) => renameExpr(a))
16981
17089
  };
16982
17090
  case "MemberExpression":
16983
- return { ...expr, object: renameExpr(expr.object), property: renameExpr(expr.property) };
17091
+ return {
17092
+ ...expr,
17093
+ object: renameExpr(expr.object),
17094
+ property: expr.computed ? renameExpr(expr.property) : expr.property
17095
+ };
17096
+ case "OptionalMemberExpression":
17097
+ return {
17098
+ ...expr,
17099
+ object: renameExpr(expr.object),
17100
+ property: expr.computed ? renameExpr(expr.property) : expr.property
17101
+ };
16984
17102
  case "BinaryExpression":
16985
17103
  case "LogicalExpression":
16986
17104
  return { ...expr, left: renameExpr(expr.left), right: renameExpr(expr.right) };
@@ -16998,11 +17116,12 @@ function toSSA(fn) {
16998
17116
  case "ObjectExpression":
16999
17117
  return {
17000
17118
  ...expr,
17001
- properties: expr.properties.map((p) => ({
17002
- ...p,
17003
- key: renameExpr(p.key),
17004
- value: renameExpr(p.value)
17005
- }))
17119
+ properties: expr.properties.map((p) => {
17120
+ if (p.kind === "SpreadElement") {
17121
+ return { ...p, argument: renameExpr(p.argument) };
17122
+ }
17123
+ return { ...p, value: renameExpr(p.value) };
17124
+ })
17006
17125
  };
17007
17126
  default:
17008
17127
  return expr;
@@ -17497,8 +17616,8 @@ function mergeOverlappingScopes(scopes, _byName) {
17497
17616
  scope.blocks.forEach((b) => merged.blocks.add(b));
17498
17617
  scope.dependencies.forEach((d) => merged.dependencies.add(d));
17499
17618
  for (const [base, paths] of scope.dependencyPaths) {
17500
- for (const path of paths) {
17501
- addPath(merged.dependencyPaths, base, path);
17619
+ for (const path2 of paths) {
17620
+ addPath(merged.dependencyPaths, base, path2);
17502
17621
  }
17503
17622
  }
17504
17623
  merged.hasExternalEffect = merged.hasExternalEffect || scope.hasExternalEffect;
@@ -17592,12 +17711,12 @@ function collectExprReads(expr, into, paths, bound = /* @__PURE__ */ new Set(),
17592
17711
  if (bound.has(baseName(expr.name))) return;
17593
17712
  into.add(expr.name);
17594
17713
  if (paths) {
17595
- const path = {
17714
+ const path2 = {
17596
17715
  base: expr.name,
17597
17716
  segments: [],
17598
17717
  hasOptional: false
17599
17718
  };
17600
- addPath(paths, expr.name, path);
17719
+ addPath(paths, expr.name, path2);
17601
17720
  }
17602
17721
  return;
17603
17722
  case "CallExpression": {
@@ -17753,11 +17872,11 @@ function collectExprReads(expr, into, paths, bound = /* @__PURE__ */ new Set(),
17753
17872
  return;
17754
17873
  }
17755
17874
  }
17756
- function addPath(paths, base, path) {
17875
+ function addPath(paths, base, path2) {
17757
17876
  const existing = paths.get(base) ?? [];
17758
- const pathStr = pathToString(path);
17877
+ const pathStr = pathToString(path2);
17759
17878
  if (!existing.some((p) => pathToString(p) === pathStr)) {
17760
- existing.push(path);
17879
+ existing.push(path2);
17761
17880
  paths.set(base, existing);
17762
17881
  }
17763
17882
  }
@@ -17776,11 +17895,11 @@ function analyzeOptionalChainDependencies(scope) {
17776
17895
  } else {
17777
17896
  let hasRequiredPath = false;
17778
17897
  let hasOptionalOnlyPath = false;
17779
- for (const path of paths) {
17780
- if (!path.hasOptional) {
17898
+ for (const path2 of paths) {
17899
+ if (!path2.hasOptional) {
17781
17900
  hasRequiredPath = true;
17782
17901
  } else {
17783
- const firstOptionalIndex = path.segments.findIndex((s) => s.optional);
17902
+ const firstOptionalIndex = path2.segments.findIndex((s) => s.optional);
17784
17903
  if (firstOptionalIndex === 0) {
17785
17904
  hasOptionalOnlyPath = true;
17786
17905
  } else if (firstOptionalIndex > 0) {
@@ -18531,12 +18650,23 @@ function createPropsShape() {
18531
18650
  };
18532
18651
  }
18533
18652
  function cloneKeyContext(ctx) {
18534
- return new Map(ctx);
18653
+ const cloneMap = (map) => {
18654
+ const next = /* @__PURE__ */ new Map();
18655
+ for (const [key, value] of map.entries()) {
18656
+ next.set(key, new Set(value));
18657
+ }
18658
+ return next;
18659
+ };
18660
+ return {
18661
+ values: cloneMap(ctx.values),
18662
+ keySets: cloneMap(ctx.keySets)
18663
+ };
18535
18664
  }
18536
18665
  function clearPatternBindings(pattern, ctx) {
18537
18666
  if (!pattern || typeof pattern !== "object") return;
18538
18667
  if (t2.isIdentifier(pattern)) {
18539
- ctx.delete(pattern.name);
18668
+ ctx.values.delete(pattern.name);
18669
+ ctx.keySets.delete(pattern.name);
18540
18670
  return;
18541
18671
  }
18542
18672
  if (t2.isRestElement(pattern)) {
@@ -18563,19 +18693,106 @@ function clearPatternBindings(pattern, ctx) {
18563
18693
  }
18564
18694
  }
18565
18695
  }
18566
- function resolveNarrowedKey(expr, ctx) {
18696
+ function resolveNarrowedKeys(expr, ctx) {
18567
18697
  if (expr.kind === "Literal") {
18568
18698
  if (typeof expr.value === "string" || typeof expr.value === "number") {
18569
- return expr.value;
18699
+ return /* @__PURE__ */ new Set([expr.value]);
18570
18700
  }
18571
18701
  return null;
18572
18702
  }
18573
18703
  if (expr.kind === "Identifier") {
18574
- return ctx.get(expr.name) ?? null;
18704
+ const value = ctx.values.get(expr.name);
18705
+ return value ? new Set(value) : null;
18706
+ }
18707
+ if (expr.kind === "ConditionalExpression") {
18708
+ const consequent = resolveNarrowedKeys(expr.consequent, ctx);
18709
+ const alternate = resolveNarrowedKeys(expr.alternate, ctx);
18710
+ if (consequent && alternate) {
18711
+ return /* @__PURE__ */ new Set([...consequent, ...alternate]);
18712
+ }
18713
+ return null;
18714
+ }
18715
+ if (expr.kind === "SequenceExpression" && expr.expressions.length > 0) {
18716
+ const last = expr.expressions[expr.expressions.length - 1];
18717
+ return resolveNarrowedKeys(last, ctx);
18718
+ }
18719
+ if (expr.kind === "MemberExpression" || expr.kind === "OptionalMemberExpression") {
18720
+ if (expr.computed && expr.object.kind === "Identifier") {
18721
+ const keySet = ctx.keySets.get(expr.object.name);
18722
+ if (keySet && keySet.size > 0) {
18723
+ return new Set(keySet);
18724
+ }
18725
+ }
18726
+ }
18727
+ return null;
18728
+ }
18729
+ function resolveKeySet(expr, ctx) {
18730
+ if (expr.kind === "Identifier") {
18731
+ const set = ctx.keySets.get(expr.name);
18732
+ return set ? new Set(set) : null;
18733
+ }
18734
+ if (expr.kind === "ArrayExpression") {
18735
+ const values = [];
18736
+ for (const el of expr.elements) {
18737
+ if (!el) return null;
18738
+ if (el.kind !== "Literal") return null;
18739
+ if (typeof el.value !== "string" && typeof el.value !== "number") return null;
18740
+ values.push(el.value);
18741
+ }
18742
+ return values.length > 0 ? new Set(values) : null;
18743
+ }
18744
+ if (expr.kind === "CallExpression") {
18745
+ if (expr.callee.kind === "MemberExpression") {
18746
+ const object = expr.callee.object;
18747
+ const property = expr.callee.property;
18748
+ if (object.kind === "Identifier" && object.name === "Object" && !expr.callee.computed && property.kind === "Identifier" && property.name === "keys" && expr.arguments.length === 1) {
18749
+ const arg = expr.arguments[0];
18750
+ if (arg.kind === "ObjectExpression") {
18751
+ const values = [];
18752
+ for (const prop of arg.properties) {
18753
+ if (prop.kind !== "Property") return null;
18754
+ if (prop.key.kind === "Identifier") {
18755
+ values.push(prop.key.name);
18756
+ } else if (prop.key.kind === "Literal") {
18757
+ if (typeof prop.key.value !== "string" && typeof prop.key.value !== "number") {
18758
+ return null;
18759
+ }
18760
+ values.push(prop.key.value);
18761
+ } else {
18762
+ return null;
18763
+ }
18764
+ }
18765
+ return values.length > 0 ? new Set(values) : null;
18766
+ }
18767
+ }
18768
+ }
18769
+ }
18770
+ if (expr.kind === "ConditionalExpression") {
18771
+ const consequent = resolveKeySet(expr.consequent, ctx);
18772
+ const alternate = resolveKeySet(expr.alternate, ctx);
18773
+ if (consequent && alternate) {
18774
+ return /* @__PURE__ */ new Set([...consequent, ...alternate]);
18775
+ }
18776
+ return null;
18777
+ }
18778
+ if (expr.kind === "SequenceExpression" && expr.expressions.length > 0) {
18779
+ const last = expr.expressions[expr.expressions.length - 1];
18780
+ return resolveKeySet(last, ctx);
18575
18781
  }
18576
18782
  return null;
18577
18783
  }
18578
18784
  function extractEqualityNarrowing(expr) {
18785
+ if (expr.kind === "LogicalExpression" && expr.operator === "||") {
18786
+ const left = extractEqualityNarrowing(expr.left);
18787
+ const right = extractEqualityNarrowing(expr.right);
18788
+ if (left && right && left.kind === "eq" && right.kind === "eq" && left.name === right.name) {
18789
+ return {
18790
+ name: left.name,
18791
+ values: /* @__PURE__ */ new Set([...left.values, ...right.values]),
18792
+ kind: "eq"
18793
+ };
18794
+ }
18795
+ }
18579
18796
  if (expr.kind !== "BinaryExpression") return null;
18580
18797
  const isEq = expr.operator === "===";
18581
18798
  const isNeq = expr.operator === "!==";
@@ -18590,17 +18807,55 @@ function extractEqualityNarrowing(expr) {
18590
18807
  if (expr.left.kind === "Identifier") {
18591
18808
  const value = literalValue(expr.right);
18592
18809
  if (value !== null) {
18593
- return { name: expr.left.name, value, kind: isEq ? "eq" : "neq" };
18810
+ return { name: expr.left.name, values: /* @__PURE__ */ new Set([value]), kind: isEq ? "eq" : "neq" };
18594
18811
  }
18595
18812
  }
18596
18813
  if (expr.right.kind === "Identifier") {
18597
18814
  const value = literalValue(expr.left);
18598
18815
  if (value !== null) {
18599
- return { name: expr.right.name, value, kind: isEq ? "eq" : "neq" };
18816
+ return { name: expr.right.name, values: /* @__PURE__ */ new Set([value]), kind: isEq ? "eq" : "neq" };
18600
18817
  }
18601
18818
  }
18602
18819
  return null;
18603
18820
  }
18821
+ function applyNarrowing(ctx, name, values) {
18822
+ const existing = ctx.values.get(name);
18823
+ if (!existing) {
18824
+ ctx.values.set(name, new Set(values));
18825
+ return;
18826
+ }
18827
+ const intersection = /* @__PURE__ */ new Set();
18828
+ for (const value of existing) {
18829
+ if (values.has(value)) intersection.add(value);
18830
+ }
18831
+ if (intersection.size > 0) {
18832
+ ctx.values.set(name, intersection);
18833
+ } else {
18834
+ ctx.values.delete(name);
18835
+ }
18836
+ }
18837
+ function applyKeyAssignment(ctx, name, expr) {
18838
+ ctx.values.delete(name);
18839
+ ctx.keySets.delete(name);
18840
+ let assignedKeys = null;
18841
+ let keySet = null;
18842
+ if (expr.kind === "Identifier") {
18843
+ assignedKeys = resolveNarrowedKeys(expr, ctx);
18844
+ keySet = resolveKeySet(expr, ctx);
18845
+ if (ctx.keySets.has(expr.name)) {
18846
+ ctx.keySets.delete(expr.name);
18847
+ }
18848
+ } else {
18849
+ assignedKeys = resolveNarrowedKeys(expr, ctx);
18850
+ keySet = resolveKeySet(expr, ctx);
18851
+ }
18852
+ if (assignedKeys && assignedKeys.size > 0) {
18853
+ ctx.values.set(name, new Set(assignedKeys));
18854
+ }
18855
+ if (keySet && keySet.size > 0) {
18856
+ ctx.keySets.set(name, new Set(keySet));
18857
+ }
18858
+ }
18604
18859
  function mergeShapes(a, b) {
18605
18860
  return {
18606
18861
  knownKeys: /* @__PURE__ */ new Set([...a.knownKeys, ...b.knownKeys]),
@@ -18622,7 +18877,7 @@ function analyzeObjectShapes(fn) {
18622
18877
  shapes.set(param.name, createUnknownShape({ kind: "param", name: param.name }));
18623
18878
  }
18624
18879
  }
18625
- const baseCtx = /* @__PURE__ */ new Map();
18880
+ const baseCtx = { values: /* @__PURE__ */ new Map(), keySets: /* @__PURE__ */ new Map() };
18626
18881
  let structured = null;
18627
18882
  try {
18628
18883
  structured = structurizeCFG(fn, {
@@ -18709,9 +18964,9 @@ function analyzeStructuredNode(node, shapes, propertyReads, ctx) {
18709
18964
  const alternateCtx = cloneKeyContext(ctx);
18710
18965
  if (narrowing) {
18711
18966
  if (narrowing.kind === "eq") {
18712
- consequentCtx.set(narrowing.name, narrowing.value);
18967
+ applyNarrowing(consequentCtx, narrowing.name, narrowing.values);
18713
18968
  } else {
18714
- alternateCtx.set(narrowing.name, narrowing.value);
18969
+ applyNarrowing(alternateCtx, narrowing.name, narrowing.values);
18715
18970
  }
18716
18971
  }
18717
18972
  analyzeStructuredNode(node.consequent, shapes, propertyReads, consequentCtx);
@@ -18726,7 +18981,7 @@ function analyzeStructuredNode(node, shapes, propertyReads, ctx) {
18726
18981
  for (const caseNode of node.cases) {
18727
18982
  const caseCtx = cloneKeyContext(ctx);
18728
18983
  if (discriminant && caseNode.test?.kind === "Literal" && (typeof caseNode.test.value === "string" || typeof caseNode.test.value === "number")) {
18729
- caseCtx.set(discriminant, caseNode.test.value);
18984
+ applyNarrowing(caseCtx, discriminant, /* @__PURE__ */ new Set([caseNode.test.value]));
18730
18985
  }
18731
18986
  analyzeStructuredNode(caseNode.body, shapes, propertyReads, caseCtx);
18732
18987
  }
@@ -18757,7 +19012,8 @@ function analyzeStructuredNode(node, shapes, propertyReads, ctx) {
18757
19012
  analyzeExpression(node.iterable, shapes, propertyReads, ctx);
18758
19013
  {
18759
19014
  const bodyCtx = cloneKeyContext(ctx);
18760
- bodyCtx.delete(node.variable);
19015
+ bodyCtx.values.delete(node.variable);
19016
+ bodyCtx.keySets.delete(node.variable);
18761
19017
  if (node.pattern) {
18762
19018
  clearPatternBindings(node.pattern, bodyCtx);
18763
19019
  }
@@ -18768,7 +19024,8 @@ function analyzeStructuredNode(node, shapes, propertyReads, ctx) {
18768
19024
  analyzeExpression(node.object, shapes, propertyReads, ctx);
18769
19025
  {
18770
19026
  const bodyCtx = cloneKeyContext(ctx);
18771
- bodyCtx.delete(node.variable);
19027
+ bodyCtx.values.delete(node.variable);
19028
+ bodyCtx.keySets.delete(node.variable);
18772
19029
  if (node.pattern) {
18773
19030
  clearPatternBindings(node.pattern, bodyCtx);
18774
19031
  }
@@ -18780,7 +19037,8 @@ function analyzeStructuredNode(node, shapes, propertyReads, ctx) {
18780
19037
  if (node.handler) {
18781
19038
  const handlerCtx = cloneKeyContext(ctx);
18782
19039
  if (node.handler.param) {
18783
- handlerCtx.delete(node.handler.param);
19040
+ handlerCtx.values.delete(node.handler.param);
19041
+ handlerCtx.keySets.delete(node.handler.param);
18784
19042
  }
18785
19043
  analyzeStructuredNode(node.handler.body, shapes, propertyReads, handlerCtx);
18786
19044
  }
@@ -18806,9 +19064,7 @@ function analyzeStructuredNode(node, shapes, propertyReads, ctx) {
18806
19064
  }
18807
19065
  function analyzeInstruction(instr, shapes, propertyReads, ctx) {
18808
19066
  if (instr.kind === "Assign") {
18809
- if (ctx.has(instr.target.name)) {
18810
- ctx.delete(instr.target.name);
18811
- }
19067
+ applyKeyAssignment(ctx, instr.target.name, instr.value);
18812
19068
  const valueShape = analyzeExpression(instr.value, shapes, propertyReads, ctx);
18813
19069
  if (valueShape) {
18814
19070
  const existing = shapes.get(instr.target.name);
@@ -18865,12 +19121,14 @@ function analyzeExpression(expr, shapes, propertyReads, ctx) {
18865
19121
  const reads = propertyReads.get(base) ?? /* @__PURE__ */ new Set();
18866
19122
  const baseShape = shapes.get(base);
18867
19123
  if (directMember.computed) {
18868
- const resolved = resolveNarrowedKey(directMember.property, ctx);
18869
- if (resolved !== null) {
18870
- const key = String(resolved);
18871
- reads.add(key);
18872
- if (baseShape) {
18873
- baseShape.knownKeys.add(key);
19124
+ const resolved = resolveNarrowedKeys(directMember.property, ctx);
19125
+ if (resolved && resolved.size > 0) {
19126
+ for (const value of resolved) {
19127
+ const key = String(value);
19128
+ reads.add(key);
19129
+ if (baseShape) {
19130
+ baseShape.knownKeys.add(key);
19131
+ }
18874
19132
  }
18875
19133
  } else if (baseShape) {
18876
19134
  baseShape.dynamicAccess = true;
@@ -18892,6 +19150,34 @@ function analyzeExpression(expr, shapes, propertyReads, ctx) {
18892
19150
  return null;
18893
19151
  }
18894
19152
  case "CallExpression": {
19153
+ if (expr.callee.kind === "MemberExpression") {
19154
+ if (expr.callee.object.kind === "Identifier") {
19155
+ const baseName2 = expr.callee.object.name;
19156
+ const propName = !expr.callee.computed && expr.callee.property.kind === "Identifier" ? expr.callee.property.name : expr.callee.property.kind === "Literal" && typeof expr.callee.property.value === "string" ? expr.callee.property.value : null;
19157
+ if (propName && ctx.keySets.has(baseName2) && [
19158
+ "push",
19159
+ "pop",
19160
+ "shift",
19161
+ "unshift",
19162
+ "splice",
19163
+ "sort",
19164
+ "reverse",
19165
+ "copyWithin",
19166
+ "fill"
19167
+ ].includes(propName)) {
19168
+ ctx.keySets.delete(baseName2);
19169
+ }
19170
+ }
19171
+ }
19172
+ for (const arg of expr.arguments) {
19173
+ if (arg.kind === "Identifier" && ctx.keySets.has(arg.name)) {
19174
+ ctx.keySets.delete(arg.name);
19175
+ } else if (arg.kind === "SpreadElement" && arg.argument.kind === "Identifier") {
19176
+ if (ctx.keySets.has(arg.argument.name)) {
19177
+ ctx.keySets.delete(arg.argument.name);
19178
+ }
19179
+ }
19180
+ }
18895
19181
  for (const arg of expr.arguments) {
18896
19182
  markEscaping(arg, shapes);
18897
19183
  }
@@ -18943,9 +19229,7 @@ function analyzeExpression(expr, shapes, propertyReads, ctx) {
18943
19229
  }
18944
19230
  case "AssignmentExpression": {
18945
19231
  if (expr.left.kind === "Identifier") {
18946
- if (ctx.has(expr.left.name)) {
18947
- ctx.delete(expr.left.name);
18948
- }
19232
+ applyKeyAssignment(ctx, expr.left.name, expr.right);
18949
19233
  }
18950
19234
  if (expr.left.kind === "MemberExpression") {
18951
19235
  const base = getBaseIdentifier(expr.left.object);
@@ -18957,14 +19241,19 @@ function analyzeExpression(expr, shapes, propertyReads, ctx) {
18957
19241
  } else if (expr.left.property.kind === "Literal" && typeof expr.left.property.value === "string") {
18958
19242
  shape.mutableKeys.add(expr.left.property.value);
18959
19243
  } else {
18960
- const resolved = resolveNarrowedKey(expr.left.property, ctx);
18961
- if (resolved !== null) {
18962
- shape.mutableKeys.add(String(resolved));
19244
+ const resolved = resolveNarrowedKeys(expr.left.property, ctx);
19245
+ if (resolved && resolved.size > 0) {
19246
+ for (const value of resolved) {
19247
+ shape.mutableKeys.add(String(value));
19248
+ }
18963
19249
  } else {
18964
19250
  shape.dynamicAccess = true;
18965
19251
  }
18966
19252
  }
18967
19253
  }
19254
+ if (ctx.keySets.has(base)) {
19255
+ ctx.keySets.delete(base);
19256
+ }
18968
19257
  }
18969
19258
  }
18970
19259
  analyzeExpression(expr.right, shapes, propertyReads, ctx);
@@ -18972,8 +19261,13 @@ function analyzeExpression(expr, shapes, propertyReads, ctx) {
18972
19261
  }
18973
19262
  case "UpdateExpression": {
18974
19263
  if (expr.argument.kind === "Identifier") {
18975
- if (ctx.has(expr.argument.name)) {
18976
- ctx.delete(expr.argument.name);
19264
+ ctx.values.delete(expr.argument.name);
19265
+ ctx.keySets.delete(expr.argument.name);
19266
+ }
19267
+ if (expr.argument.kind === "MemberExpression") {
19268
+ const base = getBaseIdentifier(expr.argument.object);
19269
+ if (base) {
19270
+ ctx.keySets.delete(base);
18977
19271
  }
18978
19272
  }
18979
19273
  analyzeExpression(expr.argument, shapes, propertyReads, ctx);
@@ -19405,7 +19699,11 @@ function expressionUsesTracked(expr, ctx) {
19405
19699
  return ctx.trackedVars.has(deSSAVarName(expr.name)) || (ctx.externalTracked?.has(deSSAVarName(expr.name)) ?? false) || (ctx.memoVars?.has(deSSAVarName(expr.name)) ?? false) || (ctx.aliasVars?.has(deSSAVarName(expr.name)) ?? false);
19406
19700
  case "MemberExpression":
19407
19701
  case "OptionalMemberExpression":
19408
- return expressionUsesTracked(expr.object, ctx);
19702
+ if (expressionUsesTracked(expr.object, ctx)) return true;
19703
+ if (expr.computed && expr.property.kind !== "Literal") {
19704
+ return expressionUsesTracked(expr.property, ctx);
19705
+ }
19706
+ return false;
19409
19707
  case "CallExpression":
19410
19708
  case "OptionalCallExpression":
19411
19709
  if (expressionUsesTracked(expr.callee, ctx)) return true;
@@ -21213,6 +21511,24 @@ function setNodeLoc(node, loc) {
21213
21511
  node.loc = cloneLoc(loc) ?? null;
21214
21512
  return node;
21215
21513
  }
21514
+ function serializeHookReturnInfo(info) {
21515
+ const objectProps = info.objectProps ? Object.fromEntries(info.objectProps.entries()) : void 0;
21516
+ const arrayProps = info.arrayProps ? Object.fromEntries(Array.from(info.arrayProps.entries()).map(([k, v]) => [String(k), v])) : void 0;
21517
+ return {
21518
+ objectProps,
21519
+ arrayProps,
21520
+ directAccessor: info.directAccessor
21521
+ };
21522
+ }
21523
+ function deserializeHookReturnInfo(info) {
21524
+ const objectProps = info.objectProps ? new Map(Object.entries(info.objectProps)) : void 0;
21525
+ const arrayProps = info.arrayProps ? new Map(Object.entries(info.arrayProps).map(([k, v]) => [Number.parseInt(k, 10), v])) : void 0;
21526
+ return {
21527
+ objectProps,
21528
+ arrayProps,
21529
+ directAccessor: info.directAccessor
21530
+ };
21531
+ }
21216
21532
  function propagateHookResultAlias(targetBase, value, ctx) {
21217
21533
  const mapSource = (source) => {
21218
21534
  const hookName = ctx.hookResultVarMap?.get(source);
@@ -21236,6 +21552,15 @@ function propagateHookResultAlias(targetBase, value, ctx) {
21236
21552
  mapSource(deSSAVarName(firstArg.name));
21237
21553
  }
21238
21554
  }
21555
+ if (value.kind === "SequenceExpression" && value.expressions.length > 0) {
21556
+ const last = value.expressions[value.expressions.length - 1];
21557
+ if (last && last.kind === "CallExpression" && last.callee.kind === "Identifier" && last.callee.name === "__fictPropsRest") {
21558
+ const firstArg = last.arguments[0];
21559
+ if (firstArg && firstArg.kind === "Identifier") {
21560
+ mapSource(deSSAVarName(firstArg.name));
21561
+ }
21562
+ }
21563
+ }
21239
21564
  }
21240
21565
  function applyRegionToContext(ctx, region) {
21241
21566
  const prevRegion = ctx.currentRegion;
@@ -21542,6 +21867,7 @@ function createCodegenContext(t4) {
21542
21867
  aliasVars: /* @__PURE__ */ new Set(),
21543
21868
  externalTracked: /* @__PURE__ */ new Set(),
21544
21869
  storeVars: /* @__PURE__ */ new Set(),
21870
+ importedNamespaces: /* @__PURE__ */ new Map(),
21545
21871
  signalVars: /* @__PURE__ */ new Set(),
21546
21872
  functionVars: /* @__PURE__ */ new Set(),
21547
21873
  memoVars: /* @__PURE__ */ new Set(),
@@ -22489,6 +22815,12 @@ function extractKeyFromMapCallback(callback) {
22489
22815
  if (!jsx) return void 0;
22490
22816
  return extractKeyFromAttributes(jsx.attributes);
22491
22817
  }
22818
+ function buildOutputParams(fn, t4) {
22819
+ if (fn.rawParams && fn.rawParams.length > 0) {
22820
+ return fn.rawParams.map((param) => t4.cloneNode(param, true));
22821
+ }
22822
+ return fn.params.map((p) => t4.identifier(deSSAVarName(p.name)));
22823
+ }
22492
22824
  function lowerTrackedExpression(expr, ctx) {
22493
22825
  const regionOverride = ctx.inReturn && ctx.currentFnIsHook ? null : ctx.currentRegion ?? (ctx.trackedVars.size ? {
22494
22826
  id: -1,
@@ -22782,6 +23114,171 @@ function collectRuntimeImportNames(body, t4) {
22782
23114
  }
22783
23115
  return imported;
22784
23116
  }
23117
+ function addImportedReactiveBinding(name, kind, ctx) {
23118
+ const base = deSSAVarName(name);
23119
+ if (kind === "signal") {
23120
+ ctx.signalVars?.add(base);
23121
+ } else if (kind === "store") {
23122
+ ctx.storeVars?.add(base);
23123
+ } else if (kind === "memo") {
23124
+ ctx.memoVars?.add(base);
23125
+ }
23126
+ ctx.trackedVars.add(base);
23127
+ }
23128
+ function applyImportedReactiveMetadata(body, ctx, t4, options) {
23129
+ const importer = options?.filename;
23130
+ const namespaces = /* @__PURE__ */ new Map();
23131
+ for (const stmt of body) {
23132
+ if (!t4.isImportDeclaration(stmt)) continue;
23133
+ const meta = resolveModuleMetadata(stmt.source.value, importer, options);
23134
+ if (!meta) continue;
23135
+ for (const spec of stmt.specifiers) {
23136
+ if (t4.isImportSpecifier(spec)) {
23137
+ const importedName = t4.isIdentifier(spec.imported) ? spec.imported.name : String(spec.imported.value);
23138
+ const localName = spec.local.name;
23139
+ const kind = meta.exports[importedName];
23140
+ if (kind) {
23141
+ addImportedReactiveBinding(localName, kind, ctx);
23142
+ }
23143
+ const hookInfo = meta.hooks?.[importedName];
23144
+ if (hookInfo) {
23145
+ ctx.hookReturnInfo = ctx.hookReturnInfo ?? /* @__PURE__ */ new Map();
23146
+ ctx.hookReturnInfo.set(localName, deserializeHookReturnInfo(hookInfo));
23147
+ }
23148
+ continue;
23149
+ }
23150
+ if (t4.isImportDefaultSpecifier(spec)) {
23151
+ const localName = spec.local.name;
23152
+ const kind = meta.exports.default;
23153
+ if (kind) {
23154
+ addImportedReactiveBinding(localName, kind, ctx);
23155
+ }
23156
+ const hookInfo = meta.hooks?.default;
23157
+ if (hookInfo) {
23158
+ ctx.hookReturnInfo = ctx.hookReturnInfo ?? /* @__PURE__ */ new Map();
23159
+ ctx.hookReturnInfo.set(localName, deserializeHookReturnInfo(hookInfo));
23160
+ }
23161
+ continue;
23162
+ }
23163
+ if (t4.isImportNamespaceSpecifier(spec)) {
23164
+ namespaces.set(spec.local.name, meta);
23165
+ }
23166
+ }
23167
+ }
23168
+ if (namespaces.size > 0) {
23169
+ ctx.importedNamespaces = namespaces;
23170
+ }
23171
+ }
23172
+ function classifyReactiveExport(name, ctx) {
23173
+ const base = deSSAVarName(name);
23174
+ if (ctx.storeVars?.has(base)) return "store";
23175
+ if (ctx.signalVars?.has(base)) return "signal";
23176
+ if (ctx.aliasVars?.has(base)) return "signal";
23177
+ if (ctx.memoVars?.has(base)) return "memo";
23178
+ return null;
23179
+ }
23180
+ function buildModuleReactiveMetadata(body, ctx, t4, options, stateMacroNames, memoMacroNames) {
23181
+ const metadata = { exports: {} };
23182
+ const hookExports = {};
23183
+ const addExport = (exportName, localName) => {
23184
+ const kind = classifyReactiveExport(localName, ctx);
23185
+ if (kind) {
23186
+ metadata.exports[exportName] = kind;
23187
+ }
23188
+ const hookInfo = getHookReturnInfo(localName, ctx);
23189
+ if (hookInfo) {
23190
+ hookExports[exportName] = serializeHookReturnInfo(hookInfo);
23191
+ }
23192
+ };
23193
+ const addExportFromSource = (source, importedName, exportName) => {
23194
+ const sourceMeta = resolveModuleMetadata(source, options?.filename, options);
23195
+ if (!sourceMeta) return;
23196
+ const kind = sourceMeta.exports[importedName];
23197
+ if (kind) {
23198
+ metadata.exports[exportName] = kind;
23199
+ }
23200
+ const hookInfo = sourceMeta.hooks?.[importedName];
23201
+ if (hookInfo) {
23202
+ hookExports[exportName] = hookInfo;
23203
+ }
23204
+ };
23205
+ const addDefaultExportKind = (kind) => {
23206
+ if (kind) {
23207
+ metadata.exports.default = kind;
23208
+ }
23209
+ };
23210
+ for (const stmt of body) {
23211
+ if (t4.isExportNamedDeclaration(stmt)) {
23212
+ if (stmt.source && stmt.specifiers.length > 0) {
23213
+ for (const spec of stmt.specifiers) {
23214
+ if (!t4.isExportSpecifier(spec)) continue;
23215
+ const importedName = spec.local.name;
23216
+ const exportName = t4.isIdentifier(spec.exported) ? spec.exported.name : t4.isStringLiteral(spec.exported) ? spec.exported.value : String(spec.exported);
23217
+ addExportFromSource(stmt.source.value, importedName, exportName);
23218
+ }
23219
+ continue;
23220
+ }
23221
+ if (stmt.declaration) {
23222
+ const decl = stmt.declaration;
23223
+ if (t4.isFunctionDeclaration(decl) && decl.id) {
23224
+ addExport(decl.id.name, decl.id.name);
23225
+ } else if (t4.isClassDeclaration(decl) && decl.id) {
23226
+ addExport(decl.id.name, decl.id.name);
23227
+ } else if (t4.isVariableDeclaration(decl)) {
23228
+ for (const v of decl.declarations) {
23229
+ if (t4.isIdentifier(v.id)) {
23230
+ addExport(v.id.name, v.id.name);
23231
+ }
23232
+ }
23233
+ }
23234
+ } else {
23235
+ for (const spec of stmt.specifiers) {
23236
+ if (!t4.isExportSpecifier(spec)) continue;
23237
+ const localName = spec.local.name;
23238
+ const exportName = t4.isIdentifier(spec.exported) ? spec.exported.name : t4.isStringLiteral(spec.exported) ? spec.exported.value : String(spec.exported);
23239
+ addExport(exportName, localName);
23240
+ }
23241
+ }
23242
+ continue;
23243
+ }
23244
+ if (t4.isExportAllDeclaration(stmt)) {
23245
+ const sourceMeta = resolveModuleMetadata(stmt.source.value, options?.filename, options);
23246
+ if (!sourceMeta) continue;
23247
+ for (const [exportName, kind] of Object.entries(sourceMeta.exports)) {
23248
+ if (exportName === "default") continue;
23249
+ metadata.exports[exportName] = kind;
23250
+ }
23251
+ if (sourceMeta.hooks) {
23252
+ for (const [exportName, info] of Object.entries(sourceMeta.hooks)) {
23253
+ if (exportName === "default") continue;
23254
+ hookExports[exportName] = info;
23255
+ }
23256
+ }
23257
+ continue;
23258
+ }
23259
+ if (t4.isExportDefaultDeclaration(stmt)) {
23260
+ const decl = stmt.declaration;
23261
+ if (t4.isIdentifier(decl)) {
23262
+ addExport("default", decl.name);
23263
+ } else if (t4.isFunctionDeclaration(decl) && decl.id) {
23264
+ addExport("default", decl.id.name);
23265
+ } else if (t4.isClassDeclaration(decl) && decl.id) {
23266
+ addExport("default", decl.id.name);
23267
+ } else if (t4.isCallExpression(decl) && t4.isIdentifier(decl.callee)) {
23268
+ const callee = decl.callee.name;
23269
+ if (stateMacroNames.has(callee) || callee === "$store") {
23270
+ addDefaultExportKind(callee === "$store" ? "store" : "signal");
23271
+ } else if (memoMacroNames.has(callee)) {
23272
+ addDefaultExportKind("memo");
23273
+ }
23274
+ }
23275
+ }
23276
+ }
23277
+ if (Object.keys(hookExports).length > 0) {
23278
+ metadata.hooks = hookExports;
23279
+ }
23280
+ return metadata;
23281
+ }
22785
23282
  function collectLocalDeclaredNames(params, blocks, t4) {
22786
23283
  const declared = /* @__PURE__ */ new Set();
22787
23284
  const addPatternNames = (pattern) => {
@@ -23090,6 +23587,24 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
23090
23587
  if (matchesListKeyPattern(expr, ctx)) {
23091
23588
  return t4.identifier(ctx.listKeyParamName);
23092
23589
  }
23590
+ if (expr.object.kind === "Identifier") {
23591
+ const nsMeta = ctx.importedNamespaces?.get(deSSAVarName(expr.object.name));
23592
+ if (nsMeta) {
23593
+ const propName = getStaticPropName(expr.property, expr.computed);
23594
+ if (typeof propName === "string") {
23595
+ const kind = nsMeta.exports[propName];
23596
+ if (kind === "signal" || kind === "memo") {
23597
+ const member = t4.memberExpression(
23598
+ t4.identifier(deSSAVarName(expr.object.name)),
23599
+ expr.computed ? t4.stringLiteral(propName) : t4.identifier(propName),
23600
+ expr.computed,
23601
+ expr.optional
23602
+ );
23603
+ return t4.callExpression(member, []);
23604
+ }
23605
+ }
23606
+ }
23607
+ }
23093
23608
  if (expr.object.kind === "Identifier" && ctx.hookResultVarMap?.has(deSSAVarName(expr.object.name))) {
23094
23609
  const hookName = ctx.hookResultVarMap.get(deSSAVarName(expr.object.name));
23095
23610
  const info = getHookReturnInfo(hookName, ctx);
@@ -23581,8 +24096,8 @@ function collectExpressionDependencies(expr, deps) {
23581
24096
  return;
23582
24097
  }
23583
24098
  if (expr.kind === "MemberExpression") {
23584
- const path = getMemberDependencyPath(expr);
23585
- if (path) deps.add(path);
24099
+ const path2 = getMemberDependencyPath(expr);
24100
+ if (path2) deps.add(path2);
23586
24101
  collectExpressionDependencies(expr.object, deps);
23587
24102
  if (expr.computed && expr.property.kind !== "Literal") {
23588
24103
  collectExpressionDependencies(expr.property, deps);
@@ -23767,9 +24282,9 @@ function replaceIdentifiersWithOverrides(node, overrides, t4, parentKind, parent
23767
24282
  if (!skipCurrentNode && (t4.isMemberExpression(node) || t4.isOptionalMemberExpression(node))) {
23768
24283
  const propertyNode = node.property;
23769
24284
  const isDynamicComputed = (node.computed ?? false) && !t4.isStringLiteral(propertyNode) && !t4.isNumericLiteral(propertyNode);
23770
- const path = getDependencyPathFromNode(node, t4);
23771
- const normalized = path ? normalizeDependencyKey2(path) : null;
23772
- const override = normalized && overrides[normalized] || (path ? overrides[path] : void 0);
24285
+ const path2 = getDependencyPathFromNode(node, t4);
24286
+ const normalized = path2 ? normalizeDependencyKey2(path2) : null;
24287
+ const override = normalized && overrides[normalized] || (path2 ? overrides[path2] : void 0);
23773
24288
  if (override && !isCallTarget && !isDynamicComputed) {
23774
24289
  const replacement = override();
23775
24290
  Object.assign(node, replacement);
@@ -24500,11 +25015,11 @@ function lowerIntrinsicElement(jsx, ctx) {
24500
25015
  }
24501
25016
  return t4.callExpression(t4.arrowFunctionExpression([], body), []);
24502
25017
  }
24503
- function resolveHIRBindingPath(path, cache, statements, ctx) {
24504
- const key = path.join(",");
25018
+ function resolveHIRBindingPath(path2, cache, statements, ctx) {
25019
+ const key = path2.join(",");
24505
25020
  if (cache.has(key)) return cache.get(key);
24506
25021
  const { t: t4 } = ctx;
24507
- const ancestorPath = [...path];
25022
+ const ancestorPath = [...path2];
24508
25023
  let ancestorId;
24509
25024
  let relativePath = [];
24510
25025
  while (ancestorPath.length > 0) {
@@ -24512,13 +25027,13 @@ function resolveHIRBindingPath(path, cache, statements, ctx) {
24512
25027
  const ancestorKey = ancestorPath.join(",");
24513
25028
  if (cache.has(ancestorKey)) {
24514
25029
  ancestorId = cache.get(ancestorKey);
24515
- relativePath = path.slice(ancestorPath.length);
25030
+ relativePath = path2.slice(ancestorPath.length);
24516
25031
  break;
24517
25032
  }
24518
25033
  }
24519
25034
  if (!ancestorId) {
24520
25035
  ancestorId = cache.get("");
24521
- relativePath = path;
25036
+ relativePath = path2;
24522
25037
  }
24523
25038
  let currentExpr = ancestorId;
24524
25039
  for (const index of relativePath) {
@@ -25327,6 +25842,7 @@ function lowerHIRWithRegions(program, t4, options, macroAliases) {
25327
25842
  const originalBody = program.originalBody ?? [];
25328
25843
  ctx.moduleDeclaredNames = collectDeclaredNames(originalBody, t4);
25329
25844
  ctx.moduleRuntimeNames = collectRuntimeImportNames(originalBody, t4);
25845
+ applyImportedReactiveMetadata(originalBody, ctx, t4, options);
25330
25846
  const stateMacroNames = /* @__PURE__ */ new Set(["$state", ...macroAliases?.state ?? []]);
25331
25847
  const memoMacroNames = new Set(macroAliases?.memo ?? ctx.memoMacroNames ?? []);
25332
25848
  if (!memoMacroNames.has("$memo")) memoMacroNames.add("$memo");
@@ -25566,6 +26082,15 @@ function lowerHIRWithRegions(program, t4, options, macroAliases) {
25566
26082
  ctx.helpersUsed.add("popContext");
25567
26083
  body.push(t4.expressionStatement(t4.callExpression(t4.identifier(RUNTIME_ALIASES.popContext), [])));
25568
26084
  }
26085
+ const moduleMeta = buildModuleReactiveMetadata(
26086
+ originalBody,
26087
+ ctx,
26088
+ t4,
26089
+ options,
26090
+ stateMacroNames,
26091
+ memoMacroNames
26092
+ );
26093
+ setModuleMetadata(options?.filename, moduleMeta, options);
25569
26094
  return t4.file(t4.program(attachHelperImports(ctx, body, t4)));
25570
26095
  }
25571
26096
  function lowerTopLevelStatementBlock(statements, ctx, t4, name = "__module_segment", existingAliases) {
@@ -26046,7 +26571,7 @@ function lowerFunctionWithRegions(fn, ctx) {
26046
26571
  if (!hasComplexControlFlow && !isAsync) {
26047
26572
  const pureDeclaredVars = /* @__PURE__ */ new Set();
26048
26573
  const pureStatements = lowerStructuredNodeWithoutRegions(structured, t4, ctx, pureDeclaredVars);
26049
- const params2 = fn.params.map((p) => t4.identifier(deSSAVarName(p.name)));
26574
+ const params2 = buildOutputParams(fn, t4);
26050
26575
  const funcDecl2 = setNodeLoc(
26051
26576
  t4.functionDeclaration(
26052
26577
  t4.identifier(fn.name ?? "fn"),
@@ -26121,13 +26646,31 @@ function lowerFunctionWithRegions(fn, ctx) {
26121
26646
  )
26122
26647
  );
26123
26648
  }
26124
- let finalParams = fn.params.map((p) => t4.identifier(deSSAVarName(p.name)));
26649
+ let finalParams = buildOutputParams(fn, t4);
26125
26650
  const propsDestructuring = [];
26126
26651
  if (isComponent && fn.rawParams && fn.rawParams.length === 1) {
26127
26652
  const rawParam = fn.rawParams[0];
26128
26653
  if (rawParam && (rawParam.type === "ObjectPattern" || rawParam.type === "AssignmentPattern" && rawParam.left?.type === "ObjectPattern")) {
26129
- finalParams = [t4.identifier("__props")];
26130
26654
  const pattern = rawParam.type === "AssignmentPattern" ? rawParam.left : rawParam;
26655
+ const defaultExpr = rawParam.type === "AssignmentPattern" ? rawParam.right : null;
26656
+ if (defaultExpr) {
26657
+ const propsParamName = "__propsParam";
26658
+ finalParams = [t4.identifier(propsParamName)];
26659
+ propsDestructuring.push(
26660
+ t4.variableDeclaration("const", [
26661
+ t4.variableDeclarator(
26662
+ t4.identifier("__props"),
26663
+ t4.conditionalExpression(
26664
+ t4.binaryExpression("===", t4.identifier(propsParamName), t4.identifier("undefined")),
26665
+ t4.cloneNode(defaultExpr, true),
26666
+ t4.identifier(propsParamName)
26667
+ )
26668
+ )
26669
+ ])
26670
+ );
26671
+ } else {
26672
+ finalParams = [t4.identifier("__props")];
26673
+ }
26131
26674
  if (propsDestructurePlan) {
26132
26675
  if (propsDestructurePlan.usesProp) {
26133
26676
  ctx.helpersUsed.add("prop");
@@ -26285,7 +26828,7 @@ function optimizeHIR(program, options = {}) {
26285
26828
  originalBody: []
26286
26829
  });
26287
26830
  const ssaFn = ssaProgram.functions[0];
26288
- return ssaFn ? optimizeSSAFunction(ssaFn) : fn;
26831
+ return ssaFn ? optimizeSSAFunction(ssaFn, options) : fn;
26289
26832
  }
26290
26833
  if (isReactiveOptimizationCandidate(fn)) {
26291
26834
  return optimizeReactiveFunction(fn, exportedNames, options);
@@ -26297,9 +26840,9 @@ function optimizeHIR(program, options = {}) {
26297
26840
  functions
26298
26841
  };
26299
26842
  }
26300
- function optimizeSSAFunction(fn) {
26843
+ function optimizeSSAFunction(fn, options) {
26301
26844
  let current = fn;
26302
- current = propagateConstants(current);
26845
+ current = propagateConstants(current, options);
26303
26846
  const purity = buildPurityContext(current);
26304
26847
  current = eliminateCommonSubexpressions(current, purity);
26305
26848
  current = inlineSingleUse(current, purity);
@@ -26924,7 +27467,9 @@ function optimizeReactiveFunction(fn, exportedNames, options) {
26924
27467
  const reactive = buildReactiveContext(fn);
26925
27468
  const purity = buildPurityContext(fn);
26926
27469
  const hookLike = isHookLikeFunction(fn);
26927
- const transformedBlocks = fn.blocks.map((block) => optimizeReactiveBlock(block, reactive, purity));
27470
+ const transformedBlocks = fn.blocks.map(
27471
+ (block) => optimizeReactiveBlock(block, reactive, purity, options)
27472
+ );
26928
27473
  let transformed = { ...fn, blocks: transformedBlocks };
26929
27474
  if (isCrossBlockConstPropagationEnabled()) {
26930
27475
  transformed = propagateCrossBlockConstants(transformed, reactive, purity, scopeResult);
@@ -26959,7 +27504,7 @@ function optimizeReactiveFunction(fn, exportedNames, options) {
26959
27504
  });
26960
27505
  return { ...transformed, blocks };
26961
27506
  }
26962
- function optimizeReactiveBlock(block, reactive, purity) {
27507
+ function optimizeReactiveBlock(block, reactive, purity, options) {
26963
27508
  const constants = /* @__PURE__ */ new Map();
26964
27509
  const constObjects = /* @__PURE__ */ new Map();
26965
27510
  const constArrays = /* @__PURE__ */ new Map();
@@ -26997,7 +27542,7 @@ function optimizeReactiveBlock(block, reactive, purity) {
26997
27542
  constArrays.delete(name);
26998
27543
  }
26999
27544
  const dependsOnReactiveValue = expressionDependsOnReactive(instr.value, reactive);
27000
- let value = dependsOnReactiveValue ? instr.value : foldExpressionWithConstants(instr.value, constants, constObjects, constArrays);
27545
+ let value = dependsOnReactiveValue ? instr.value : foldExpressionWithConstants(instr.value, constants, options, constObjects, constArrays);
27001
27546
  const allowCSE = isCompilerGeneratedName(target) && (!declKind || declKind === "const");
27002
27547
  if (allowCSE && isPureExpression(value, purity) && !isExplicitMemoCall(value, purity) && !dependsOnReactiveValue && isCSESafeExpression(value, purity)) {
27003
27548
  const deps = collectExpressionIdentifiers2(value, true);
@@ -27045,7 +27590,7 @@ function optimizeReactiveBlock(block, reactive, purity) {
27045
27590
  constArrays.delete(name);
27046
27591
  }
27047
27592
  const dependsOnReactiveValue = expressionDependsOnReactive(instr.value, reactive);
27048
- const value = dependsOnReactiveValue ? instr.value : foldExpressionWithConstants(instr.value, constants, constObjects, constArrays);
27593
+ const value = dependsOnReactiveValue ? instr.value : foldExpressionWithConstants(instr.value, constants, options, constObjects, constArrays);
27049
27594
  instructions.push(value === instr.value ? instr : { ...instr, value });
27050
27595
  continue;
27051
27596
  }
@@ -27054,6 +27599,7 @@ function optimizeReactiveBlock(block, reactive, purity) {
27054
27599
  const terminator = foldTerminatorWithConstants(
27055
27600
  block.terminator,
27056
27601
  constants,
27602
+ options,
27057
27603
  reactive,
27058
27604
  constObjects,
27059
27605
  constArrays
@@ -27985,7 +28531,7 @@ function blocksContainImpureMarkers(blocks) {
27985
28531
  }
27986
28532
  return false;
27987
28533
  }
27988
- function propagateConstants(fn) {
28534
+ function propagateConstants(fn, options) {
27989
28535
  const constants = computeConstantMap(fn);
27990
28536
  if (constants.size === 0) return fn;
27991
28537
  const blocks = fn.blocks.map((block) => ({
@@ -27993,12 +28539,12 @@ function propagateConstants(fn) {
27993
28539
  instructions: block.instructions.map((instr) => {
27994
28540
  if (instr.kind === "Assign") {
27995
28541
  const replaced = replaceIdentifiersWithConstants(instr.value, constants);
27996
- const folded = foldExpression(replaced, constants);
28542
+ const folded = foldExpression(replaced, constants, options);
27997
28543
  return { ...instr, value: folded };
27998
28544
  }
27999
28545
  if (instr.kind === "Expression") {
28000
28546
  const replaced = replaceIdentifiersWithConstants(instr.value, constants);
28001
- const folded = foldExpression(replaced, constants);
28547
+ const folded = foldExpression(replaced, constants, options);
28002
28548
  return { ...instr, value: folded };
28003
28549
  }
28004
28550
  if (instr.kind === "Phi") {
@@ -28398,15 +28944,18 @@ function evaluateBinary(operator, left, right) {
28398
28944
  return UNKNOWN_CONST;
28399
28945
  }
28400
28946
  }
28401
- function foldExpression(expr, constants) {
28947
+ function foldExpression(expr, constants, options) {
28402
28948
  const value = evaluateConstant(expr, constants);
28403
28949
  if (value === UNKNOWN_CONST) {
28404
- return simplifyAlgebraically(expr, constants);
28950
+ return simplifyAlgebraically(expr, constants, options);
28405
28951
  }
28406
28952
  return { kind: "Literal", value, loc: expr.loc };
28407
28953
  }
28408
- function simplifyAlgebraically(expr, constants) {
28409
- const simplified = simplifyChildren(expr, constants);
28954
+ function simplifyAlgebraically(expr, constants, options) {
28955
+ const simplified = simplifyChildren(expr, constants, options);
28956
+ if (options.optimizeLevel === "safe") {
28957
+ return simplified;
28958
+ }
28410
28959
  if (simplified.kind === "BinaryExpression") {
28411
28960
  const { operator, left, right, loc } = simplified;
28412
28961
  switch (operator) {
@@ -28485,37 +29034,37 @@ function simplifyAlgebraically(expr, constants) {
28485
29034
  }
28486
29035
  return simplified;
28487
29036
  }
28488
- function simplifyChildren(expr, constants) {
29037
+ function simplifyChildren(expr, constants, options) {
28489
29038
  switch (expr.kind) {
28490
29039
  case "BinaryExpression":
28491
29040
  return {
28492
29041
  ...expr,
28493
- left: simplifyAlgebraically(expr.left, constants),
28494
- right: simplifyAlgebraically(expr.right, constants)
29042
+ left: simplifyAlgebraically(expr.left, constants, options),
29043
+ right: simplifyAlgebraically(expr.right, constants, options)
28495
29044
  };
28496
29045
  case "LogicalExpression":
28497
29046
  return {
28498
29047
  ...expr,
28499
- left: simplifyAlgebraically(expr.left, constants),
28500
- right: simplifyAlgebraically(expr.right, constants)
29048
+ left: simplifyAlgebraically(expr.left, constants, options),
29049
+ right: simplifyAlgebraically(expr.right, constants, options)
28501
29050
  };
28502
29051
  case "UnaryExpression":
28503
29052
  return {
28504
29053
  ...expr,
28505
- argument: simplifyAlgebraically(expr.argument, constants)
29054
+ argument: simplifyAlgebraically(expr.argument, constants, options)
28506
29055
  };
28507
29056
  case "ConditionalExpression":
28508
29057
  return {
28509
29058
  ...expr,
28510
- test: simplifyAlgebraically(expr.test, constants),
28511
- consequent: simplifyAlgebraically(expr.consequent, constants),
28512
- alternate: simplifyAlgebraically(expr.alternate, constants)
29059
+ test: simplifyAlgebraically(expr.test, constants, options),
29060
+ consequent: simplifyAlgebraically(expr.consequent, constants, options),
29061
+ alternate: simplifyAlgebraically(expr.alternate, constants, options)
28513
29062
  };
28514
29063
  case "ArrayExpression":
28515
29064
  return {
28516
29065
  ...expr,
28517
29066
  elements: expr.elements.map(
28518
- (el) => el ? simplifyAlgebraically(el, constants) : el
29067
+ (el) => el ? simplifyAlgebraically(el, constants, options) : el
28519
29068
  )
28520
29069
  };
28521
29070
  case "ObjectExpression":
@@ -28525,13 +29074,13 @@ function simplifyChildren(expr, constants) {
28525
29074
  if (prop.kind === "Property") {
28526
29075
  return {
28527
29076
  ...prop,
28528
- value: simplifyAlgebraically(prop.value, constants)
29077
+ value: simplifyAlgebraically(prop.value, constants, options)
28529
29078
  };
28530
29079
  }
28531
29080
  if (prop.kind === "SpreadElement") {
28532
29081
  return {
28533
29082
  ...prop,
28534
- argument: simplifyAlgebraically(prop.argument, constants)
29083
+ argument: simplifyAlgebraically(prop.argument, constants, options)
28535
29084
  };
28536
29085
  }
28537
29086
  return prop;
@@ -28541,35 +29090,35 @@ function simplifyChildren(expr, constants) {
28541
29090
  case "OptionalCallExpression":
28542
29091
  return {
28543
29092
  ...expr,
28544
- arguments: expr.arguments.map((arg) => simplifyAlgebraically(arg, constants))
29093
+ arguments: expr.arguments.map((arg) => simplifyAlgebraically(arg, constants, options))
28545
29094
  };
28546
29095
  case "ImportExpression":
28547
29096
  return {
28548
29097
  ...expr,
28549
- source: simplifyAlgebraically(expr.source, constants)
29098
+ source: simplifyAlgebraically(expr.source, constants, options)
28550
29099
  };
28551
29100
  case "MemberExpression":
28552
29101
  case "OptionalMemberExpression":
28553
29102
  return {
28554
29103
  ...expr,
28555
- object: simplifyAlgebraically(expr.object, constants),
28556
- property: expr.computed ? simplifyAlgebraically(expr.property, constants) : expr.property
29104
+ object: simplifyAlgebraically(expr.object, constants, options),
29105
+ property: expr.computed ? simplifyAlgebraically(expr.property, constants, options) : expr.property
28557
29106
  };
28558
29107
  default:
28559
29108
  return expr;
28560
29109
  }
28561
29110
  }
28562
- function foldExpressionWithConstants(expr, constants, constObjects, constArrays) {
29111
+ function foldExpressionWithConstants(expr, constants, options, constObjects, constArrays) {
28563
29112
  const replaced = replaceIdentifiersWithConstants(expr, constants);
28564
29113
  if (!constObjects && !constArrays) {
28565
- return foldExpression(replaced, constants);
29114
+ return foldExpression(replaced, constants, options);
28566
29115
  }
28567
29116
  const memberReplaced = replaceConstMemberExpressions(
28568
29117
  replaced,
28569
29118
  constObjects ?? /* @__PURE__ */ new Map(),
28570
29119
  constArrays ?? /* @__PURE__ */ new Map()
28571
29120
  );
28572
- return foldExpression(memberReplaced, constants);
29121
+ return foldExpression(memberReplaced, constants, options);
28573
29122
  }
28574
29123
  function replaceIdentifiersWithConstants(expr, constants, context = {}) {
28575
29124
  switch (expr.kind) {
@@ -28731,10 +29280,10 @@ function replaceConstantsInTerminator(term, constants) {
28731
29280
  return term;
28732
29281
  }
28733
29282
  }
28734
- function foldTerminatorWithConstants(term, constants, reactive, constObjects, constArrays) {
29283
+ function foldTerminatorWithConstants(term, constants, options, reactive, constObjects, constArrays) {
28735
29284
  const fold = (expr) => {
28736
29285
  if (reactive && expressionDependsOnReactive(expr, reactive)) return expr;
28737
- return foldExpressionWithConstants(expr, constants, constObjects, constArrays);
29286
+ return foldExpressionWithConstants(expr, constants, options, constObjects, constArrays);
28738
29287
  };
28739
29288
  switch (term.kind) {
28740
29289
  case "Return":
@@ -28851,11 +29400,14 @@ function hasSideEffectsBetween(instructions, start, end, purity) {
28851
29400
  function eliminateDeadCode(fn, purity) {
28852
29401
  const depsByVar = buildDependencyGraph(fn);
28853
29402
  const live = computeLiveVariables(fn, depsByVar, purity);
29403
+ const baseLive = /* @__PURE__ */ new Set();
29404
+ live.forEach((name) => baseLive.add(getSSABaseName(name)));
28854
29405
  const blocks = fn.blocks.map((block) => {
28855
29406
  const instructions = block.instructions.filter((instr) => {
28856
29407
  if (instr.kind === "Assign") {
28857
29408
  const name = instr.target.name;
28858
29409
  if (live.has(name)) return true;
29410
+ if (instr.declarationKind && baseLive.has(getSSABaseName(name))) return true;
28859
29411
  return !isPureExpression(instr.value, purity) || isExplicitMemoCall(instr.value, purity);
28860
29412
  }
28861
29413
  if (instr.kind === "Phi") {
@@ -29867,8 +30419,8 @@ function getRootIdentifier(expr, t4) {
29867
30419
  }
29868
30420
 
29869
30421
  // src/index.ts
29870
- function stripMacroImports(path, t4) {
29871
- path.traverse({
30422
+ function stripMacroImports(path2, t4) {
30423
+ path2.traverse({
29872
30424
  ImportDeclaration(importPath) {
29873
30425
  if (importPath.node.source.value !== "fict" && importPath.node.source.value !== "fict/slim")
29874
30426
  return;
@@ -29886,19 +30438,19 @@ function stripMacroImports(path, t4) {
29886
30438
  }
29887
30439
  });
29888
30440
  }
29889
- function isInsideLoop(path) {
29890
- return !!path.findParent(
30441
+ function isInsideLoop(path2) {
30442
+ return !!path2.findParent(
29891
30443
  (p) => p.isForStatement?.() || p.isWhileStatement?.() || p.isDoWhileStatement?.() || p.isForInStatement?.() || p.isForOfStatement?.()
29892
30444
  );
29893
30445
  }
29894
- function isInsideConditional(path) {
29895
- return !!path.findParent(
30446
+ function isInsideConditional(path2) {
30447
+ return !!path2.findParent(
29896
30448
  (p) => p.isIfStatement?.() || p.isConditionalExpression?.() || p.isSwitchCase?.()
29897
30449
  );
29898
30450
  }
29899
- function isInsideNestedFunction(path) {
30451
+ function isInsideNestedFunction(path2) {
29900
30452
  let depth = 0;
29901
- let current = path;
30453
+ let current = path2;
29902
30454
  while (current) {
29903
30455
  if (current.isFunction?.()) {
29904
30456
  depth++;
@@ -29908,8 +30460,8 @@ function isInsideNestedFunction(path) {
29908
30460
  }
29909
30461
  return false;
29910
30462
  }
29911
- function isInsideJSX(path) {
29912
- return !!path.findParent((p) => p.isJSXElement?.() || p.isJSXFragment?.());
30463
+ function isInsideJSX(path2) {
30464
+ return !!path2.findParent((p) => p.isJSXElement?.() || p.isJSXFragment?.());
29913
30465
  }
29914
30466
  function parseSuppressionCodes(raw) {
29915
30467
  if (!raw) return void 0;
@@ -29938,12 +30490,42 @@ function shouldSuppressWarning(suppressions, code, line) {
29938
30490
  return entry.codes.has(code);
29939
30491
  });
29940
30492
  }
29941
- function createWarningDispatcher(onWarn, suppressions) {
29942
- if (!onWarn) return () => {
30493
+ function hasErrorEscalation(options) {
30494
+ if (options.warningsAsErrors === true) return true;
30495
+ if (Array.isArray(options.warningsAsErrors) && options.warningsAsErrors.length > 0) return true;
30496
+ if (options.warningLevels) {
30497
+ return Object.values(options.warningLevels).some((level) => level === "error");
30498
+ }
30499
+ return false;
30500
+ }
30501
+ function resolveWarningLevel(code, options) {
30502
+ const override = options.warningLevels?.[code];
30503
+ if (override) return override;
30504
+ if (options.warningsAsErrors === true) return "error";
30505
+ if (Array.isArray(options.warningsAsErrors) && options.warningsAsErrors.includes(code)) {
30506
+ return "error";
30507
+ }
30508
+ return "warn";
30509
+ }
30510
+ function formatWarningAsError(warning) {
30511
+ const location = warning.line > 0 ? `${warning.fileName}:${warning.line}:${warning.column}` : warning.fileName;
30512
+ return `Fict warning treated as error (${warning.code}): ${warning.message}
30513
+ at ${location}`;
30514
+ }
30515
+ function createWarningDispatcher(onWarn, suppressions, options, dev) {
30516
+ const hasEscalation = hasErrorEscalation(options);
30517
+ if (!dev && !hasEscalation) return () => {
29943
30518
  };
29944
30519
  return (warning) => {
29945
30520
  if (shouldSuppressWarning(suppressions, warning.code, warning.line)) return;
29946
- onWarn(warning);
30521
+ const level = resolveWarningLevel(warning.code, options);
30522
+ if (level === "off") return;
30523
+ if (level === "error") {
30524
+ throw new Error(formatWarningAsError(warning));
30525
+ }
30526
+ if (dev && onWarn) {
30527
+ onWarn(warning);
30528
+ }
29947
30529
  };
29948
30530
  }
29949
30531
  function emitWarning(node, code, message, warn, fileName) {
@@ -30043,13 +30625,13 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
30043
30625
  };
30044
30626
  const reactiveNames = /* @__PURE__ */ new Set([...stateVars, ...derivedVars]);
30045
30627
  programPath.traverse({
30046
- AssignmentExpression(path) {
30047
- const { left } = path.node;
30628
+ AssignmentExpression(path2) {
30629
+ const { left } = path2.node;
30048
30630
  if (t4.isIdentifier(left)) return;
30049
30631
  if (t4.isMemberExpression(left) || t4.isOptionalMemberExpression(left)) {
30050
30632
  if (isStateRoot(left.object)) {
30051
30633
  emitWarning(
30052
- path.node,
30634
+ path2.node,
30053
30635
  "FICT-M",
30054
30636
  "Direct mutation of nested property detected; use immutable update or $store helpers",
30055
30637
  warn,
@@ -30057,7 +30639,7 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
30057
30639
  );
30058
30640
  if (isDynamicPropertyAccess(left, t4)) {
30059
30641
  emitWarning(
30060
- path.node,
30642
+ path2.node,
30061
30643
  "FICT-H",
30062
30644
  "Dynamic property access widens dependency tracking",
30063
30645
  warn,
@@ -30067,12 +30649,12 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
30067
30649
  }
30068
30650
  }
30069
30651
  },
30070
- UpdateExpression(path) {
30071
- const arg = path.node.argument;
30652
+ UpdateExpression(path2) {
30653
+ const arg = path2.node.argument;
30072
30654
  if (t4.isMemberExpression(arg) || t4.isOptionalMemberExpression(arg)) {
30073
30655
  if (isStateRoot(arg.object)) {
30074
30656
  emitWarning(
30075
- path.node,
30657
+ path2.node,
30076
30658
  "FICT-M",
30077
30659
  "Direct mutation of nested property detected; use immutable update or $store helpers",
30078
30660
  warn,
@@ -30080,7 +30662,7 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
30080
30662
  );
30081
30663
  if (isDynamicPropertyAccess(arg, t4)) {
30082
30664
  emitWarning(
30083
- path.node,
30665
+ path2.node,
30084
30666
  "FICT-H",
30085
30667
  "Dynamic property access widens dependency tracking",
30086
30668
  warn,
@@ -30090,13 +30672,13 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
30090
30672
  }
30091
30673
  }
30092
30674
  },
30093
- MemberExpression(path) {
30094
- if (!path.node.computed) return;
30095
- if (path.parentPath.isAssignmentExpression({ left: path.node })) return;
30096
- if (path.parentPath.isUpdateExpression({ argument: path.node })) return;
30097
- if (isDynamicPropertyAccess(path.node, t4) && isStateRoot(path.node.object)) {
30675
+ MemberExpression(path2) {
30676
+ if (!path2.node.computed) return;
30677
+ if (path2.parentPath.isAssignmentExpression({ left: path2.node })) return;
30678
+ if (path2.parentPath.isUpdateExpression({ argument: path2.node })) return;
30679
+ if (isDynamicPropertyAccess(path2.node, t4) && isStateRoot(path2.node.object)) {
30098
30680
  emitWarning(
30099
- path.node,
30681
+ path2.node,
30100
30682
  "FICT-H",
30101
30683
  "Dynamic property access widens dependency tracking",
30102
30684
  warn,
@@ -30104,12 +30686,12 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
30104
30686
  );
30105
30687
  }
30106
30688
  },
30107
- Function(path) {
30689
+ Function(path2) {
30108
30690
  const captured = /* @__PURE__ */ new Set();
30109
- path.traverse(
30691
+ path2.traverse(
30110
30692
  {
30111
30693
  Function(inner) {
30112
- if (inner === path) return;
30694
+ if (inner === path2) return;
30113
30695
  inner.skip();
30114
30696
  },
30115
30697
  Identifier(idPath) {
@@ -30117,7 +30699,7 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
30117
30699
  if (!reactiveNames.has(name)) return;
30118
30700
  const binding = idPath.scope.getBinding(name);
30119
30701
  if (!binding) return;
30120
- if (binding.scope === idPath.scope || binding.scope === path.scope) return;
30702
+ if (binding.scope === idPath.scope || binding.scope === path2.scope) return;
30121
30703
  captured.add(name);
30122
30704
  }
30123
30705
  },
@@ -30125,7 +30707,7 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
30125
30707
  );
30126
30708
  if (captured.size > 0) {
30127
30709
  emitWarning(
30128
- path.node,
30710
+ path2.node,
30129
30711
  "FICT-R005",
30130
30712
  `Function captures reactive variable(s): ${Array.from(captured).join(", ")}. Pass them as parameters or memoize explicitly to avoid hidden dependencies.`,
30131
30713
  warn,
@@ -30133,9 +30715,9 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
30133
30715
  );
30134
30716
  }
30135
30717
  },
30136
- CallExpression(path) {
30137
- if (t4.isIdentifier(path.node.callee, { name: "$effect" })) {
30138
- const argPath = path.get("arguments.0");
30718
+ CallExpression(path2) {
30719
+ if (t4.isIdentifier(path2.node.callee, { name: "$effect" })) {
30720
+ const argPath = path2.get("arguments.0");
30139
30721
  if (argPath?.isFunctionExpression() || argPath?.isArrowFunctionExpression()) {
30140
30722
  let hasReactiveDependency = false;
30141
30723
  argPath.traverse({
@@ -30156,7 +30738,7 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
30156
30738
  });
30157
30739
  if (!hasReactiveDependency) {
30158
30740
  emitWarning(
30159
- path.node,
30741
+ path2.node,
30160
30742
  "FICT-E001",
30161
30743
  "Effect has no reactive reads; it will run once. Consider removing $effect or adding dependencies.",
30162
30744
  warn,
@@ -30166,7 +30748,7 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
30166
30748
  }
30167
30749
  return;
30168
30750
  }
30169
- const callee = path.node.callee;
30751
+ const callee = path2.node.callee;
30170
30752
  let calleeName = "";
30171
30753
  if (t4.isIdentifier(callee)) {
30172
30754
  calleeName = callee.name;
@@ -30178,7 +30760,7 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
30178
30760
  }
30179
30761
  const isSafe = calleeName && SAFE_FUNCTIONS.has(calleeName);
30180
30762
  if (isSafe) return;
30181
- for (const arg of path.node.arguments) {
30763
+ for (const arg of path2.node.arguments) {
30182
30764
  if (!t4.isExpression(arg)) continue;
30183
30765
  if (isStateRoot(arg)) {
30184
30766
  emitWarning(
@@ -30192,13 +30774,13 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
30192
30774
  }
30193
30775
  }
30194
30776
  },
30195
- OptionalMemberExpression(path) {
30196
- if (!path.node.computed) return;
30197
- if (path.parentPath.isAssignmentExpression({ left: path.node })) return;
30198
- if (path.parentPath.isUpdateExpression({ argument: path.node })) return;
30199
- if (isDynamicPropertyAccess(path.node, t4) && isStateRoot(path.node.object)) {
30777
+ OptionalMemberExpression(path2) {
30778
+ if (!path2.node.computed) return;
30779
+ if (path2.parentPath.isAssignmentExpression({ left: path2.node })) return;
30780
+ if (path2.parentPath.isUpdateExpression({ argument: path2.node })) return;
30781
+ if (isDynamicPropertyAccess(path2.node, t4) && isStateRoot(path2.node.object)) {
30200
30782
  emitWarning(
30201
- path.node,
30783
+ path2.node,
30202
30784
  "FICT-H",
30203
30785
  "Dynamic property access widens dependency tracking",
30204
30786
  warn,
@@ -30249,14 +30831,17 @@ function createHIREntrypointVisitor(t4, options) {
30249
30831
  };
30250
30832
  return {
30251
30833
  Program: {
30252
- exit(path) {
30253
- const fileName = path.hub?.file?.opts?.filename || "<unknown>";
30254
- const comments = path.hub?.file?.ast?.comments || [];
30834
+ exit(path2) {
30835
+ const fileName = path2.hub?.file?.opts?.filename || "<unknown>";
30836
+ const comments = path2.hub?.file?.ast?.comments || [];
30255
30837
  const suppressions = parseSuppressions(comments);
30256
30838
  const dev = options.dev !== false;
30257
- const warn = dev ? createWarningDispatcher(options.onWarn, suppressions) : () => {
30839
+ const warn = createWarningDispatcher(options.onWarn, suppressions, options, dev);
30840
+ const optionsWithWarnings = {
30841
+ ...options,
30842
+ onWarn: warn,
30843
+ filename: fileName
30258
30844
  };
30259
- const optionsWithWarnings = dev ? { ...options, onWarn: warn } : { ...options, onWarn: void 0 };
30260
30845
  const isHookName2 = (name) => !!name && /^use[A-Z]/.test(name);
30261
30846
  const getFunctionName = (fnPath) => {
30262
30847
  return fnPath.isFunctionDeclaration() && fnPath.node.id ? fnPath.node.id.name : fnPath.isFunctionExpression() && fnPath.node.id ? fnPath.node.id.name : fnPath.parentPath.isVariableDeclarator() && t4.isIdentifier(fnPath.parentPath.node.id) && fnPath.parentPath.node.init === fnPath.node ? fnPath.parentPath.node.id.name : void 0;
@@ -30357,7 +30942,7 @@ function createHIREntrypointVisitor(t4, options) {
30357
30942
  };
30358
30943
  return checkNode(fn.body);
30359
30944
  };
30360
- path.traverse({
30945
+ path2.traverse({
30361
30946
  FunctionDeclaration(fnPath) {
30362
30947
  const name = fnPath.node.id?.name;
30363
30948
  if (!isComponentName2(name)) return;
@@ -30394,7 +30979,7 @@ function createHIREntrypointVisitor(t4, options) {
30394
30979
  const stateMacroNames = /* @__PURE__ */ new Set(["$state"]);
30395
30980
  const effectMacroNames = /* @__PURE__ */ new Set(["$effect"]);
30396
30981
  const memoMacroNames = /* @__PURE__ */ new Set(["$memo", "createMemo"]);
30397
- path.traverse({
30982
+ path2.traverse({
30398
30983
  ImportDeclaration(importPath) {
30399
30984
  if (importPath.node.source.value !== "fict" && importPath.node.source.value !== "fict/slim")
30400
30985
  return;
@@ -30414,7 +30999,7 @@ function createHIREntrypointVisitor(t4, options) {
30414
30999
  }
30415
31000
  }
30416
31001
  });
30417
- path.traverse({
31002
+ path2.traverse({
30418
31003
  JSXExpressionContainer(exprPath) {
30419
31004
  const expr = exprPath.node.expression;
30420
31005
  if (!t4.isCallExpression(expr)) return;
@@ -30459,7 +31044,7 @@ function createHIREntrypointVisitor(t4, options) {
30459
31044
  const stateVars = /* @__PURE__ */ new Set();
30460
31045
  const derivedVars = /* @__PURE__ */ new Set();
30461
31046
  const destructuredAliases = /* @__PURE__ */ new Set();
30462
- path.traverse({
31047
+ path2.traverse({
30463
31048
  VariableDeclarator(varPath) {
30464
31049
  const init = varPath.node.init;
30465
31050
  if (!init) return;
@@ -30708,7 +31293,7 @@ or extract the nested logic into a custom hook (useXxx).`
30708
31293
  return usesState;
30709
31294
  };
30710
31295
  debugLog("alias", "state vars", Array.from(stateVars));
30711
- path.traverse({
31296
+ path2.traverse({
30712
31297
  Function: {
30713
31298
  enter() {
30714
31299
  aliasStack.push(/* @__PURE__ */ new Set());
@@ -30766,7 +31351,7 @@ or extract the nested logic into a custom hook (useXxx).`
30766
31351
  }
30767
31352
  });
30768
31353
  if (derivedVars.size > 0) {
30769
- path.traverse({
31354
+ path2.traverse({
30770
31355
  AssignmentExpression(assignPath) {
30771
31356
  const { left } = assignPath.node;
30772
31357
  if (t4.isIdentifier(left) && derivedVars.has(left.name)) {
@@ -30787,7 +31372,7 @@ or extract the nested logic into a custom hook (useXxx).`
30787
31372
  });
30788
31373
  }
30789
31374
  if (destructuredAliases.size > 0) {
30790
- path.traverse({
31375
+ path2.traverse({
30791
31376
  AssignmentExpression(assignPath) {
30792
31377
  const { left } = assignPath.node;
30793
31378
  if (t4.isIdentifier(left) && destructuredAliases.has(left.name)) {
@@ -30815,10 +31400,11 @@ or extract the nested logic into a custom hook (useXxx).`
30815
31400
  }
30816
31401
  });
30817
31402
  }
30818
- if (dev) {
30819
- runWarningPass(path, stateVars, derivedVars, warn, fileName, t4);
31403
+ const shouldRunWarnings = dev || hasErrorEscalation(options);
31404
+ if (shouldRunWarnings) {
31405
+ runWarningPass(path2, stateVars, derivedVars, warn, fileName, t4);
30820
31406
  }
30821
- const fileAst = t4.file(path.node);
31407
+ const fileAst = t4.file(path2.node);
30822
31408
  const hir = buildHIR(
30823
31409
  fileAst,
30824
31410
  {
@@ -30833,19 +31419,20 @@ or extract the nested logic into a custom hook (useXxx).`
30833
31419
  );
30834
31420
  const optimized = optionsWithWarnings.optimize ? optimizeHIR(hir, {
30835
31421
  memoMacroNames,
30836
- inlineDerivedMemos: optionsWithWarnings.inlineDerivedMemos ?? true
31422
+ inlineDerivedMemos: optionsWithWarnings.inlineDerivedMemos ?? true,
31423
+ optimizeLevel: optionsWithWarnings.optimizeLevel ?? "safe"
30837
31424
  }) : hir;
30838
31425
  const lowered = lowerHIRWithRegions(optimized, t4, optionsWithWarnings, {
30839
31426
  state: stateMacroNames,
30840
31427
  effect: effectMacroNames,
30841
31428
  memo: memoMacroNames
30842
31429
  });
30843
- path.node.body = lowered.program.body;
30844
- path.node.directives = lowered.program.directives;
31430
+ path2.node.body = lowered.program.body;
31431
+ path2.node.directives = lowered.program.directives;
30845
31432
  if (!process.env.FICT_SKIP_SCOPE_CRAWL) {
30846
- path.scope.crawl();
31433
+ path2.scope.crawl();
30847
31434
  }
30848
- stripMacroImports(path, t4);
31435
+ stripMacroImports(path2, t4);
30849
31436
  }
30850
31437
  }
30851
31438
  };
@@ -30858,6 +31445,7 @@ var createFictPlugin = (0, import_helper_plugin_utils.declare)(
30858
31445
  ...options,
30859
31446
  fineGrainedDom: options.fineGrainedDom ?? true,
30860
31447
  optimize: options.optimize ?? true,
31448
+ optimizeLevel: options.optimizeLevel ?? "safe",
30861
31449
  inlineDerivedMemos: options.inlineDerivedMemos ?? true,
30862
31450
  dev: options.dev ?? (process.env.NODE_ENV !== "production" && process.env.NODE_ENV !== "test")
30863
31451
  };
@@ -30870,5 +31458,8 @@ var createFictPlugin = (0, import_helper_plugin_utils.declare)(
30870
31458
  var index_default = createFictPlugin;
30871
31459
  // Annotate the CommonJS export names for ESM import in node:
30872
31460
  0 && (module.exports = {
30873
- createFictPlugin
31461
+ clearModuleMetadata,
31462
+ createFictPlugin,
31463
+ resolveModuleMetadata,
31464
+ setModuleMetadata
30874
31465
  });