@hyperframes/parsers 0.8.30 → 0.8.32

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.
@@ -557,19 +557,82 @@ function addBinding(bindings, scopeNode, name, selector) {
557
557
  }
558
558
  if (!scoped.has(name)) scoped.set(name, selector);
559
559
  }
560
- function collectTargetBindings(ast, scope) {
560
+ function directHelperReturn(node) {
561
+ if (node.type === "ArrowFunctionExpression" && node.body?.type !== "BlockStatement") {
562
+ return node.body;
563
+ }
564
+ if (!isFunctionNode(node) || node.body?.type !== "BlockStatement") return null;
565
+ const returns = (node.body.body ?? []).filter(
566
+ (statement) => statement.type === "ReturnStatement" && statement.argument
567
+ );
568
+ return returns.length === 1 ? returns[0].argument : null;
569
+ }
570
+ function collectTargetHelpers(ast) {
571
+ const helpers = /* @__PURE__ */ new Map();
572
+ const add = (scopeNode, name, fn) => {
573
+ const returnNode = directHelperReturn(fn);
574
+ const params = (fn.params ?? []).filter((param) => param.type === "Identifier").map((param) => param.name);
575
+ if (!returnNode || params.length !== (fn.params?.length ?? 0)) return;
576
+ let scoped = helpers.get(scopeNode);
577
+ if (!scoped) {
578
+ scoped = /* @__PURE__ */ new Map();
579
+ helpers.set(scopeNode, scoped);
580
+ }
581
+ if (!scoped.has(name)) scoped.set(name, { params, returnNode });
582
+ };
583
+ recast.types.visit(ast, {
584
+ visitFunctionDeclaration(path) {
585
+ const name = path.node.id?.name;
586
+ const scopeNode = enclosingScopeNode(path);
587
+ if (name && scopeNode) add(scopeNode, name, path.node);
588
+ this.traverse(path);
589
+ },
590
+ visitVariableDeclarator(path) {
591
+ const name = path.node.id?.name;
592
+ const fn = path.node.init;
593
+ const scopeNode = enclosingScopeNode(path);
594
+ if (name && fn && isFunctionNode(fn) && scopeNode) add(scopeNode, name, fn);
595
+ this.traverse(path);
596
+ }
597
+ });
598
+ return helpers;
599
+ }
600
+ function lookupTargetHelper(name, path, helpers) {
601
+ for (const scopeNode of scopeChainOf(path)) {
602
+ const helper = helpers.get(scopeNode)?.get(name);
603
+ if (helper) return helper;
604
+ }
605
+ return null;
606
+ }
607
+ function selectorFromTargetCall(node, path, scope, helpers) {
608
+ const direct = selectorFromQueryCall(node, scope);
609
+ if (direct) return direct;
610
+ if (node?.type !== "CallExpression" || node.callee?.type !== "Identifier") return null;
611
+ const helper = lookupTargetHelper(node.callee.name, path, helpers);
612
+ if (!helper || helper.params.length !== (node.arguments?.length ?? 0)) return null;
613
+ const helperScope = new Map(scope);
614
+ for (let i = 0; i < helper.params.length; i += 1) {
615
+ const param = helper.params[i];
616
+ if (!param) return null;
617
+ const value = resolveNode(node.arguments[i], scope);
618
+ if (value === void 0) return null;
619
+ helperScope.set(param, value);
620
+ }
621
+ return selectorFromQueryCall(helper.returnNode, helperScope);
622
+ }
623
+ function collectTargetBindings(ast, scope, helpers) {
561
624
  const bindings = /* @__PURE__ */ new Map();
562
625
  recast.types.visit(ast, {
563
626
  visitVariableDeclarator(path) {
564
627
  const name = path.node.id?.name;
565
- const selector = selectorFromQueryCall(path.node.init, scope);
628
+ const selector = selectorFromTargetCall(path.node.init, path, scope, helpers);
566
629
  const scopeNode = enclosingScopeNode(path);
567
630
  if (name && selector !== null && scopeNode) addBinding(bindings, scopeNode, name, selector);
568
631
  this.traverse(path);
569
632
  },
570
633
  visitAssignmentExpression(path) {
571
634
  const left = path.node.left;
572
- const selector = selectorFromQueryCall(path.node.right, scope);
635
+ const selector = selectorFromTargetCall(path.node.right, path, scope, helpers);
573
636
  const scopeNode = enclosingScopeNode(path);
574
637
  if (left?.type === "Identifier" && selector !== null && scopeNode) {
575
638
  addBinding(bindings, scopeNode, left.name, selector);
@@ -609,7 +672,7 @@ function lookupBinding(name, path, bindings) {
609
672
  }
610
673
  return null;
611
674
  }
612
- function resolveTargetSelector(node, path, scope, bindings) {
675
+ function resolveTargetSelector(node, path, scope, bindings, helpers) {
613
676
  if (!node) return null;
614
677
  if (node.type === "StringLiteral" || node.type === "Literal") {
615
678
  return typeof node.value === "string" ? node.value : null;
@@ -618,10 +681,10 @@ function resolveTargetSelector(node, path, scope, bindings) {
618
681
  return lookupBinding(node.name, path, bindings);
619
682
  }
620
683
  if (node.type === "CallExpression") {
621
- return selectorFromQueryCall(node, scope);
684
+ return selectorFromTargetCall(node, path, scope, helpers);
622
685
  }
623
686
  if (node.type === "ArrayExpression") {
624
- const parts = node.elements.map((el) => resolveTargetSelector(el, path, scope, bindings)).filter((s) => typeof s === "string" && s.length > 0);
687
+ const parts = node.elements.map((el) => resolveTargetSelector(el, path, scope, bindings, helpers)).filter((s) => typeof s === "string" && s.length > 0);
625
688
  return parts.length > 0 ? parts.join(", ") : null;
626
689
  }
627
690
  if (node.type === "MemberExpression" && node.object?.type === "Identifier") {
@@ -736,7 +799,7 @@ function isTimelineRootedCall(callNode, ref) {
736
799
  if (ref.kind === "identifier") return obj?.type === "Identifier" && obj.name === ref.name;
737
800
  return sameMemberAccess(obj, ref.node);
738
801
  }
739
- function findAllTweenCalls(ast, ref, scope, targetBindings) {
802
+ function findAllTweenCalls(ast, ref, scope, targetBindings, targetHelpers) {
740
803
  const results = [];
741
804
  recast.types.visit(ast, {
742
805
  visitCallExpression(path) {
@@ -755,7 +818,7 @@ function findAllTweenCalls(ast, ref, scope, targetBindings) {
755
818
  this.traverse(path);
756
819
  return;
757
820
  }
758
- const selectorValue = resolveTargetSelector(args[0], path, scope, targetBindings) ?? "__unresolved__";
821
+ const selectorValue = resolveTargetSelector(args[0], path, scope, targetBindings, targetHelpers) ?? "__unresolved__";
759
822
  if (method === "fromTo") {
760
823
  results.push({
761
824
  path,
@@ -1208,11 +1271,12 @@ function assignStableIds(anims) {
1208
1271
  function parseGsapAst(script) {
1209
1272
  const ast = parseScript(script);
1210
1273
  const scope = collectScopeBindings(ast);
1211
- const targetBindings = collectTargetBindings(ast, scope);
1274
+ const targetHelpers = collectTargetHelpers(ast);
1275
+ const targetBindings = collectTargetBindings(ast, scope, targetHelpers);
1212
1276
  const detection = findTimelineVar(ast, scope);
1213
1277
  const ref = detection.ref ?? { kind: "identifier", name: "tl" };
1214
1278
  const timelineVar = timelineRootSource(ref);
1215
- const calls = findAllTweenCalls(ast, ref, scope, targetBindings);
1279
+ const calls = findAllTweenCalls(ast, ref, scope, targetBindings, targetHelpers);
1216
1280
  sortBySourcePosition(calls);
1217
1281
  const rawAnims = calls.map((call) => tweenCallToAnimation(call, scope));
1218
1282
  applyTimelineDefaults(rawAnims, detection.defaults);