@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.js CHANGED
@@ -179,7 +179,7 @@ var require_generated = __commonJS({
179
179
  exports.isExpression = isExpression2;
180
180
  exports.isExpressionStatement = isExpressionStatement2;
181
181
  exports.isExpressionWrapper = isExpressionWrapper;
182
- exports.isFile = isFile;
182
+ exports.isFile = isFile2;
183
183
  exports.isFlow = isFlow;
184
184
  exports.isFlowBaseAnnotation = isFlowBaseAnnotation;
185
185
  exports.isFlowDeclaration = isFlowDeclaration;
@@ -489,7 +489,7 @@ var require_generated = __commonJS({
489
489
  if (node.type !== "ExpressionStatement") return false;
490
490
  return opts == null || (0, _shallowEqual.default)(node, opts);
491
491
  }
492
- function isFile(node, opts) {
492
+ function isFile2(node, opts) {
493
493
  if (!node) return false;
494
494
  if (node.type !== "File") return false;
495
495
  return opts == null || (0, _shallowEqual.default)(node, opts);
@@ -7322,7 +7322,7 @@ var require_lowercase = __commonJS({
7322
7322
  exports.restElement = restElement;
7323
7323
  exports.restProperty = RestProperty;
7324
7324
  exports.returnStatement = returnStatement2;
7325
- exports.sequenceExpression = sequenceExpression;
7325
+ exports.sequenceExpression = sequenceExpression2;
7326
7326
  exports.spreadElement = spreadElement;
7327
7327
  exports.spreadProperty = SpreadProperty;
7328
7328
  exports.staticBlock = staticBlock;
@@ -7876,7 +7876,7 @@ var require_lowercase = __commonJS({
7876
7876
  validate(defs.argument, node, "argument", argument, 1);
7877
7877
  return node;
7878
7878
  }
7879
- function sequenceExpression(expressions) {
7879
+ function sequenceExpression2(expressions) {
7880
7880
  const node = {
7881
7881
  type: "SequenceExpression",
7882
7882
  expressions
@@ -11970,7 +11970,7 @@ var require_cloneNode = __commonJS({
11970
11970
  Object.defineProperty(exports, "__esModule", {
11971
11971
  value: true
11972
11972
  });
11973
- exports.default = cloneNode;
11973
+ exports.default = cloneNode2;
11974
11974
  var _index = require_definitions();
11975
11975
  var _index2 = require_generated();
11976
11976
  var {
@@ -11990,7 +11990,7 @@ var require_cloneNode = __commonJS({
11990
11990
  }
11991
11991
  return cloneIfNode(obj, deep, withoutLoc, commentsCache);
11992
11992
  }
11993
- function cloneNode(node, deep = true, withoutLoc = false) {
11993
+ function cloneNode2(node, deep = true, withoutLoc = false) {
11994
11994
  return cloneNodeInternal(node, deep, withoutLoc, /* @__PURE__ */ new Map());
11995
11995
  }
11996
11996
  function cloneNodeInternal(node, deep = true, withoutLoc = false, commentsCache) {
@@ -14308,6 +14308,7 @@ function debugWarn(flag, message, data) {
14308
14308
  var t = __toESM(require_lib3(), 1);
14309
14309
  import { transformFromAstSync } from "@babel/core";
14310
14310
  import transformDestructuring from "@babel/plugin-transform-destructuring";
14311
+ import traverseModule from "@babel/traverse";
14311
14312
 
14312
14313
  // src/ir/hir.ts
14313
14314
  var HIRError = class extends Error {
@@ -14393,9 +14394,9 @@ function extractDependencyPath(expr) {
14393
14394
  }
14394
14395
  return void 0;
14395
14396
  }
14396
- function pathToString(path) {
14397
- let result = path.base;
14398
- for (const seg of path.segments) {
14397
+ function pathToString(path2) {
14398
+ let result = path2.base;
14399
+ for (const seg of path2.segments) {
14399
14400
  if (seg.optional) {
14400
14401
  result += "?.";
14401
14402
  } else {
@@ -14420,42 +14421,56 @@ var resolveDestructuringPlugin = () => {
14420
14421
  const mod = transformDestructuring;
14421
14422
  return mod?.default ?? mod;
14422
14423
  };
14423
- var createAssignmentDestructuringPlugin = () => {
14424
- const pluginFactory = resolveDestructuringPlugin();
14425
- if (typeof pluginFactory !== "function") {
14426
- throw new Error("Expected @babel/plugin-transform-destructuring to export a function");
14427
- }
14428
- const plugin = pluginFactory(
14429
- {
14430
- assertVersion() {
14431
- },
14432
- assumption() {
14433
- return void 0;
14434
- },
14435
- types: t
14436
- },
14437
- {}
14438
- );
14439
- return {
14440
- visitor: {
14441
- AssignmentExpression(path, state) {
14442
- if (!t.isObjectPattern(path.node.left) && !t.isArrayPattern(path.node.left)) return;
14443
- const visitor = plugin.visitor?.AssignmentExpression;
14444
- if (!visitor) return;
14445
- visitor.call(this, path, state);
14424
+ var resolveTraverse = () => {
14425
+ const mod = traverseModule;
14426
+ return mod?.default ?? mod;
14427
+ };
14428
+ var OBJECT_REST_HELPERS = /* @__PURE__ */ new Set(["_objectWithoutProperties", "_objectWithoutPropertiesLoose"]);
14429
+ var OBJECT_DESTRUCTURING_EMPTY_HELPER = "_objectDestructuringEmpty";
14430
+ var EXTENDS_HELPER = "_extends";
14431
+ var isSameIdentifier = (left, right) => {
14432
+ return t.isIdentifier(left) && t.isIdentifier(right) && left.name === right.name;
14433
+ };
14434
+ var rewriteObjectRestHelpers = (ast) => {
14435
+ const traverse = resolveTraverse();
14436
+ traverse(ast, {
14437
+ CallExpression(path2) {
14438
+ const { callee, arguments: args } = path2.node;
14439
+ if (t.isIdentifier(callee) && OBJECT_REST_HELPERS.has(callee.name)) {
14440
+ path2.node.callee = t.identifier("__fictPropsRest");
14441
+ return;
14442
+ }
14443
+ 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) {
14444
+ const [checkExpr, sourceExpr] = args[1].expressions;
14445
+ if (t.isCallExpression(checkExpr) && t.isIdentifier(checkExpr.callee) && checkExpr.callee.name === OBJECT_DESTRUCTURING_EMPTY_HELPER && checkExpr.arguments.length === 1) {
14446
+ const [checkArg] = checkExpr.arguments;
14447
+ if (checkArg && isSameIdentifier(checkArg, sourceExpr)) {
14448
+ const restCall = t.callExpression(t.identifier("__fictPropsRest"), [
14449
+ t.cloneNode(sourceExpr, true),
14450
+ t.arrayExpression([])
14451
+ ]);
14452
+ path2.replaceWith(t.sequenceExpression([checkExpr, restCall]));
14453
+ }
14454
+ }
14446
14455
  }
14447
14456
  }
14448
- };
14457
+ });
14449
14458
  };
14450
14459
  var expandDestructuringAssignments = (ast) => {
14460
+ const pluginFactory = resolveDestructuringPlugin();
14461
+ if (typeof pluginFactory !== "function") {
14462
+ throw new Error("Expected @babel/plugin-transform-destructuring to export a function");
14463
+ }
14451
14464
  const result = transformFromAstSync(ast, void 0, {
14452
14465
  configFile: false,
14453
14466
  babelrc: false,
14454
14467
  ast: true,
14455
14468
  code: false,
14456
- plugins: [createAssignmentDestructuringPlugin()]
14469
+ plugins: [pluginFactory]
14457
14470
  });
14458
- return result?.ast ?? ast;
14471
+ const expanded = result?.ast ?? ast;
14472
+ rewriteObjectRestHelpers(expanded);
14473
+ return expanded;
14459
14474
  };
14460
14475
  var reportUnsupportedExpression = (node, overrideMessage) => {
14461
14476
  const loc = getLoc(node);
@@ -16365,6 +16380,70 @@ function shouldMemoizeRegion(region) {
16365
16380
  return false;
16366
16381
  }
16367
16382
 
16383
+ // src/module-metadata.ts
16384
+ import path from "path";
16385
+ import { existsSync, statSync } from "fs";
16386
+ var globalMetadata = /* @__PURE__ */ new Map();
16387
+ var MODULE_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"];
16388
+ function normalizeFileName(fileName) {
16389
+ return path.resolve(fileName);
16390
+ }
16391
+ function getMetadataStore(options) {
16392
+ return options?.moduleMetadata ?? globalMetadata;
16393
+ }
16394
+ function isFile(pathName) {
16395
+ try {
16396
+ return statSync(pathName).isFile();
16397
+ } catch {
16398
+ return false;
16399
+ }
16400
+ }
16401
+ function resolveImportSource(source, importer, store) {
16402
+ if (!importer) return void 0;
16403
+ const isAbsolute = path.isAbsolute(source);
16404
+ if (!isAbsolute && !source.startsWith(".")) return void 0;
16405
+ const base = isAbsolute ? source : path.resolve(path.dirname(importer), source);
16406
+ const normalized = normalizeFileName(base);
16407
+ if (store.has(normalized)) return normalized;
16408
+ if (existsSync(normalized) && isFile(normalized)) return normalized;
16409
+ const ext = path.extname(normalized);
16410
+ if (!ext) {
16411
+ for (const suffix of MODULE_EXTENSIONS) {
16412
+ const candidate = `${normalized}${suffix}`;
16413
+ if (store.has(candidate)) return candidate;
16414
+ if (existsSync(candidate) && isFile(candidate)) return candidate;
16415
+ }
16416
+ }
16417
+ for (const suffix of MODULE_EXTENSIONS) {
16418
+ const candidate = path.join(normalized, `index${suffix}`);
16419
+ if (store.has(candidate)) return candidate;
16420
+ if (existsSync(candidate) && isFile(candidate)) return candidate;
16421
+ }
16422
+ return void 0;
16423
+ }
16424
+ function resolveModuleMetadata(source, importer, options) {
16425
+ if (options?.resolveModuleMetadata) {
16426
+ const resolved = options.resolveModuleMetadata(source, importer);
16427
+ if (resolved) return resolved;
16428
+ }
16429
+ const store = getMetadataStore(options);
16430
+ const resolvedKey = resolveImportSource(source, importer, store);
16431
+ if (resolvedKey) {
16432
+ return store.get(resolvedKey);
16433
+ }
16434
+ if (store.has(source)) return store.get(source);
16435
+ return void 0;
16436
+ }
16437
+ function setModuleMetadata(fileName, metadata, options) {
16438
+ if (!fileName) return;
16439
+ const store = getMetadataStore(options);
16440
+ store.set(normalizeFileName(fileName), metadata);
16441
+ }
16442
+ function clearModuleMetadata(options) {
16443
+ const store = getMetadataStore(options);
16444
+ store.clear();
16445
+ }
16446
+
16368
16447
  // src/validation.ts
16369
16448
  var DiagnosticMessages = {
16370
16449
  ["FICT-P001" /* FICT_P001 */]: "Props destructuring falls back to non-reactive binding.",
@@ -16557,6 +16636,23 @@ function buildPropsPlan(attributes, children, ctx, helpers) {
16557
16636
  }
16558
16637
  return false;
16559
16638
  };
16639
+ const getBaseIdentifier2 = (expr) => {
16640
+ if (expr.kind === "Identifier") return expr.name;
16641
+ if (expr.kind === "MemberExpression" || expr.kind === "OptionalMemberExpression") {
16642
+ return getBaseIdentifier2(expr.object);
16643
+ }
16644
+ return null;
16645
+ };
16646
+ const isDynamicStoreMember = (expr) => {
16647
+ if (expr.kind !== "MemberExpression" && expr.kind !== "OptionalMemberExpression") return false;
16648
+ if (!expr.computed) return false;
16649
+ if (expr.property.kind === "Literal" && (typeof expr.property.value === "string" || typeof expr.property.value === "number")) {
16650
+ return false;
16651
+ }
16652
+ const base = getBaseIdentifier2(expr.object);
16653
+ if (!base) return false;
16654
+ return ctx.storeVars?.has(helpers.deSSAVarName(base)) ?? false;
16655
+ };
16560
16656
  const flushBucket = () => {
16561
16657
  if (bucket.length === 0) return;
16562
16658
  segments.push({ kind: "object", properties: bucket });
@@ -16628,13 +16724,15 @@ function buildPropsPlan(attributes, children, ctx, helpers) {
16628
16724
  ctx
16629
16725
  ) : null;
16630
16726
  const useMemoProp = usesTracked && trackedExpr && t4.isExpression(trackedExpr) && !t4.isIdentifier(trackedExpr) && !t4.isMemberExpression(trackedExpr) && !t4.isLiteral(trackedExpr);
16727
+ const forceMemoProp = usesTracked && isDynamicStoreMember(attr.value);
16728
+ const shouldMemoProp = useMemoProp || forceMemoProp;
16631
16729
  const valueExpr = !isFunctionLike && isAccessorBase && baseIdent ? (() => {
16632
16730
  ctx.helpersUsed.add("propGetter");
16633
16731
  return t4.callExpression(t4.identifier(RUNTIME_ALIASES.propGetter), [
16634
16732
  t4.arrowFunctionExpression([], t4.callExpression(t4.identifier(baseIdent), []))
16635
16733
  ]);
16636
16734
  })() : usesTracked && t4.isExpression(lowered) ? (() => {
16637
- if (useMemoProp) {
16735
+ if (shouldMemoProp) {
16638
16736
  ctx.helpersUsed.add("prop");
16639
16737
  return t4.callExpression(t4.identifier(RUNTIME_ALIASES.prop), [
16640
16738
  t4.arrowFunctionExpression([], trackedExpr ?? lowered)
@@ -16827,7 +16925,13 @@ function rewriteExprWithMap(expr, rewrites) {
16827
16925
  return {
16828
16926
  ...expr,
16829
16927
  object: rewriteExprWithMap(expr.object, rewrites),
16830
- property: rewriteExprWithMap(expr.property, rewrites)
16928
+ property: expr.computed ? rewriteExprWithMap(expr.property, rewrites) : expr.property
16929
+ };
16930
+ case "OptionalMemberExpression":
16931
+ return {
16932
+ ...expr,
16933
+ object: rewriteExprWithMap(expr.object, rewrites),
16934
+ property: expr.computed ? rewriteExprWithMap(expr.property, rewrites) : expr.property
16831
16935
  };
16832
16936
  case "BinaryExpression":
16833
16937
  case "LogicalExpression":
@@ -16850,11 +16954,12 @@ function rewriteExprWithMap(expr, rewrites) {
16850
16954
  case "ObjectExpression":
16851
16955
  return {
16852
16956
  ...expr,
16853
- properties: expr.properties.map((p) => ({
16854
- ...p,
16855
- key: rewriteExprWithMap(p.key, rewrites),
16856
- value: rewriteExprWithMap(p.value, rewrites)
16857
- }))
16957
+ properties: expr.properties.map((p) => {
16958
+ if (p.kind === "SpreadElement") {
16959
+ return { ...p, argument: rewriteExprWithMap(p.argument, rewrites) };
16960
+ }
16961
+ return { ...p, value: rewriteExprWithMap(p.value, rewrites) };
16962
+ })
16858
16963
  };
16859
16964
  case "ImportExpression":
16860
16965
  return {
@@ -16968,7 +17073,17 @@ function toSSA(fn) {
16968
17073
  arguments: expr.arguments.map((a) => renameExpr(a))
16969
17074
  };
16970
17075
  case "MemberExpression":
16971
- return { ...expr, object: renameExpr(expr.object), property: renameExpr(expr.property) };
17076
+ return {
17077
+ ...expr,
17078
+ object: renameExpr(expr.object),
17079
+ property: expr.computed ? renameExpr(expr.property) : expr.property
17080
+ };
17081
+ case "OptionalMemberExpression":
17082
+ return {
17083
+ ...expr,
17084
+ object: renameExpr(expr.object),
17085
+ property: expr.computed ? renameExpr(expr.property) : expr.property
17086
+ };
16972
17087
  case "BinaryExpression":
16973
17088
  case "LogicalExpression":
16974
17089
  return { ...expr, left: renameExpr(expr.left), right: renameExpr(expr.right) };
@@ -16986,11 +17101,12 @@ function toSSA(fn) {
16986
17101
  case "ObjectExpression":
16987
17102
  return {
16988
17103
  ...expr,
16989
- properties: expr.properties.map((p) => ({
16990
- ...p,
16991
- key: renameExpr(p.key),
16992
- value: renameExpr(p.value)
16993
- }))
17104
+ properties: expr.properties.map((p) => {
17105
+ if (p.kind === "SpreadElement") {
17106
+ return { ...p, argument: renameExpr(p.argument) };
17107
+ }
17108
+ return { ...p, value: renameExpr(p.value) };
17109
+ })
16994
17110
  };
16995
17111
  default:
16996
17112
  return expr;
@@ -17485,8 +17601,8 @@ function mergeOverlappingScopes(scopes, _byName) {
17485
17601
  scope.blocks.forEach((b) => merged.blocks.add(b));
17486
17602
  scope.dependencies.forEach((d) => merged.dependencies.add(d));
17487
17603
  for (const [base, paths] of scope.dependencyPaths) {
17488
- for (const path of paths) {
17489
- addPath(merged.dependencyPaths, base, path);
17604
+ for (const path2 of paths) {
17605
+ addPath(merged.dependencyPaths, base, path2);
17490
17606
  }
17491
17607
  }
17492
17608
  merged.hasExternalEffect = merged.hasExternalEffect || scope.hasExternalEffect;
@@ -17580,12 +17696,12 @@ function collectExprReads(expr, into, paths, bound = /* @__PURE__ */ new Set(),
17580
17696
  if (bound.has(baseName(expr.name))) return;
17581
17697
  into.add(expr.name);
17582
17698
  if (paths) {
17583
- const path = {
17699
+ const path2 = {
17584
17700
  base: expr.name,
17585
17701
  segments: [],
17586
17702
  hasOptional: false
17587
17703
  };
17588
- addPath(paths, expr.name, path);
17704
+ addPath(paths, expr.name, path2);
17589
17705
  }
17590
17706
  return;
17591
17707
  case "CallExpression": {
@@ -17741,11 +17857,11 @@ function collectExprReads(expr, into, paths, bound = /* @__PURE__ */ new Set(),
17741
17857
  return;
17742
17858
  }
17743
17859
  }
17744
- function addPath(paths, base, path) {
17860
+ function addPath(paths, base, path2) {
17745
17861
  const existing = paths.get(base) ?? [];
17746
- const pathStr = pathToString(path);
17862
+ const pathStr = pathToString(path2);
17747
17863
  if (!existing.some((p) => pathToString(p) === pathStr)) {
17748
- existing.push(path);
17864
+ existing.push(path2);
17749
17865
  paths.set(base, existing);
17750
17866
  }
17751
17867
  }
@@ -17764,11 +17880,11 @@ function analyzeOptionalChainDependencies(scope) {
17764
17880
  } else {
17765
17881
  let hasRequiredPath = false;
17766
17882
  let hasOptionalOnlyPath = false;
17767
- for (const path of paths) {
17768
- if (!path.hasOptional) {
17883
+ for (const path2 of paths) {
17884
+ if (!path2.hasOptional) {
17769
17885
  hasRequiredPath = true;
17770
17886
  } else {
17771
- const firstOptionalIndex = path.segments.findIndex((s) => s.optional);
17887
+ const firstOptionalIndex = path2.segments.findIndex((s) => s.optional);
17772
17888
  if (firstOptionalIndex === 0) {
17773
17889
  hasOptionalOnlyPath = true;
17774
17890
  } else if (firstOptionalIndex > 0) {
@@ -18519,12 +18635,23 @@ function createPropsShape() {
18519
18635
  };
18520
18636
  }
18521
18637
  function cloneKeyContext(ctx) {
18522
- return new Map(ctx);
18638
+ const cloneMap = (map) => {
18639
+ const next = /* @__PURE__ */ new Map();
18640
+ for (const [key, value] of map.entries()) {
18641
+ next.set(key, new Set(value));
18642
+ }
18643
+ return next;
18644
+ };
18645
+ return {
18646
+ values: cloneMap(ctx.values),
18647
+ keySets: cloneMap(ctx.keySets)
18648
+ };
18523
18649
  }
18524
18650
  function clearPatternBindings(pattern, ctx) {
18525
18651
  if (!pattern || typeof pattern !== "object") return;
18526
18652
  if (t2.isIdentifier(pattern)) {
18527
- ctx.delete(pattern.name);
18653
+ ctx.values.delete(pattern.name);
18654
+ ctx.keySets.delete(pattern.name);
18528
18655
  return;
18529
18656
  }
18530
18657
  if (t2.isRestElement(pattern)) {
@@ -18551,19 +18678,106 @@ function clearPatternBindings(pattern, ctx) {
18551
18678
  }
18552
18679
  }
18553
18680
  }
18554
- function resolveNarrowedKey(expr, ctx) {
18681
+ function resolveNarrowedKeys(expr, ctx) {
18555
18682
  if (expr.kind === "Literal") {
18556
18683
  if (typeof expr.value === "string" || typeof expr.value === "number") {
18557
- return expr.value;
18684
+ return /* @__PURE__ */ new Set([expr.value]);
18558
18685
  }
18559
18686
  return null;
18560
18687
  }
18561
18688
  if (expr.kind === "Identifier") {
18562
- return ctx.get(expr.name) ?? null;
18689
+ const value = ctx.values.get(expr.name);
18690
+ return value ? new Set(value) : null;
18691
+ }
18692
+ if (expr.kind === "ConditionalExpression") {
18693
+ const consequent = resolveNarrowedKeys(expr.consequent, ctx);
18694
+ const alternate = resolveNarrowedKeys(expr.alternate, ctx);
18695
+ if (consequent && alternate) {
18696
+ return /* @__PURE__ */ new Set([...consequent, ...alternate]);
18697
+ }
18698
+ return null;
18699
+ }
18700
+ if (expr.kind === "SequenceExpression" && expr.expressions.length > 0) {
18701
+ const last = expr.expressions[expr.expressions.length - 1];
18702
+ return resolveNarrowedKeys(last, ctx);
18703
+ }
18704
+ if (expr.kind === "MemberExpression" || expr.kind === "OptionalMemberExpression") {
18705
+ if (expr.computed && expr.object.kind === "Identifier") {
18706
+ const keySet = ctx.keySets.get(expr.object.name);
18707
+ if (keySet && keySet.size > 0) {
18708
+ return new Set(keySet);
18709
+ }
18710
+ }
18711
+ }
18712
+ return null;
18713
+ }
18714
+ function resolveKeySet(expr, ctx) {
18715
+ if (expr.kind === "Identifier") {
18716
+ const set = ctx.keySets.get(expr.name);
18717
+ return set ? new Set(set) : null;
18718
+ }
18719
+ if (expr.kind === "ArrayExpression") {
18720
+ const values = [];
18721
+ for (const el of expr.elements) {
18722
+ if (!el) return null;
18723
+ if (el.kind !== "Literal") return null;
18724
+ if (typeof el.value !== "string" && typeof el.value !== "number") return null;
18725
+ values.push(el.value);
18726
+ }
18727
+ return values.length > 0 ? new Set(values) : null;
18728
+ }
18729
+ if (expr.kind === "CallExpression") {
18730
+ if (expr.callee.kind === "MemberExpression") {
18731
+ const object = expr.callee.object;
18732
+ const property = expr.callee.property;
18733
+ if (object.kind === "Identifier" && object.name === "Object" && !expr.callee.computed && property.kind === "Identifier" && property.name === "keys" && expr.arguments.length === 1) {
18734
+ const arg = expr.arguments[0];
18735
+ if (arg.kind === "ObjectExpression") {
18736
+ const values = [];
18737
+ for (const prop of arg.properties) {
18738
+ if (prop.kind !== "Property") return null;
18739
+ if (prop.key.kind === "Identifier") {
18740
+ values.push(prop.key.name);
18741
+ } else if (prop.key.kind === "Literal") {
18742
+ if (typeof prop.key.value !== "string" && typeof prop.key.value !== "number") {
18743
+ return null;
18744
+ }
18745
+ values.push(prop.key.value);
18746
+ } else {
18747
+ return null;
18748
+ }
18749
+ }
18750
+ return values.length > 0 ? new Set(values) : null;
18751
+ }
18752
+ }
18753
+ }
18754
+ }
18755
+ if (expr.kind === "ConditionalExpression") {
18756
+ const consequent = resolveKeySet(expr.consequent, ctx);
18757
+ const alternate = resolveKeySet(expr.alternate, ctx);
18758
+ if (consequent && alternate) {
18759
+ return /* @__PURE__ */ new Set([...consequent, ...alternate]);
18760
+ }
18761
+ return null;
18762
+ }
18763
+ if (expr.kind === "SequenceExpression" && expr.expressions.length > 0) {
18764
+ const last = expr.expressions[expr.expressions.length - 1];
18765
+ return resolveKeySet(last, ctx);
18563
18766
  }
18564
18767
  return null;
18565
18768
  }
18566
18769
  function extractEqualityNarrowing(expr) {
18770
+ if (expr.kind === "LogicalExpression" && expr.operator === "||") {
18771
+ const left = extractEqualityNarrowing(expr.left);
18772
+ const right = extractEqualityNarrowing(expr.right);
18773
+ if (left && right && left.kind === "eq" && right.kind === "eq" && left.name === right.name) {
18774
+ return {
18775
+ name: left.name,
18776
+ values: /* @__PURE__ */ new Set([...left.values, ...right.values]),
18777
+ kind: "eq"
18778
+ };
18779
+ }
18780
+ }
18567
18781
  if (expr.kind !== "BinaryExpression") return null;
18568
18782
  const isEq = expr.operator === "===";
18569
18783
  const isNeq = expr.operator === "!==";
@@ -18578,17 +18792,55 @@ function extractEqualityNarrowing(expr) {
18578
18792
  if (expr.left.kind === "Identifier") {
18579
18793
  const value = literalValue(expr.right);
18580
18794
  if (value !== null) {
18581
- return { name: expr.left.name, value, kind: isEq ? "eq" : "neq" };
18795
+ return { name: expr.left.name, values: /* @__PURE__ */ new Set([value]), kind: isEq ? "eq" : "neq" };
18582
18796
  }
18583
18797
  }
18584
18798
  if (expr.right.kind === "Identifier") {
18585
18799
  const value = literalValue(expr.left);
18586
18800
  if (value !== null) {
18587
- return { name: expr.right.name, value, kind: isEq ? "eq" : "neq" };
18801
+ return { name: expr.right.name, values: /* @__PURE__ */ new Set([value]), kind: isEq ? "eq" : "neq" };
18588
18802
  }
18589
18803
  }
18590
18804
  return null;
18591
18805
  }
18806
+ function applyNarrowing(ctx, name, values) {
18807
+ const existing = ctx.values.get(name);
18808
+ if (!existing) {
18809
+ ctx.values.set(name, new Set(values));
18810
+ return;
18811
+ }
18812
+ const intersection = /* @__PURE__ */ new Set();
18813
+ for (const value of existing) {
18814
+ if (values.has(value)) intersection.add(value);
18815
+ }
18816
+ if (intersection.size > 0) {
18817
+ ctx.values.set(name, intersection);
18818
+ } else {
18819
+ ctx.values.delete(name);
18820
+ }
18821
+ }
18822
+ function applyKeyAssignment(ctx, name, expr) {
18823
+ ctx.values.delete(name);
18824
+ ctx.keySets.delete(name);
18825
+ let assignedKeys = null;
18826
+ let keySet = null;
18827
+ if (expr.kind === "Identifier") {
18828
+ assignedKeys = resolveNarrowedKeys(expr, ctx);
18829
+ keySet = resolveKeySet(expr, ctx);
18830
+ if (ctx.keySets.has(expr.name)) {
18831
+ ctx.keySets.delete(expr.name);
18832
+ }
18833
+ } else {
18834
+ assignedKeys = resolveNarrowedKeys(expr, ctx);
18835
+ keySet = resolveKeySet(expr, ctx);
18836
+ }
18837
+ if (assignedKeys && assignedKeys.size > 0) {
18838
+ ctx.values.set(name, new Set(assignedKeys));
18839
+ }
18840
+ if (keySet && keySet.size > 0) {
18841
+ ctx.keySets.set(name, new Set(keySet));
18842
+ }
18843
+ }
18592
18844
  function mergeShapes(a, b) {
18593
18845
  return {
18594
18846
  knownKeys: /* @__PURE__ */ new Set([...a.knownKeys, ...b.knownKeys]),
@@ -18610,7 +18862,7 @@ function analyzeObjectShapes(fn) {
18610
18862
  shapes.set(param.name, createUnknownShape({ kind: "param", name: param.name }));
18611
18863
  }
18612
18864
  }
18613
- const baseCtx = /* @__PURE__ */ new Map();
18865
+ const baseCtx = { values: /* @__PURE__ */ new Map(), keySets: /* @__PURE__ */ new Map() };
18614
18866
  let structured = null;
18615
18867
  try {
18616
18868
  structured = structurizeCFG(fn, {
@@ -18697,9 +18949,9 @@ function analyzeStructuredNode(node, shapes, propertyReads, ctx) {
18697
18949
  const alternateCtx = cloneKeyContext(ctx);
18698
18950
  if (narrowing) {
18699
18951
  if (narrowing.kind === "eq") {
18700
- consequentCtx.set(narrowing.name, narrowing.value);
18952
+ applyNarrowing(consequentCtx, narrowing.name, narrowing.values);
18701
18953
  } else {
18702
- alternateCtx.set(narrowing.name, narrowing.value);
18954
+ applyNarrowing(alternateCtx, narrowing.name, narrowing.values);
18703
18955
  }
18704
18956
  }
18705
18957
  analyzeStructuredNode(node.consequent, shapes, propertyReads, consequentCtx);
@@ -18714,7 +18966,7 @@ function analyzeStructuredNode(node, shapes, propertyReads, ctx) {
18714
18966
  for (const caseNode of node.cases) {
18715
18967
  const caseCtx = cloneKeyContext(ctx);
18716
18968
  if (discriminant && caseNode.test?.kind === "Literal" && (typeof caseNode.test.value === "string" || typeof caseNode.test.value === "number")) {
18717
- caseCtx.set(discriminant, caseNode.test.value);
18969
+ applyNarrowing(caseCtx, discriminant, /* @__PURE__ */ new Set([caseNode.test.value]));
18718
18970
  }
18719
18971
  analyzeStructuredNode(caseNode.body, shapes, propertyReads, caseCtx);
18720
18972
  }
@@ -18745,7 +18997,8 @@ function analyzeStructuredNode(node, shapes, propertyReads, ctx) {
18745
18997
  analyzeExpression(node.iterable, shapes, propertyReads, ctx);
18746
18998
  {
18747
18999
  const bodyCtx = cloneKeyContext(ctx);
18748
- bodyCtx.delete(node.variable);
19000
+ bodyCtx.values.delete(node.variable);
19001
+ bodyCtx.keySets.delete(node.variable);
18749
19002
  if (node.pattern) {
18750
19003
  clearPatternBindings(node.pattern, bodyCtx);
18751
19004
  }
@@ -18756,7 +19009,8 @@ function analyzeStructuredNode(node, shapes, propertyReads, ctx) {
18756
19009
  analyzeExpression(node.object, shapes, propertyReads, ctx);
18757
19010
  {
18758
19011
  const bodyCtx = cloneKeyContext(ctx);
18759
- bodyCtx.delete(node.variable);
19012
+ bodyCtx.values.delete(node.variable);
19013
+ bodyCtx.keySets.delete(node.variable);
18760
19014
  if (node.pattern) {
18761
19015
  clearPatternBindings(node.pattern, bodyCtx);
18762
19016
  }
@@ -18768,7 +19022,8 @@ function analyzeStructuredNode(node, shapes, propertyReads, ctx) {
18768
19022
  if (node.handler) {
18769
19023
  const handlerCtx = cloneKeyContext(ctx);
18770
19024
  if (node.handler.param) {
18771
- handlerCtx.delete(node.handler.param);
19025
+ handlerCtx.values.delete(node.handler.param);
19026
+ handlerCtx.keySets.delete(node.handler.param);
18772
19027
  }
18773
19028
  analyzeStructuredNode(node.handler.body, shapes, propertyReads, handlerCtx);
18774
19029
  }
@@ -18794,9 +19049,7 @@ function analyzeStructuredNode(node, shapes, propertyReads, ctx) {
18794
19049
  }
18795
19050
  function analyzeInstruction(instr, shapes, propertyReads, ctx) {
18796
19051
  if (instr.kind === "Assign") {
18797
- if (ctx.has(instr.target.name)) {
18798
- ctx.delete(instr.target.name);
18799
- }
19052
+ applyKeyAssignment(ctx, instr.target.name, instr.value);
18800
19053
  const valueShape = analyzeExpression(instr.value, shapes, propertyReads, ctx);
18801
19054
  if (valueShape) {
18802
19055
  const existing = shapes.get(instr.target.name);
@@ -18853,12 +19106,14 @@ function analyzeExpression(expr, shapes, propertyReads, ctx) {
18853
19106
  const reads = propertyReads.get(base) ?? /* @__PURE__ */ new Set();
18854
19107
  const baseShape = shapes.get(base);
18855
19108
  if (directMember.computed) {
18856
- const resolved = resolveNarrowedKey(directMember.property, ctx);
18857
- if (resolved !== null) {
18858
- const key = String(resolved);
18859
- reads.add(key);
18860
- if (baseShape) {
18861
- baseShape.knownKeys.add(key);
19109
+ const resolved = resolveNarrowedKeys(directMember.property, ctx);
19110
+ if (resolved && resolved.size > 0) {
19111
+ for (const value of resolved) {
19112
+ const key = String(value);
19113
+ reads.add(key);
19114
+ if (baseShape) {
19115
+ baseShape.knownKeys.add(key);
19116
+ }
18862
19117
  }
18863
19118
  } else if (baseShape) {
18864
19119
  baseShape.dynamicAccess = true;
@@ -18880,6 +19135,34 @@ function analyzeExpression(expr, shapes, propertyReads, ctx) {
18880
19135
  return null;
18881
19136
  }
18882
19137
  case "CallExpression": {
19138
+ if (expr.callee.kind === "MemberExpression") {
19139
+ if (expr.callee.object.kind === "Identifier") {
19140
+ const baseName2 = expr.callee.object.name;
19141
+ 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;
19142
+ if (propName && ctx.keySets.has(baseName2) && [
19143
+ "push",
19144
+ "pop",
19145
+ "shift",
19146
+ "unshift",
19147
+ "splice",
19148
+ "sort",
19149
+ "reverse",
19150
+ "copyWithin",
19151
+ "fill"
19152
+ ].includes(propName)) {
19153
+ ctx.keySets.delete(baseName2);
19154
+ }
19155
+ }
19156
+ }
19157
+ for (const arg of expr.arguments) {
19158
+ if (arg.kind === "Identifier" && ctx.keySets.has(arg.name)) {
19159
+ ctx.keySets.delete(arg.name);
19160
+ } else if (arg.kind === "SpreadElement" && arg.argument.kind === "Identifier") {
19161
+ if (ctx.keySets.has(arg.argument.name)) {
19162
+ ctx.keySets.delete(arg.argument.name);
19163
+ }
19164
+ }
19165
+ }
18883
19166
  for (const arg of expr.arguments) {
18884
19167
  markEscaping(arg, shapes);
18885
19168
  }
@@ -18931,9 +19214,7 @@ function analyzeExpression(expr, shapes, propertyReads, ctx) {
18931
19214
  }
18932
19215
  case "AssignmentExpression": {
18933
19216
  if (expr.left.kind === "Identifier") {
18934
- if (ctx.has(expr.left.name)) {
18935
- ctx.delete(expr.left.name);
18936
- }
19217
+ applyKeyAssignment(ctx, expr.left.name, expr.right);
18937
19218
  }
18938
19219
  if (expr.left.kind === "MemberExpression") {
18939
19220
  const base = getBaseIdentifier(expr.left.object);
@@ -18945,14 +19226,19 @@ function analyzeExpression(expr, shapes, propertyReads, ctx) {
18945
19226
  } else if (expr.left.property.kind === "Literal" && typeof expr.left.property.value === "string") {
18946
19227
  shape.mutableKeys.add(expr.left.property.value);
18947
19228
  } else {
18948
- const resolved = resolveNarrowedKey(expr.left.property, ctx);
18949
- if (resolved !== null) {
18950
- shape.mutableKeys.add(String(resolved));
19229
+ const resolved = resolveNarrowedKeys(expr.left.property, ctx);
19230
+ if (resolved && resolved.size > 0) {
19231
+ for (const value of resolved) {
19232
+ shape.mutableKeys.add(String(value));
19233
+ }
18951
19234
  } else {
18952
19235
  shape.dynamicAccess = true;
18953
19236
  }
18954
19237
  }
18955
19238
  }
19239
+ if (ctx.keySets.has(base)) {
19240
+ ctx.keySets.delete(base);
19241
+ }
18956
19242
  }
18957
19243
  }
18958
19244
  analyzeExpression(expr.right, shapes, propertyReads, ctx);
@@ -18960,8 +19246,13 @@ function analyzeExpression(expr, shapes, propertyReads, ctx) {
18960
19246
  }
18961
19247
  case "UpdateExpression": {
18962
19248
  if (expr.argument.kind === "Identifier") {
18963
- if (ctx.has(expr.argument.name)) {
18964
- ctx.delete(expr.argument.name);
19249
+ ctx.values.delete(expr.argument.name);
19250
+ ctx.keySets.delete(expr.argument.name);
19251
+ }
19252
+ if (expr.argument.kind === "MemberExpression") {
19253
+ const base = getBaseIdentifier(expr.argument.object);
19254
+ if (base) {
19255
+ ctx.keySets.delete(base);
18965
19256
  }
18966
19257
  }
18967
19258
  analyzeExpression(expr.argument, shapes, propertyReads, ctx);
@@ -19393,7 +19684,11 @@ function expressionUsesTracked(expr, ctx) {
19393
19684
  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);
19394
19685
  case "MemberExpression":
19395
19686
  case "OptionalMemberExpression":
19396
- return expressionUsesTracked(expr.object, ctx);
19687
+ if (expressionUsesTracked(expr.object, ctx)) return true;
19688
+ if (expr.computed && expr.property.kind !== "Literal") {
19689
+ return expressionUsesTracked(expr.property, ctx);
19690
+ }
19691
+ return false;
19397
19692
  case "CallExpression":
19398
19693
  case "OptionalCallExpression":
19399
19694
  if (expressionUsesTracked(expr.callee, ctx)) return true;
@@ -21201,6 +21496,24 @@ function setNodeLoc(node, loc) {
21201
21496
  node.loc = cloneLoc(loc) ?? null;
21202
21497
  return node;
21203
21498
  }
21499
+ function serializeHookReturnInfo(info) {
21500
+ const objectProps = info.objectProps ? Object.fromEntries(info.objectProps.entries()) : void 0;
21501
+ const arrayProps = info.arrayProps ? Object.fromEntries(Array.from(info.arrayProps.entries()).map(([k, v]) => [String(k), v])) : void 0;
21502
+ return {
21503
+ objectProps,
21504
+ arrayProps,
21505
+ directAccessor: info.directAccessor
21506
+ };
21507
+ }
21508
+ function deserializeHookReturnInfo(info) {
21509
+ const objectProps = info.objectProps ? new Map(Object.entries(info.objectProps)) : void 0;
21510
+ const arrayProps = info.arrayProps ? new Map(Object.entries(info.arrayProps).map(([k, v]) => [Number.parseInt(k, 10), v])) : void 0;
21511
+ return {
21512
+ objectProps,
21513
+ arrayProps,
21514
+ directAccessor: info.directAccessor
21515
+ };
21516
+ }
21204
21517
  function propagateHookResultAlias(targetBase, value, ctx) {
21205
21518
  const mapSource = (source) => {
21206
21519
  const hookName = ctx.hookResultVarMap?.get(source);
@@ -21224,6 +21537,15 @@ function propagateHookResultAlias(targetBase, value, ctx) {
21224
21537
  mapSource(deSSAVarName(firstArg.name));
21225
21538
  }
21226
21539
  }
21540
+ if (value.kind === "SequenceExpression" && value.expressions.length > 0) {
21541
+ const last = value.expressions[value.expressions.length - 1];
21542
+ if (last && last.kind === "CallExpression" && last.callee.kind === "Identifier" && last.callee.name === "__fictPropsRest") {
21543
+ const firstArg = last.arguments[0];
21544
+ if (firstArg && firstArg.kind === "Identifier") {
21545
+ mapSource(deSSAVarName(firstArg.name));
21546
+ }
21547
+ }
21548
+ }
21227
21549
  }
21228
21550
  function applyRegionToContext(ctx, region) {
21229
21551
  const prevRegion = ctx.currentRegion;
@@ -21530,6 +21852,7 @@ function createCodegenContext(t4) {
21530
21852
  aliasVars: /* @__PURE__ */ new Set(),
21531
21853
  externalTracked: /* @__PURE__ */ new Set(),
21532
21854
  storeVars: /* @__PURE__ */ new Set(),
21855
+ importedNamespaces: /* @__PURE__ */ new Map(),
21533
21856
  signalVars: /* @__PURE__ */ new Set(),
21534
21857
  functionVars: /* @__PURE__ */ new Set(),
21535
21858
  memoVars: /* @__PURE__ */ new Set(),
@@ -22477,6 +22800,12 @@ function extractKeyFromMapCallback(callback) {
22477
22800
  if (!jsx) return void 0;
22478
22801
  return extractKeyFromAttributes(jsx.attributes);
22479
22802
  }
22803
+ function buildOutputParams(fn, t4) {
22804
+ if (fn.rawParams && fn.rawParams.length > 0) {
22805
+ return fn.rawParams.map((param) => t4.cloneNode(param, true));
22806
+ }
22807
+ return fn.params.map((p) => t4.identifier(deSSAVarName(p.name)));
22808
+ }
22480
22809
  function lowerTrackedExpression(expr, ctx) {
22481
22810
  const regionOverride = ctx.inReturn && ctx.currentFnIsHook ? null : ctx.currentRegion ?? (ctx.trackedVars.size ? {
22482
22811
  id: -1,
@@ -22770,6 +23099,171 @@ function collectRuntimeImportNames(body, t4) {
22770
23099
  }
22771
23100
  return imported;
22772
23101
  }
23102
+ function addImportedReactiveBinding(name, kind, ctx) {
23103
+ const base = deSSAVarName(name);
23104
+ if (kind === "signal") {
23105
+ ctx.signalVars?.add(base);
23106
+ } else if (kind === "store") {
23107
+ ctx.storeVars?.add(base);
23108
+ } else if (kind === "memo") {
23109
+ ctx.memoVars?.add(base);
23110
+ }
23111
+ ctx.trackedVars.add(base);
23112
+ }
23113
+ function applyImportedReactiveMetadata(body, ctx, t4, options) {
23114
+ const importer = options?.filename;
23115
+ const namespaces = /* @__PURE__ */ new Map();
23116
+ for (const stmt of body) {
23117
+ if (!t4.isImportDeclaration(stmt)) continue;
23118
+ const meta = resolveModuleMetadata(stmt.source.value, importer, options);
23119
+ if (!meta) continue;
23120
+ for (const spec of stmt.specifiers) {
23121
+ if (t4.isImportSpecifier(spec)) {
23122
+ const importedName = t4.isIdentifier(spec.imported) ? spec.imported.name : String(spec.imported.value);
23123
+ const localName = spec.local.name;
23124
+ const kind = meta.exports[importedName];
23125
+ if (kind) {
23126
+ addImportedReactiveBinding(localName, kind, ctx);
23127
+ }
23128
+ const hookInfo = meta.hooks?.[importedName];
23129
+ if (hookInfo) {
23130
+ ctx.hookReturnInfo = ctx.hookReturnInfo ?? /* @__PURE__ */ new Map();
23131
+ ctx.hookReturnInfo.set(localName, deserializeHookReturnInfo(hookInfo));
23132
+ }
23133
+ continue;
23134
+ }
23135
+ if (t4.isImportDefaultSpecifier(spec)) {
23136
+ const localName = spec.local.name;
23137
+ const kind = meta.exports.default;
23138
+ if (kind) {
23139
+ addImportedReactiveBinding(localName, kind, ctx);
23140
+ }
23141
+ const hookInfo = meta.hooks?.default;
23142
+ if (hookInfo) {
23143
+ ctx.hookReturnInfo = ctx.hookReturnInfo ?? /* @__PURE__ */ new Map();
23144
+ ctx.hookReturnInfo.set(localName, deserializeHookReturnInfo(hookInfo));
23145
+ }
23146
+ continue;
23147
+ }
23148
+ if (t4.isImportNamespaceSpecifier(spec)) {
23149
+ namespaces.set(spec.local.name, meta);
23150
+ }
23151
+ }
23152
+ }
23153
+ if (namespaces.size > 0) {
23154
+ ctx.importedNamespaces = namespaces;
23155
+ }
23156
+ }
23157
+ function classifyReactiveExport(name, ctx) {
23158
+ const base = deSSAVarName(name);
23159
+ if (ctx.storeVars?.has(base)) return "store";
23160
+ if (ctx.signalVars?.has(base)) return "signal";
23161
+ if (ctx.aliasVars?.has(base)) return "signal";
23162
+ if (ctx.memoVars?.has(base)) return "memo";
23163
+ return null;
23164
+ }
23165
+ function buildModuleReactiveMetadata(body, ctx, t4, options, stateMacroNames, memoMacroNames) {
23166
+ const metadata = { exports: {} };
23167
+ const hookExports = {};
23168
+ const addExport = (exportName, localName) => {
23169
+ const kind = classifyReactiveExport(localName, ctx);
23170
+ if (kind) {
23171
+ metadata.exports[exportName] = kind;
23172
+ }
23173
+ const hookInfo = getHookReturnInfo(localName, ctx);
23174
+ if (hookInfo) {
23175
+ hookExports[exportName] = serializeHookReturnInfo(hookInfo);
23176
+ }
23177
+ };
23178
+ const addExportFromSource = (source, importedName, exportName) => {
23179
+ const sourceMeta = resolveModuleMetadata(source, options?.filename, options);
23180
+ if (!sourceMeta) return;
23181
+ const kind = sourceMeta.exports[importedName];
23182
+ if (kind) {
23183
+ metadata.exports[exportName] = kind;
23184
+ }
23185
+ const hookInfo = sourceMeta.hooks?.[importedName];
23186
+ if (hookInfo) {
23187
+ hookExports[exportName] = hookInfo;
23188
+ }
23189
+ };
23190
+ const addDefaultExportKind = (kind) => {
23191
+ if (kind) {
23192
+ metadata.exports.default = kind;
23193
+ }
23194
+ };
23195
+ for (const stmt of body) {
23196
+ if (t4.isExportNamedDeclaration(stmt)) {
23197
+ if (stmt.source && stmt.specifiers.length > 0) {
23198
+ for (const spec of stmt.specifiers) {
23199
+ if (!t4.isExportSpecifier(spec)) continue;
23200
+ const importedName = spec.local.name;
23201
+ const exportName = t4.isIdentifier(spec.exported) ? spec.exported.name : t4.isStringLiteral(spec.exported) ? spec.exported.value : String(spec.exported);
23202
+ addExportFromSource(stmt.source.value, importedName, exportName);
23203
+ }
23204
+ continue;
23205
+ }
23206
+ if (stmt.declaration) {
23207
+ const decl = stmt.declaration;
23208
+ if (t4.isFunctionDeclaration(decl) && decl.id) {
23209
+ addExport(decl.id.name, decl.id.name);
23210
+ } else if (t4.isClassDeclaration(decl) && decl.id) {
23211
+ addExport(decl.id.name, decl.id.name);
23212
+ } else if (t4.isVariableDeclaration(decl)) {
23213
+ for (const v of decl.declarations) {
23214
+ if (t4.isIdentifier(v.id)) {
23215
+ addExport(v.id.name, v.id.name);
23216
+ }
23217
+ }
23218
+ }
23219
+ } else {
23220
+ for (const spec of stmt.specifiers) {
23221
+ if (!t4.isExportSpecifier(spec)) continue;
23222
+ const localName = spec.local.name;
23223
+ const exportName = t4.isIdentifier(spec.exported) ? spec.exported.name : t4.isStringLiteral(spec.exported) ? spec.exported.value : String(spec.exported);
23224
+ addExport(exportName, localName);
23225
+ }
23226
+ }
23227
+ continue;
23228
+ }
23229
+ if (t4.isExportAllDeclaration(stmt)) {
23230
+ const sourceMeta = resolveModuleMetadata(stmt.source.value, options?.filename, options);
23231
+ if (!sourceMeta) continue;
23232
+ for (const [exportName, kind] of Object.entries(sourceMeta.exports)) {
23233
+ if (exportName === "default") continue;
23234
+ metadata.exports[exportName] = kind;
23235
+ }
23236
+ if (sourceMeta.hooks) {
23237
+ for (const [exportName, info] of Object.entries(sourceMeta.hooks)) {
23238
+ if (exportName === "default") continue;
23239
+ hookExports[exportName] = info;
23240
+ }
23241
+ }
23242
+ continue;
23243
+ }
23244
+ if (t4.isExportDefaultDeclaration(stmt)) {
23245
+ const decl = stmt.declaration;
23246
+ if (t4.isIdentifier(decl)) {
23247
+ addExport("default", decl.name);
23248
+ } else if (t4.isFunctionDeclaration(decl) && decl.id) {
23249
+ addExport("default", decl.id.name);
23250
+ } else if (t4.isClassDeclaration(decl) && decl.id) {
23251
+ addExport("default", decl.id.name);
23252
+ } else if (t4.isCallExpression(decl) && t4.isIdentifier(decl.callee)) {
23253
+ const callee = decl.callee.name;
23254
+ if (stateMacroNames.has(callee) || callee === "$store") {
23255
+ addDefaultExportKind(callee === "$store" ? "store" : "signal");
23256
+ } else if (memoMacroNames.has(callee)) {
23257
+ addDefaultExportKind("memo");
23258
+ }
23259
+ }
23260
+ }
23261
+ }
23262
+ if (Object.keys(hookExports).length > 0) {
23263
+ metadata.hooks = hookExports;
23264
+ }
23265
+ return metadata;
23266
+ }
22773
23267
  function collectLocalDeclaredNames(params, blocks, t4) {
22774
23268
  const declared = /* @__PURE__ */ new Set();
22775
23269
  const addPatternNames = (pattern) => {
@@ -23078,6 +23572,24 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
23078
23572
  if (matchesListKeyPattern(expr, ctx)) {
23079
23573
  return t4.identifier(ctx.listKeyParamName);
23080
23574
  }
23575
+ if (expr.object.kind === "Identifier") {
23576
+ const nsMeta = ctx.importedNamespaces?.get(deSSAVarName(expr.object.name));
23577
+ if (nsMeta) {
23578
+ const propName = getStaticPropName(expr.property, expr.computed);
23579
+ if (typeof propName === "string") {
23580
+ const kind = nsMeta.exports[propName];
23581
+ if (kind === "signal" || kind === "memo") {
23582
+ const member = t4.memberExpression(
23583
+ t4.identifier(deSSAVarName(expr.object.name)),
23584
+ expr.computed ? t4.stringLiteral(propName) : t4.identifier(propName),
23585
+ expr.computed,
23586
+ expr.optional
23587
+ );
23588
+ return t4.callExpression(member, []);
23589
+ }
23590
+ }
23591
+ }
23592
+ }
23081
23593
  if (expr.object.kind === "Identifier" && ctx.hookResultVarMap?.has(deSSAVarName(expr.object.name))) {
23082
23594
  const hookName = ctx.hookResultVarMap.get(deSSAVarName(expr.object.name));
23083
23595
  const info = getHookReturnInfo(hookName, ctx);
@@ -23569,8 +24081,8 @@ function collectExpressionDependencies(expr, deps) {
23569
24081
  return;
23570
24082
  }
23571
24083
  if (expr.kind === "MemberExpression") {
23572
- const path = getMemberDependencyPath(expr);
23573
- if (path) deps.add(path);
24084
+ const path2 = getMemberDependencyPath(expr);
24085
+ if (path2) deps.add(path2);
23574
24086
  collectExpressionDependencies(expr.object, deps);
23575
24087
  if (expr.computed && expr.property.kind !== "Literal") {
23576
24088
  collectExpressionDependencies(expr.property, deps);
@@ -23755,9 +24267,9 @@ function replaceIdentifiersWithOverrides(node, overrides, t4, parentKind, parent
23755
24267
  if (!skipCurrentNode && (t4.isMemberExpression(node) || t4.isOptionalMemberExpression(node))) {
23756
24268
  const propertyNode = node.property;
23757
24269
  const isDynamicComputed = (node.computed ?? false) && !t4.isStringLiteral(propertyNode) && !t4.isNumericLiteral(propertyNode);
23758
- const path = getDependencyPathFromNode(node, t4);
23759
- const normalized = path ? normalizeDependencyKey2(path) : null;
23760
- const override = normalized && overrides[normalized] || (path ? overrides[path] : void 0);
24270
+ const path2 = getDependencyPathFromNode(node, t4);
24271
+ const normalized = path2 ? normalizeDependencyKey2(path2) : null;
24272
+ const override = normalized && overrides[normalized] || (path2 ? overrides[path2] : void 0);
23761
24273
  if (override && !isCallTarget && !isDynamicComputed) {
23762
24274
  const replacement = override();
23763
24275
  Object.assign(node, replacement);
@@ -24488,11 +25000,11 @@ function lowerIntrinsicElement(jsx, ctx) {
24488
25000
  }
24489
25001
  return t4.callExpression(t4.arrowFunctionExpression([], body), []);
24490
25002
  }
24491
- function resolveHIRBindingPath(path, cache, statements, ctx) {
24492
- const key = path.join(",");
25003
+ function resolveHIRBindingPath(path2, cache, statements, ctx) {
25004
+ const key = path2.join(",");
24493
25005
  if (cache.has(key)) return cache.get(key);
24494
25006
  const { t: t4 } = ctx;
24495
- const ancestorPath = [...path];
25007
+ const ancestorPath = [...path2];
24496
25008
  let ancestorId;
24497
25009
  let relativePath = [];
24498
25010
  while (ancestorPath.length > 0) {
@@ -24500,13 +25012,13 @@ function resolveHIRBindingPath(path, cache, statements, ctx) {
24500
25012
  const ancestorKey = ancestorPath.join(",");
24501
25013
  if (cache.has(ancestorKey)) {
24502
25014
  ancestorId = cache.get(ancestorKey);
24503
- relativePath = path.slice(ancestorPath.length);
25015
+ relativePath = path2.slice(ancestorPath.length);
24504
25016
  break;
24505
25017
  }
24506
25018
  }
24507
25019
  if (!ancestorId) {
24508
25020
  ancestorId = cache.get("");
24509
- relativePath = path;
25021
+ relativePath = path2;
24510
25022
  }
24511
25023
  let currentExpr = ancestorId;
24512
25024
  for (const index of relativePath) {
@@ -25315,6 +25827,7 @@ function lowerHIRWithRegions(program, t4, options, macroAliases) {
25315
25827
  const originalBody = program.originalBody ?? [];
25316
25828
  ctx.moduleDeclaredNames = collectDeclaredNames(originalBody, t4);
25317
25829
  ctx.moduleRuntimeNames = collectRuntimeImportNames(originalBody, t4);
25830
+ applyImportedReactiveMetadata(originalBody, ctx, t4, options);
25318
25831
  const stateMacroNames = /* @__PURE__ */ new Set(["$state", ...macroAliases?.state ?? []]);
25319
25832
  const memoMacroNames = new Set(macroAliases?.memo ?? ctx.memoMacroNames ?? []);
25320
25833
  if (!memoMacroNames.has("$memo")) memoMacroNames.add("$memo");
@@ -25554,6 +26067,15 @@ function lowerHIRWithRegions(program, t4, options, macroAliases) {
25554
26067
  ctx.helpersUsed.add("popContext");
25555
26068
  body.push(t4.expressionStatement(t4.callExpression(t4.identifier(RUNTIME_ALIASES.popContext), [])));
25556
26069
  }
26070
+ const moduleMeta = buildModuleReactiveMetadata(
26071
+ originalBody,
26072
+ ctx,
26073
+ t4,
26074
+ options,
26075
+ stateMacroNames,
26076
+ memoMacroNames
26077
+ );
26078
+ setModuleMetadata(options?.filename, moduleMeta, options);
25557
26079
  return t4.file(t4.program(attachHelperImports(ctx, body, t4)));
25558
26080
  }
25559
26081
  function lowerTopLevelStatementBlock(statements, ctx, t4, name = "__module_segment", existingAliases) {
@@ -26034,7 +26556,7 @@ function lowerFunctionWithRegions(fn, ctx) {
26034
26556
  if (!hasComplexControlFlow && !isAsync) {
26035
26557
  const pureDeclaredVars = /* @__PURE__ */ new Set();
26036
26558
  const pureStatements = lowerStructuredNodeWithoutRegions(structured, t4, ctx, pureDeclaredVars);
26037
- const params2 = fn.params.map((p) => t4.identifier(deSSAVarName(p.name)));
26559
+ const params2 = buildOutputParams(fn, t4);
26038
26560
  const funcDecl2 = setNodeLoc(
26039
26561
  t4.functionDeclaration(
26040
26562
  t4.identifier(fn.name ?? "fn"),
@@ -26109,13 +26631,31 @@ function lowerFunctionWithRegions(fn, ctx) {
26109
26631
  )
26110
26632
  );
26111
26633
  }
26112
- let finalParams = fn.params.map((p) => t4.identifier(deSSAVarName(p.name)));
26634
+ let finalParams = buildOutputParams(fn, t4);
26113
26635
  const propsDestructuring = [];
26114
26636
  if (isComponent && fn.rawParams && fn.rawParams.length === 1) {
26115
26637
  const rawParam = fn.rawParams[0];
26116
26638
  if (rawParam && (rawParam.type === "ObjectPattern" || rawParam.type === "AssignmentPattern" && rawParam.left?.type === "ObjectPattern")) {
26117
- finalParams = [t4.identifier("__props")];
26118
26639
  const pattern = rawParam.type === "AssignmentPattern" ? rawParam.left : rawParam;
26640
+ const defaultExpr = rawParam.type === "AssignmentPattern" ? rawParam.right : null;
26641
+ if (defaultExpr) {
26642
+ const propsParamName = "__propsParam";
26643
+ finalParams = [t4.identifier(propsParamName)];
26644
+ propsDestructuring.push(
26645
+ t4.variableDeclaration("const", [
26646
+ t4.variableDeclarator(
26647
+ t4.identifier("__props"),
26648
+ t4.conditionalExpression(
26649
+ t4.binaryExpression("===", t4.identifier(propsParamName), t4.identifier("undefined")),
26650
+ t4.cloneNode(defaultExpr, true),
26651
+ t4.identifier(propsParamName)
26652
+ )
26653
+ )
26654
+ ])
26655
+ );
26656
+ } else {
26657
+ finalParams = [t4.identifier("__props")];
26658
+ }
26119
26659
  if (propsDestructurePlan) {
26120
26660
  if (propsDestructurePlan.usesProp) {
26121
26661
  ctx.helpersUsed.add("prop");
@@ -26273,7 +26813,7 @@ function optimizeHIR(program, options = {}) {
26273
26813
  originalBody: []
26274
26814
  });
26275
26815
  const ssaFn = ssaProgram.functions[0];
26276
- return ssaFn ? optimizeSSAFunction(ssaFn) : fn;
26816
+ return ssaFn ? optimizeSSAFunction(ssaFn, options) : fn;
26277
26817
  }
26278
26818
  if (isReactiveOptimizationCandidate(fn)) {
26279
26819
  return optimizeReactiveFunction(fn, exportedNames, options);
@@ -26285,9 +26825,9 @@ function optimizeHIR(program, options = {}) {
26285
26825
  functions
26286
26826
  };
26287
26827
  }
26288
- function optimizeSSAFunction(fn) {
26828
+ function optimizeSSAFunction(fn, options) {
26289
26829
  let current = fn;
26290
- current = propagateConstants(current);
26830
+ current = propagateConstants(current, options);
26291
26831
  const purity = buildPurityContext(current);
26292
26832
  current = eliminateCommonSubexpressions(current, purity);
26293
26833
  current = inlineSingleUse(current, purity);
@@ -26912,7 +27452,9 @@ function optimizeReactiveFunction(fn, exportedNames, options) {
26912
27452
  const reactive = buildReactiveContext(fn);
26913
27453
  const purity = buildPurityContext(fn);
26914
27454
  const hookLike = isHookLikeFunction(fn);
26915
- const transformedBlocks = fn.blocks.map((block) => optimizeReactiveBlock(block, reactive, purity));
27455
+ const transformedBlocks = fn.blocks.map(
27456
+ (block) => optimizeReactiveBlock(block, reactive, purity, options)
27457
+ );
26916
27458
  let transformed = { ...fn, blocks: transformedBlocks };
26917
27459
  if (isCrossBlockConstPropagationEnabled()) {
26918
27460
  transformed = propagateCrossBlockConstants(transformed, reactive, purity, scopeResult);
@@ -26947,7 +27489,7 @@ function optimizeReactiveFunction(fn, exportedNames, options) {
26947
27489
  });
26948
27490
  return { ...transformed, blocks };
26949
27491
  }
26950
- function optimizeReactiveBlock(block, reactive, purity) {
27492
+ function optimizeReactiveBlock(block, reactive, purity, options) {
26951
27493
  const constants = /* @__PURE__ */ new Map();
26952
27494
  const constObjects = /* @__PURE__ */ new Map();
26953
27495
  const constArrays = /* @__PURE__ */ new Map();
@@ -26985,7 +27527,7 @@ function optimizeReactiveBlock(block, reactive, purity) {
26985
27527
  constArrays.delete(name);
26986
27528
  }
26987
27529
  const dependsOnReactiveValue = expressionDependsOnReactive(instr.value, reactive);
26988
- let value = dependsOnReactiveValue ? instr.value : foldExpressionWithConstants(instr.value, constants, constObjects, constArrays);
27530
+ let value = dependsOnReactiveValue ? instr.value : foldExpressionWithConstants(instr.value, constants, options, constObjects, constArrays);
26989
27531
  const allowCSE = isCompilerGeneratedName(target) && (!declKind || declKind === "const");
26990
27532
  if (allowCSE && isPureExpression(value, purity) && !isExplicitMemoCall(value, purity) && !dependsOnReactiveValue && isCSESafeExpression(value, purity)) {
26991
27533
  const deps = collectExpressionIdentifiers2(value, true);
@@ -27033,7 +27575,7 @@ function optimizeReactiveBlock(block, reactive, purity) {
27033
27575
  constArrays.delete(name);
27034
27576
  }
27035
27577
  const dependsOnReactiveValue = expressionDependsOnReactive(instr.value, reactive);
27036
- const value = dependsOnReactiveValue ? instr.value : foldExpressionWithConstants(instr.value, constants, constObjects, constArrays);
27578
+ const value = dependsOnReactiveValue ? instr.value : foldExpressionWithConstants(instr.value, constants, options, constObjects, constArrays);
27037
27579
  instructions.push(value === instr.value ? instr : { ...instr, value });
27038
27580
  continue;
27039
27581
  }
@@ -27042,6 +27584,7 @@ function optimizeReactiveBlock(block, reactive, purity) {
27042
27584
  const terminator = foldTerminatorWithConstants(
27043
27585
  block.terminator,
27044
27586
  constants,
27587
+ options,
27045
27588
  reactive,
27046
27589
  constObjects,
27047
27590
  constArrays
@@ -27973,7 +28516,7 @@ function blocksContainImpureMarkers(blocks) {
27973
28516
  }
27974
28517
  return false;
27975
28518
  }
27976
- function propagateConstants(fn) {
28519
+ function propagateConstants(fn, options) {
27977
28520
  const constants = computeConstantMap(fn);
27978
28521
  if (constants.size === 0) return fn;
27979
28522
  const blocks = fn.blocks.map((block) => ({
@@ -27981,12 +28524,12 @@ function propagateConstants(fn) {
27981
28524
  instructions: block.instructions.map((instr) => {
27982
28525
  if (instr.kind === "Assign") {
27983
28526
  const replaced = replaceIdentifiersWithConstants(instr.value, constants);
27984
- const folded = foldExpression(replaced, constants);
28527
+ const folded = foldExpression(replaced, constants, options);
27985
28528
  return { ...instr, value: folded };
27986
28529
  }
27987
28530
  if (instr.kind === "Expression") {
27988
28531
  const replaced = replaceIdentifiersWithConstants(instr.value, constants);
27989
- const folded = foldExpression(replaced, constants);
28532
+ const folded = foldExpression(replaced, constants, options);
27990
28533
  return { ...instr, value: folded };
27991
28534
  }
27992
28535
  if (instr.kind === "Phi") {
@@ -28386,15 +28929,18 @@ function evaluateBinary(operator, left, right) {
28386
28929
  return UNKNOWN_CONST;
28387
28930
  }
28388
28931
  }
28389
- function foldExpression(expr, constants) {
28932
+ function foldExpression(expr, constants, options) {
28390
28933
  const value = evaluateConstant(expr, constants);
28391
28934
  if (value === UNKNOWN_CONST) {
28392
- return simplifyAlgebraically(expr, constants);
28935
+ return simplifyAlgebraically(expr, constants, options);
28393
28936
  }
28394
28937
  return { kind: "Literal", value, loc: expr.loc };
28395
28938
  }
28396
- function simplifyAlgebraically(expr, constants) {
28397
- const simplified = simplifyChildren(expr, constants);
28939
+ function simplifyAlgebraically(expr, constants, options) {
28940
+ const simplified = simplifyChildren(expr, constants, options);
28941
+ if (options.optimizeLevel === "safe") {
28942
+ return simplified;
28943
+ }
28398
28944
  if (simplified.kind === "BinaryExpression") {
28399
28945
  const { operator, left, right, loc } = simplified;
28400
28946
  switch (operator) {
@@ -28473,37 +29019,37 @@ function simplifyAlgebraically(expr, constants) {
28473
29019
  }
28474
29020
  return simplified;
28475
29021
  }
28476
- function simplifyChildren(expr, constants) {
29022
+ function simplifyChildren(expr, constants, options) {
28477
29023
  switch (expr.kind) {
28478
29024
  case "BinaryExpression":
28479
29025
  return {
28480
29026
  ...expr,
28481
- left: simplifyAlgebraically(expr.left, constants),
28482
- right: simplifyAlgebraically(expr.right, constants)
29027
+ left: simplifyAlgebraically(expr.left, constants, options),
29028
+ right: simplifyAlgebraically(expr.right, constants, options)
28483
29029
  };
28484
29030
  case "LogicalExpression":
28485
29031
  return {
28486
29032
  ...expr,
28487
- left: simplifyAlgebraically(expr.left, constants),
28488
- right: simplifyAlgebraically(expr.right, constants)
29033
+ left: simplifyAlgebraically(expr.left, constants, options),
29034
+ right: simplifyAlgebraically(expr.right, constants, options)
28489
29035
  };
28490
29036
  case "UnaryExpression":
28491
29037
  return {
28492
29038
  ...expr,
28493
- argument: simplifyAlgebraically(expr.argument, constants)
29039
+ argument: simplifyAlgebraically(expr.argument, constants, options)
28494
29040
  };
28495
29041
  case "ConditionalExpression":
28496
29042
  return {
28497
29043
  ...expr,
28498
- test: simplifyAlgebraically(expr.test, constants),
28499
- consequent: simplifyAlgebraically(expr.consequent, constants),
28500
- alternate: simplifyAlgebraically(expr.alternate, constants)
29044
+ test: simplifyAlgebraically(expr.test, constants, options),
29045
+ consequent: simplifyAlgebraically(expr.consequent, constants, options),
29046
+ alternate: simplifyAlgebraically(expr.alternate, constants, options)
28501
29047
  };
28502
29048
  case "ArrayExpression":
28503
29049
  return {
28504
29050
  ...expr,
28505
29051
  elements: expr.elements.map(
28506
- (el) => el ? simplifyAlgebraically(el, constants) : el
29052
+ (el) => el ? simplifyAlgebraically(el, constants, options) : el
28507
29053
  )
28508
29054
  };
28509
29055
  case "ObjectExpression":
@@ -28513,13 +29059,13 @@ function simplifyChildren(expr, constants) {
28513
29059
  if (prop.kind === "Property") {
28514
29060
  return {
28515
29061
  ...prop,
28516
- value: simplifyAlgebraically(prop.value, constants)
29062
+ value: simplifyAlgebraically(prop.value, constants, options)
28517
29063
  };
28518
29064
  }
28519
29065
  if (prop.kind === "SpreadElement") {
28520
29066
  return {
28521
29067
  ...prop,
28522
- argument: simplifyAlgebraically(prop.argument, constants)
29068
+ argument: simplifyAlgebraically(prop.argument, constants, options)
28523
29069
  };
28524
29070
  }
28525
29071
  return prop;
@@ -28529,35 +29075,35 @@ function simplifyChildren(expr, constants) {
28529
29075
  case "OptionalCallExpression":
28530
29076
  return {
28531
29077
  ...expr,
28532
- arguments: expr.arguments.map((arg) => simplifyAlgebraically(arg, constants))
29078
+ arguments: expr.arguments.map((arg) => simplifyAlgebraically(arg, constants, options))
28533
29079
  };
28534
29080
  case "ImportExpression":
28535
29081
  return {
28536
29082
  ...expr,
28537
- source: simplifyAlgebraically(expr.source, constants)
29083
+ source: simplifyAlgebraically(expr.source, constants, options)
28538
29084
  };
28539
29085
  case "MemberExpression":
28540
29086
  case "OptionalMemberExpression":
28541
29087
  return {
28542
29088
  ...expr,
28543
- object: simplifyAlgebraically(expr.object, constants),
28544
- property: expr.computed ? simplifyAlgebraically(expr.property, constants) : expr.property
29089
+ object: simplifyAlgebraically(expr.object, constants, options),
29090
+ property: expr.computed ? simplifyAlgebraically(expr.property, constants, options) : expr.property
28545
29091
  };
28546
29092
  default:
28547
29093
  return expr;
28548
29094
  }
28549
29095
  }
28550
- function foldExpressionWithConstants(expr, constants, constObjects, constArrays) {
29096
+ function foldExpressionWithConstants(expr, constants, options, constObjects, constArrays) {
28551
29097
  const replaced = replaceIdentifiersWithConstants(expr, constants);
28552
29098
  if (!constObjects && !constArrays) {
28553
- return foldExpression(replaced, constants);
29099
+ return foldExpression(replaced, constants, options);
28554
29100
  }
28555
29101
  const memberReplaced = replaceConstMemberExpressions(
28556
29102
  replaced,
28557
29103
  constObjects ?? /* @__PURE__ */ new Map(),
28558
29104
  constArrays ?? /* @__PURE__ */ new Map()
28559
29105
  );
28560
- return foldExpression(memberReplaced, constants);
29106
+ return foldExpression(memberReplaced, constants, options);
28561
29107
  }
28562
29108
  function replaceIdentifiersWithConstants(expr, constants, context = {}) {
28563
29109
  switch (expr.kind) {
@@ -28719,10 +29265,10 @@ function replaceConstantsInTerminator(term, constants) {
28719
29265
  return term;
28720
29266
  }
28721
29267
  }
28722
- function foldTerminatorWithConstants(term, constants, reactive, constObjects, constArrays) {
29268
+ function foldTerminatorWithConstants(term, constants, options, reactive, constObjects, constArrays) {
28723
29269
  const fold = (expr) => {
28724
29270
  if (reactive && expressionDependsOnReactive(expr, reactive)) return expr;
28725
- return foldExpressionWithConstants(expr, constants, constObjects, constArrays);
29271
+ return foldExpressionWithConstants(expr, constants, options, constObjects, constArrays);
28726
29272
  };
28727
29273
  switch (term.kind) {
28728
29274
  case "Return":
@@ -28839,11 +29385,14 @@ function hasSideEffectsBetween(instructions, start, end, purity) {
28839
29385
  function eliminateDeadCode(fn, purity) {
28840
29386
  const depsByVar = buildDependencyGraph(fn);
28841
29387
  const live = computeLiveVariables(fn, depsByVar, purity);
29388
+ const baseLive = /* @__PURE__ */ new Set();
29389
+ live.forEach((name) => baseLive.add(getSSABaseName(name)));
28842
29390
  const blocks = fn.blocks.map((block) => {
28843
29391
  const instructions = block.instructions.filter((instr) => {
28844
29392
  if (instr.kind === "Assign") {
28845
29393
  const name = instr.target.name;
28846
29394
  if (live.has(name)) return true;
29395
+ if (instr.declarationKind && baseLive.has(getSSABaseName(name))) return true;
28847
29396
  return !isPureExpression(instr.value, purity) || isExplicitMemoCall(instr.value, purity);
28848
29397
  }
28849
29398
  if (instr.kind === "Phi") {
@@ -29855,8 +30404,8 @@ function getRootIdentifier(expr, t4) {
29855
30404
  }
29856
30405
 
29857
30406
  // src/index.ts
29858
- function stripMacroImports(path, t4) {
29859
- path.traverse({
30407
+ function stripMacroImports(path2, t4) {
30408
+ path2.traverse({
29860
30409
  ImportDeclaration(importPath) {
29861
30410
  if (importPath.node.source.value !== "fict" && importPath.node.source.value !== "fict/slim")
29862
30411
  return;
@@ -29874,19 +30423,19 @@ function stripMacroImports(path, t4) {
29874
30423
  }
29875
30424
  });
29876
30425
  }
29877
- function isInsideLoop(path) {
29878
- return !!path.findParent(
30426
+ function isInsideLoop(path2) {
30427
+ return !!path2.findParent(
29879
30428
  (p) => p.isForStatement?.() || p.isWhileStatement?.() || p.isDoWhileStatement?.() || p.isForInStatement?.() || p.isForOfStatement?.()
29880
30429
  );
29881
30430
  }
29882
- function isInsideConditional(path) {
29883
- return !!path.findParent(
30431
+ function isInsideConditional(path2) {
30432
+ return !!path2.findParent(
29884
30433
  (p) => p.isIfStatement?.() || p.isConditionalExpression?.() || p.isSwitchCase?.()
29885
30434
  );
29886
30435
  }
29887
- function isInsideNestedFunction(path) {
30436
+ function isInsideNestedFunction(path2) {
29888
30437
  let depth = 0;
29889
- let current = path;
30438
+ let current = path2;
29890
30439
  while (current) {
29891
30440
  if (current.isFunction?.()) {
29892
30441
  depth++;
@@ -29896,8 +30445,8 @@ function isInsideNestedFunction(path) {
29896
30445
  }
29897
30446
  return false;
29898
30447
  }
29899
- function isInsideJSX(path) {
29900
- return !!path.findParent((p) => p.isJSXElement?.() || p.isJSXFragment?.());
30448
+ function isInsideJSX(path2) {
30449
+ return !!path2.findParent((p) => p.isJSXElement?.() || p.isJSXFragment?.());
29901
30450
  }
29902
30451
  function parseSuppressionCodes(raw) {
29903
30452
  if (!raw) return void 0;
@@ -29926,12 +30475,42 @@ function shouldSuppressWarning(suppressions, code, line) {
29926
30475
  return entry.codes.has(code);
29927
30476
  });
29928
30477
  }
29929
- function createWarningDispatcher(onWarn, suppressions) {
29930
- if (!onWarn) return () => {
30478
+ function hasErrorEscalation(options) {
30479
+ if (options.warningsAsErrors === true) return true;
30480
+ if (Array.isArray(options.warningsAsErrors) && options.warningsAsErrors.length > 0) return true;
30481
+ if (options.warningLevels) {
30482
+ return Object.values(options.warningLevels).some((level) => level === "error");
30483
+ }
30484
+ return false;
30485
+ }
30486
+ function resolveWarningLevel(code, options) {
30487
+ const override = options.warningLevels?.[code];
30488
+ if (override) return override;
30489
+ if (options.warningsAsErrors === true) return "error";
30490
+ if (Array.isArray(options.warningsAsErrors) && options.warningsAsErrors.includes(code)) {
30491
+ return "error";
30492
+ }
30493
+ return "warn";
30494
+ }
30495
+ function formatWarningAsError(warning) {
30496
+ const location = warning.line > 0 ? `${warning.fileName}:${warning.line}:${warning.column}` : warning.fileName;
30497
+ return `Fict warning treated as error (${warning.code}): ${warning.message}
30498
+ at ${location}`;
30499
+ }
30500
+ function createWarningDispatcher(onWarn, suppressions, options, dev) {
30501
+ const hasEscalation = hasErrorEscalation(options);
30502
+ if (!dev && !hasEscalation) return () => {
29931
30503
  };
29932
30504
  return (warning) => {
29933
30505
  if (shouldSuppressWarning(suppressions, warning.code, warning.line)) return;
29934
- onWarn(warning);
30506
+ const level = resolveWarningLevel(warning.code, options);
30507
+ if (level === "off") return;
30508
+ if (level === "error") {
30509
+ throw new Error(formatWarningAsError(warning));
30510
+ }
30511
+ if (dev && onWarn) {
30512
+ onWarn(warning);
30513
+ }
29935
30514
  };
29936
30515
  }
29937
30516
  function emitWarning(node, code, message, warn, fileName) {
@@ -30031,13 +30610,13 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
30031
30610
  };
30032
30611
  const reactiveNames = /* @__PURE__ */ new Set([...stateVars, ...derivedVars]);
30033
30612
  programPath.traverse({
30034
- AssignmentExpression(path) {
30035
- const { left } = path.node;
30613
+ AssignmentExpression(path2) {
30614
+ const { left } = path2.node;
30036
30615
  if (t4.isIdentifier(left)) return;
30037
30616
  if (t4.isMemberExpression(left) || t4.isOptionalMemberExpression(left)) {
30038
30617
  if (isStateRoot(left.object)) {
30039
30618
  emitWarning(
30040
- path.node,
30619
+ path2.node,
30041
30620
  "FICT-M",
30042
30621
  "Direct mutation of nested property detected; use immutable update or $store helpers",
30043
30622
  warn,
@@ -30045,7 +30624,7 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
30045
30624
  );
30046
30625
  if (isDynamicPropertyAccess(left, t4)) {
30047
30626
  emitWarning(
30048
- path.node,
30627
+ path2.node,
30049
30628
  "FICT-H",
30050
30629
  "Dynamic property access widens dependency tracking",
30051
30630
  warn,
@@ -30055,12 +30634,12 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
30055
30634
  }
30056
30635
  }
30057
30636
  },
30058
- UpdateExpression(path) {
30059
- const arg = path.node.argument;
30637
+ UpdateExpression(path2) {
30638
+ const arg = path2.node.argument;
30060
30639
  if (t4.isMemberExpression(arg) || t4.isOptionalMemberExpression(arg)) {
30061
30640
  if (isStateRoot(arg.object)) {
30062
30641
  emitWarning(
30063
- path.node,
30642
+ path2.node,
30064
30643
  "FICT-M",
30065
30644
  "Direct mutation of nested property detected; use immutable update or $store helpers",
30066
30645
  warn,
@@ -30068,7 +30647,7 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
30068
30647
  );
30069
30648
  if (isDynamicPropertyAccess(arg, t4)) {
30070
30649
  emitWarning(
30071
- path.node,
30650
+ path2.node,
30072
30651
  "FICT-H",
30073
30652
  "Dynamic property access widens dependency tracking",
30074
30653
  warn,
@@ -30078,13 +30657,13 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
30078
30657
  }
30079
30658
  }
30080
30659
  },
30081
- MemberExpression(path) {
30082
- if (!path.node.computed) return;
30083
- if (path.parentPath.isAssignmentExpression({ left: path.node })) return;
30084
- if (path.parentPath.isUpdateExpression({ argument: path.node })) return;
30085
- if (isDynamicPropertyAccess(path.node, t4) && isStateRoot(path.node.object)) {
30660
+ MemberExpression(path2) {
30661
+ if (!path2.node.computed) return;
30662
+ if (path2.parentPath.isAssignmentExpression({ left: path2.node })) return;
30663
+ if (path2.parentPath.isUpdateExpression({ argument: path2.node })) return;
30664
+ if (isDynamicPropertyAccess(path2.node, t4) && isStateRoot(path2.node.object)) {
30086
30665
  emitWarning(
30087
- path.node,
30666
+ path2.node,
30088
30667
  "FICT-H",
30089
30668
  "Dynamic property access widens dependency tracking",
30090
30669
  warn,
@@ -30092,12 +30671,12 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
30092
30671
  );
30093
30672
  }
30094
30673
  },
30095
- Function(path) {
30674
+ Function(path2) {
30096
30675
  const captured = /* @__PURE__ */ new Set();
30097
- path.traverse(
30676
+ path2.traverse(
30098
30677
  {
30099
30678
  Function(inner) {
30100
- if (inner === path) return;
30679
+ if (inner === path2) return;
30101
30680
  inner.skip();
30102
30681
  },
30103
30682
  Identifier(idPath) {
@@ -30105,7 +30684,7 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
30105
30684
  if (!reactiveNames.has(name)) return;
30106
30685
  const binding = idPath.scope.getBinding(name);
30107
30686
  if (!binding) return;
30108
- if (binding.scope === idPath.scope || binding.scope === path.scope) return;
30687
+ if (binding.scope === idPath.scope || binding.scope === path2.scope) return;
30109
30688
  captured.add(name);
30110
30689
  }
30111
30690
  },
@@ -30113,7 +30692,7 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
30113
30692
  );
30114
30693
  if (captured.size > 0) {
30115
30694
  emitWarning(
30116
- path.node,
30695
+ path2.node,
30117
30696
  "FICT-R005",
30118
30697
  `Function captures reactive variable(s): ${Array.from(captured).join(", ")}. Pass them as parameters or memoize explicitly to avoid hidden dependencies.`,
30119
30698
  warn,
@@ -30121,9 +30700,9 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
30121
30700
  );
30122
30701
  }
30123
30702
  },
30124
- CallExpression(path) {
30125
- if (t4.isIdentifier(path.node.callee, { name: "$effect" })) {
30126
- const argPath = path.get("arguments.0");
30703
+ CallExpression(path2) {
30704
+ if (t4.isIdentifier(path2.node.callee, { name: "$effect" })) {
30705
+ const argPath = path2.get("arguments.0");
30127
30706
  if (argPath?.isFunctionExpression() || argPath?.isArrowFunctionExpression()) {
30128
30707
  let hasReactiveDependency = false;
30129
30708
  argPath.traverse({
@@ -30144,7 +30723,7 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
30144
30723
  });
30145
30724
  if (!hasReactiveDependency) {
30146
30725
  emitWarning(
30147
- path.node,
30726
+ path2.node,
30148
30727
  "FICT-E001",
30149
30728
  "Effect has no reactive reads; it will run once. Consider removing $effect or adding dependencies.",
30150
30729
  warn,
@@ -30154,7 +30733,7 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
30154
30733
  }
30155
30734
  return;
30156
30735
  }
30157
- const callee = path.node.callee;
30736
+ const callee = path2.node.callee;
30158
30737
  let calleeName = "";
30159
30738
  if (t4.isIdentifier(callee)) {
30160
30739
  calleeName = callee.name;
@@ -30166,7 +30745,7 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
30166
30745
  }
30167
30746
  const isSafe = calleeName && SAFE_FUNCTIONS.has(calleeName);
30168
30747
  if (isSafe) return;
30169
- for (const arg of path.node.arguments) {
30748
+ for (const arg of path2.node.arguments) {
30170
30749
  if (!t4.isExpression(arg)) continue;
30171
30750
  if (isStateRoot(arg)) {
30172
30751
  emitWarning(
@@ -30180,13 +30759,13 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
30180
30759
  }
30181
30760
  }
30182
30761
  },
30183
- OptionalMemberExpression(path) {
30184
- if (!path.node.computed) return;
30185
- if (path.parentPath.isAssignmentExpression({ left: path.node })) return;
30186
- if (path.parentPath.isUpdateExpression({ argument: path.node })) return;
30187
- if (isDynamicPropertyAccess(path.node, t4) && isStateRoot(path.node.object)) {
30762
+ OptionalMemberExpression(path2) {
30763
+ if (!path2.node.computed) return;
30764
+ if (path2.parentPath.isAssignmentExpression({ left: path2.node })) return;
30765
+ if (path2.parentPath.isUpdateExpression({ argument: path2.node })) return;
30766
+ if (isDynamicPropertyAccess(path2.node, t4) && isStateRoot(path2.node.object)) {
30188
30767
  emitWarning(
30189
- path.node,
30768
+ path2.node,
30190
30769
  "FICT-H",
30191
30770
  "Dynamic property access widens dependency tracking",
30192
30771
  warn,
@@ -30237,14 +30816,17 @@ function createHIREntrypointVisitor(t4, options) {
30237
30816
  };
30238
30817
  return {
30239
30818
  Program: {
30240
- exit(path) {
30241
- const fileName = path.hub?.file?.opts?.filename || "<unknown>";
30242
- const comments = path.hub?.file?.ast?.comments || [];
30819
+ exit(path2) {
30820
+ const fileName = path2.hub?.file?.opts?.filename || "<unknown>";
30821
+ const comments = path2.hub?.file?.ast?.comments || [];
30243
30822
  const suppressions = parseSuppressions(comments);
30244
30823
  const dev = options.dev !== false;
30245
- const warn = dev ? createWarningDispatcher(options.onWarn, suppressions) : () => {
30824
+ const warn = createWarningDispatcher(options.onWarn, suppressions, options, dev);
30825
+ const optionsWithWarnings = {
30826
+ ...options,
30827
+ onWarn: warn,
30828
+ filename: fileName
30246
30829
  };
30247
- const optionsWithWarnings = dev ? { ...options, onWarn: warn } : { ...options, onWarn: void 0 };
30248
30830
  const isHookName2 = (name) => !!name && /^use[A-Z]/.test(name);
30249
30831
  const getFunctionName = (fnPath) => {
30250
30832
  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;
@@ -30345,7 +30927,7 @@ function createHIREntrypointVisitor(t4, options) {
30345
30927
  };
30346
30928
  return checkNode(fn.body);
30347
30929
  };
30348
- path.traverse({
30930
+ path2.traverse({
30349
30931
  FunctionDeclaration(fnPath) {
30350
30932
  const name = fnPath.node.id?.name;
30351
30933
  if (!isComponentName2(name)) return;
@@ -30382,7 +30964,7 @@ function createHIREntrypointVisitor(t4, options) {
30382
30964
  const stateMacroNames = /* @__PURE__ */ new Set(["$state"]);
30383
30965
  const effectMacroNames = /* @__PURE__ */ new Set(["$effect"]);
30384
30966
  const memoMacroNames = /* @__PURE__ */ new Set(["$memo", "createMemo"]);
30385
- path.traverse({
30967
+ path2.traverse({
30386
30968
  ImportDeclaration(importPath) {
30387
30969
  if (importPath.node.source.value !== "fict" && importPath.node.source.value !== "fict/slim")
30388
30970
  return;
@@ -30402,7 +30984,7 @@ function createHIREntrypointVisitor(t4, options) {
30402
30984
  }
30403
30985
  }
30404
30986
  });
30405
- path.traverse({
30987
+ path2.traverse({
30406
30988
  JSXExpressionContainer(exprPath) {
30407
30989
  const expr = exprPath.node.expression;
30408
30990
  if (!t4.isCallExpression(expr)) return;
@@ -30447,7 +31029,7 @@ function createHIREntrypointVisitor(t4, options) {
30447
31029
  const stateVars = /* @__PURE__ */ new Set();
30448
31030
  const derivedVars = /* @__PURE__ */ new Set();
30449
31031
  const destructuredAliases = /* @__PURE__ */ new Set();
30450
- path.traverse({
31032
+ path2.traverse({
30451
31033
  VariableDeclarator(varPath) {
30452
31034
  const init = varPath.node.init;
30453
31035
  if (!init) return;
@@ -30696,7 +31278,7 @@ or extract the nested logic into a custom hook (useXxx).`
30696
31278
  return usesState;
30697
31279
  };
30698
31280
  debugLog("alias", "state vars", Array.from(stateVars));
30699
- path.traverse({
31281
+ path2.traverse({
30700
31282
  Function: {
30701
31283
  enter() {
30702
31284
  aliasStack.push(/* @__PURE__ */ new Set());
@@ -30754,7 +31336,7 @@ or extract the nested logic into a custom hook (useXxx).`
30754
31336
  }
30755
31337
  });
30756
31338
  if (derivedVars.size > 0) {
30757
- path.traverse({
31339
+ path2.traverse({
30758
31340
  AssignmentExpression(assignPath) {
30759
31341
  const { left } = assignPath.node;
30760
31342
  if (t4.isIdentifier(left) && derivedVars.has(left.name)) {
@@ -30775,7 +31357,7 @@ or extract the nested logic into a custom hook (useXxx).`
30775
31357
  });
30776
31358
  }
30777
31359
  if (destructuredAliases.size > 0) {
30778
- path.traverse({
31360
+ path2.traverse({
30779
31361
  AssignmentExpression(assignPath) {
30780
31362
  const { left } = assignPath.node;
30781
31363
  if (t4.isIdentifier(left) && destructuredAliases.has(left.name)) {
@@ -30803,10 +31385,11 @@ or extract the nested logic into a custom hook (useXxx).`
30803
31385
  }
30804
31386
  });
30805
31387
  }
30806
- if (dev) {
30807
- runWarningPass(path, stateVars, derivedVars, warn, fileName, t4);
31388
+ const shouldRunWarnings = dev || hasErrorEscalation(options);
31389
+ if (shouldRunWarnings) {
31390
+ runWarningPass(path2, stateVars, derivedVars, warn, fileName, t4);
30808
31391
  }
30809
- const fileAst = t4.file(path.node);
31392
+ const fileAst = t4.file(path2.node);
30810
31393
  const hir = buildHIR(
30811
31394
  fileAst,
30812
31395
  {
@@ -30821,19 +31404,20 @@ or extract the nested logic into a custom hook (useXxx).`
30821
31404
  );
30822
31405
  const optimized = optionsWithWarnings.optimize ? optimizeHIR(hir, {
30823
31406
  memoMacroNames,
30824
- inlineDerivedMemos: optionsWithWarnings.inlineDerivedMemos ?? true
31407
+ inlineDerivedMemos: optionsWithWarnings.inlineDerivedMemos ?? true,
31408
+ optimizeLevel: optionsWithWarnings.optimizeLevel ?? "safe"
30825
31409
  }) : hir;
30826
31410
  const lowered = lowerHIRWithRegions(optimized, t4, optionsWithWarnings, {
30827
31411
  state: stateMacroNames,
30828
31412
  effect: effectMacroNames,
30829
31413
  memo: memoMacroNames
30830
31414
  });
30831
- path.node.body = lowered.program.body;
30832
- path.node.directives = lowered.program.directives;
31415
+ path2.node.body = lowered.program.body;
31416
+ path2.node.directives = lowered.program.directives;
30833
31417
  if (!process.env.FICT_SKIP_SCOPE_CRAWL) {
30834
- path.scope.crawl();
31418
+ path2.scope.crawl();
30835
31419
  }
30836
- stripMacroImports(path, t4);
31420
+ stripMacroImports(path2, t4);
30837
31421
  }
30838
31422
  }
30839
31423
  };
@@ -30846,6 +31430,7 @@ var createFictPlugin = declare(
30846
31430
  ...options,
30847
31431
  fineGrainedDom: options.fineGrainedDom ?? true,
30848
31432
  optimize: options.optimize ?? true,
31433
+ optimizeLevel: options.optimizeLevel ?? "safe",
30849
31434
  inlineDerivedMemos: options.inlineDerivedMemos ?? true,
30850
31435
  dev: options.dev ?? (process.env.NODE_ENV !== "production" && process.env.NODE_ENV !== "test")
30851
31436
  };
@@ -30857,6 +31442,9 @@ var createFictPlugin = declare(
30857
31442
  );
30858
31443
  var index_default = createFictPlugin;
30859
31444
  export {
31445
+ clearModuleMetadata,
30860
31446
  createFictPlugin,
30861
- index_default as default
31447
+ index_default as default,
31448
+ resolveModuleMetadata,
31449
+ setModuleMetadata
30862
31450
  };