@hyperframes/parsers 0.7.92 → 0.7.94

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
@@ -607,8 +607,79 @@ function containsTimelineCall(node, timelineVar) {
607
607
  function rangeOf(node) {
608
608
  return typeof node.start === "number" && typeof node.end === "number" ? [node.start, node.end] : void 0;
609
609
  }
610
+ var SAFE_DEFAULT_NODES = /* @__PURE__ */ new Set([
611
+ "ArrayExpression",
612
+ "BinaryExpression",
613
+ "ChainExpression",
614
+ "ConditionalExpression",
615
+ "Identifier",
616
+ "Literal",
617
+ "LogicalExpression",
618
+ "MemberExpression",
619
+ "ObjectExpression",
620
+ "Property",
621
+ "SpreadElement",
622
+ "TemplateElement",
623
+ "TemplateLiteral",
624
+ "UnaryExpression"
625
+ ]);
626
+ function isSafeDefaultExpression(node, earlierParams) {
627
+ let safe = true;
628
+ const visit = (current, parent, key) => {
629
+ if (!isNode(current) || !safe) return;
630
+ if (!SAFE_DEFAULT_NODES.has(current.type)) {
631
+ safe = false;
632
+ return;
633
+ }
634
+ if (current.type === "UnaryExpression" && current.operator === "delete") {
635
+ safe = false;
636
+ return;
637
+ }
638
+ if (current.type === "Identifier") {
639
+ const nonValue = parent && key ? isNonValueIdentifierSlot(parent, key) : false;
640
+ if (!nonValue && current.name !== "undefined" && !earlierParams.has(current.name)) {
641
+ safe = false;
642
+ }
643
+ return;
644
+ }
645
+ for (const childKey of Object.keys(current)) {
646
+ if (SKIP_KEYS.has(childKey)) continue;
647
+ const child = current[childKey];
648
+ if (Array.isArray(child)) {
649
+ for (const item of child) visit(item, current, childKey);
650
+ } else {
651
+ visit(child, current, childKey);
652
+ }
653
+ }
654
+ };
655
+ visit(node);
656
+ return safe;
657
+ }
658
+ var SUPPORTED_PARAMS_CACHE = /* @__PURE__ */ new WeakMap();
659
+ function supportedParam(param, earlier) {
660
+ if (param.type === "Identifier") return { name: param.name };
661
+ if (param.type !== "AssignmentPattern" || param.left?.type !== "Identifier") return null;
662
+ if (!isSafeDefaultExpression(param.right, earlier)) return null;
663
+ return { name: param.left.name, defaultExpression: param.right };
664
+ }
665
+ function supportedParams(fn) {
666
+ if (SUPPORTED_PARAMS_CACHE.has(fn)) return SUPPORTED_PARAMS_CACHE.get(fn) ?? null;
667
+ const params = [];
668
+ const earlier = /* @__PURE__ */ new Set();
669
+ for (const param of fn.params ?? []) {
670
+ const parsed = supportedParam(param, earlier);
671
+ if (!parsed) {
672
+ SUPPORTED_PARAMS_CACHE.set(fn, null);
673
+ return null;
674
+ }
675
+ params.push(parsed);
676
+ earlier.add(parsed.name);
677
+ }
678
+ SUPPORTED_PARAMS_CACHE.set(fn, params);
679
+ return params;
680
+ }
610
681
  function isShapeEligible(fn) {
611
- return isFunctionNode(fn) && fn.body?.type === "BlockStatement" && !(fn.params ?? []).some((p) => p.type !== "Identifier");
682
+ return isFunctionNode(fn) && fn.body?.type === "BlockStatement" && supportedParams(fn) !== null;
612
683
  }
613
684
  function callsAny(node, names) {
614
685
  let hit = false;
@@ -658,20 +729,55 @@ function timelineBuildingNames(candidates, timelineVar) {
658
729
  function bump(counts, key) {
659
730
  counts.set(key, (counts.get(key) ?? 0) + 1);
660
731
  }
732
+ function undefinedIdentifier() {
733
+ return { type: "Identifier", name: "undefined" };
734
+ }
735
+ function isExplicitUndefined(node) {
736
+ return node?.type === "Identifier" && node.name === "undefined" || node?.type === "UnaryExpression" && node.operator === "void" && node.argument?.type === "Literal" && node.argument.value === 0;
737
+ }
738
+ function resolveHelperBindings(call, params) {
739
+ if (call.arguments?.some((arg) => arg?.type === "SpreadElement")) return null;
740
+ const bindings = /* @__PURE__ */ new Map();
741
+ for (let i = 0; i < params.length; i++) {
742
+ const param = params[i];
743
+ const arg = call.arguments?.[i];
744
+ if (arg && !isExplicitUndefined(arg)) {
745
+ bindings.set(param.name, arg);
746
+ } else if (param.defaultExpression) {
747
+ bindings.set(param.name, substituteParams(cloneNode(param.defaultExpression), bindings));
748
+ } else {
749
+ bindings.set(param.name, undefinedIdentifier());
750
+ }
751
+ }
752
+ return bindings;
753
+ }
754
+ function statementHelperCall(node, names) {
755
+ if (node.type !== "ExpressionStatement") return void 0;
756
+ const expression = node.expression;
757
+ if (expression?.type !== "CallExpression" || expression.callee?.type !== "Identifier") {
758
+ return void 0;
759
+ }
760
+ return names.has(expression.callee.name) ? expression : void 0;
761
+ }
661
762
  function safelyDroppable(program, candidates) {
662
763
  const names = new Set(candidates.keys());
663
764
  const totalIds = /* @__PURE__ */ new Map();
664
765
  const stmtCalls = /* @__PURE__ */ new Map();
766
+ const unbindable = /* @__PURE__ */ new Set();
665
767
  walkNodes(program, (n) => {
666
768
  if (n.type === "Identifier" && names.has(n.name)) bump(totalIds, n.name);
667
- const e = n.type === "ExpressionStatement" ? n.expression : void 0;
668
- if (e?.type === "CallExpression" && e.callee?.type === "Identifier" && names.has(e.callee.name)) {
669
- bump(stmtCalls, e.callee.name);
670
- }
769
+ const call = statementHelperCall(n, names);
770
+ if (!call) return;
771
+ bump(stmtCalls, call.callee.name);
772
+ const fn = candidates.get(call.callee.name);
773
+ const params = fn && supportedParams(fn);
774
+ if (!params || !resolveHelperBindings(call, params)) unbindable.add(call.callee.name);
671
775
  });
672
776
  const safe = /* @__PURE__ */ new Map();
673
777
  for (const [name, fn] of candidates) {
674
- if ((totalIds.get(name) ?? 0) === 1 + (stmtCalls.get(name) ?? 0)) safe.set(name, fn);
778
+ if (!unbindable.has(name) && (totalIds.get(name) ?? 0) === 1 + (stmtCalls.get(name) ?? 0)) {
779
+ safe.set(name, fn);
780
+ }
675
781
  }
676
782
  return safe;
677
783
  }
@@ -714,11 +820,11 @@ function expandBody(bodyStmts, bindings, prov, ctx) {
714
820
  }
715
821
  function inlineHelper(call, ctx) {
716
822
  const fn = ctx.helpers.get(call.callee.name);
717
- const bindings = /* @__PURE__ */ new Map();
718
- (fn.params ?? []).forEach((p, i) => {
719
- const arg = call.arguments?.[i];
720
- if (arg) bindings.set(p.name, arg);
721
- });
823
+ if (!fn) return null;
824
+ const params = supportedParams(fn);
825
+ if (!params) return null;
826
+ const bindings = resolveHelperBindings(call, params);
827
+ if (!bindings) return null;
722
828
  const prov = {
723
829
  kind: "helper",
724
830
  fn: call.callee.name,