@hyperframes/parsers 0.7.24 → 0.7.26

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.
@@ -169,6 +169,49 @@ var SCOPE_NODE_TYPES = /* @__PURE__ */ new Set([
169
169
  "FunctionExpression",
170
170
  "ArrowFunctionExpression"
171
171
  ]);
172
+ var CONST_NODES = /* @__PURE__ */ Symbol("hf.constNodes");
173
+ function constNodesOf(scope) {
174
+ return scope[CONST_NODES];
175
+ }
176
+ var MATH_FNS = /* @__PURE__ */ new Set(["min", "max", "round", "floor", "ceil", "abs", "sqrt", "sign", "trunc"]);
177
+ var MATH_CONSTS = { PI: Math.PI, E: Math.E, SQRT2: Math.SQRT2 };
178
+ function resolveMemberNode(node, scope) {
179
+ if (node.object?.type === "Identifier" && node.object.name === "Math") {
180
+ const key = node.property?.name;
181
+ return typeof key === "string" ? MATH_CONSTS[key] : void 0;
182
+ }
183
+ const objNode = resolveConstNode(node.object, scope);
184
+ if (!objNode) return void 0;
185
+ let valueNode;
186
+ if (node.computed) {
187
+ const idx = resolveNode(node.property, scope);
188
+ if (objNode.type === "ArrayExpression" && typeof idx === "number") {
189
+ valueNode = objNode.elements?.[idx];
190
+ } else if (objNode.type === "ObjectExpression" && (typeof idx === "string" || typeof idx === "number")) {
191
+ valueNode = findPropertyNode(objNode, String(idx));
192
+ }
193
+ } else if (objNode.type === "ObjectExpression") {
194
+ valueNode = findPropertyNode(objNode, node.property?.name ?? node.property?.value);
195
+ }
196
+ return valueNode ? resolveNode(valueNode, scope) : void 0;
197
+ }
198
+ function resolveConstMember(objNode, node, scope) {
199
+ if (!node.computed) {
200
+ return objNode.type === "ObjectExpression" ? findPropertyNode(objNode, node.property?.name ?? node.property?.value) : void 0;
201
+ }
202
+ const idx = resolveNode(node.property, scope);
203
+ if (objNode.type === "ArrayExpression" && typeof idx === "number") return objNode.elements?.[idx];
204
+ if (objNode.type === "ObjectExpression") return findPropertyNode(objNode, String(idx));
205
+ return void 0;
206
+ }
207
+ function resolveConstNode(node, scope) {
208
+ if (!node) return void 0;
209
+ if (node.type === "ArrayExpression" || node.type === "ObjectExpression") return node;
210
+ if (node.type === "Identifier") return constNodesOf(scope)?.get(node.name);
211
+ if (node.type !== "MemberExpression") return void 0;
212
+ const objNode = resolveConstNode(node.object, scope);
213
+ return objNode ? resolveConstMember(objNode, node, scope) : void 0;
214
+ }
172
215
  function resolveNode(node, scope) {
173
216
  if (!node) return void 0;
174
217
  if (node.type === "NumericLiteral" || node.type === "Literal" && typeof node.value === "number")
@@ -205,6 +248,15 @@ function resolveNode(node, scope) {
205
248
  if (node.type === "TemplateLiteral" && node.expressions?.length === 0) {
206
249
  return node.quasis?.[0]?.value?.cooked ?? void 0;
207
250
  }
251
+ if (node.type === "MemberExpression") {
252
+ return resolveMemberNode(node, scope);
253
+ }
254
+ if (node.type === "CallExpression" && node.callee?.type === "MemberExpression" && node.callee.object?.type === "Identifier" && node.callee.object.name === "Math" && MATH_FNS.has(node.callee.property?.name)) {
255
+ const args = (node.arguments ?? []).map((a) => resolveNode(a, scope));
256
+ if (args.every((a) => typeof a === "number")) {
257
+ return Math[node.callee.property.name](...args);
258
+ }
259
+ }
208
260
  return void 0;
209
261
  }
210
262
  function extractLiteralValue(node, scope) {
@@ -262,14 +314,19 @@ function resolveCollectionSelector(node, ancestors, scope, bindings) {
262
314
  }
263
315
  function collectScopeBindings(ast) {
264
316
  const bindings = /* @__PURE__ */ new Map();
317
+ const constNodes = /* @__PURE__ */ new Map();
318
+ Object.defineProperty(bindings, CONST_NODES, { value: constNodes, enumerable: false });
265
319
  acornWalk.simple(ast, {
266
320
  VariableDeclarator(node) {
267
321
  const name = node.id?.name;
268
322
  const init = node.init;
269
- if (name && init) {
270
- const val = resolveNode(init, bindings);
271
- if (val !== void 0) bindings.set(name, val);
323
+ if (!name || !init) return;
324
+ if (init.type === "ArrayExpression" || init.type === "ObjectExpression") {
325
+ constNodes.set(name, init);
326
+ return;
272
327
  }
328
+ const val = resolveNode(init, bindings);
329
+ if (val !== void 0) bindings.set(name, val);
273
330
  }
274
331
  });
275
332
  return bindings;
@@ -311,6 +368,25 @@ function collectTargetBindings(ast, scope) {
311
368
  }
312
369
  }
313
370
  });
371
+ const COLLECTION_ALIAS_METHODS = /* @__PURE__ */ new Set(["slice", "filter", "concat", "reverse"]);
372
+ acornWalk.ancestor(ast, {
373
+ // fallow-ignore-next-line complexity
374
+ VariableDeclarator(node, _, ancestors) {
375
+ const name = node.id?.name;
376
+ const init = node.init;
377
+ if (!name || !init) return;
378
+ let sourceVar;
379
+ if (init.type === "MemberExpression" && init.object?.type === "Identifier") {
380
+ sourceVar = init.object.name;
381
+ } else if (init.type === "CallExpression" && init.callee?.type === "MemberExpression" && init.callee.object?.type === "Identifier" && init.callee.property?.type === "Identifier" && COLLECTION_ALIAS_METHODS.has(init.callee.property.name)) {
382
+ sourceVar = init.callee.object.name;
383
+ }
384
+ if (!sourceVar) return;
385
+ const selector = lookupBindingFromAncestors(sourceVar, ancestors, bindings);
386
+ if (selector)
387
+ addBinding(bindings, enclosingScopeNodeFromAncestors(ancestors), name, selector);
388
+ }
389
+ });
314
390
  return bindings;
315
391
  }
316
392
  function resolveTargetSelector(node, ancestors, scope, bindings) {
@@ -333,6 +409,32 @@ function resolveTargetSelector(node, ancestors, scope, bindings) {
333
409
  }
334
410
  return null;
335
411
  }
412
+ function describeProxyTarget(targetNode, varsNode, scope) {
413
+ const objNode = targetNode?.type === "ObjectExpression" ? targetNode : targetNode?.type === "Identifier" ? resolveConstNode(targetNode, scope) : void 0;
414
+ if (objNode?.type !== "ObjectExpression") return null;
415
+ const onUpdate = findPropertyNode(varsNode, "onUpdate");
416
+ const driven = onUpdate ? drivenDomChannel(onUpdate) : void 0;
417
+ if (driven) return `proxy \u2192 ${driven}`;
418
+ return "dwell/hold";
419
+ }
420
+ function isStyleAssignmentTarget(left) {
421
+ return left?.type === "MemberExpression" && left.object?.type === "MemberExpression" && left.object.property?.name === "style" && !!left.property?.name;
422
+ }
423
+ function drivenDomChannel(fnNode) {
424
+ let found;
425
+ acornWalk.simple(fnNode, {
426
+ CallExpression(node) {
427
+ if (node.callee?.type === "MemberExpression" && node.callee.property?.name === "setAttribute" && typeof node.arguments?.[0]?.value === "string") {
428
+ found ??= node.arguments[0].value;
429
+ }
430
+ },
431
+ AssignmentExpression(node) {
432
+ const left = node.left;
433
+ if (isStyleAssignmentTarget(left)) found ??= `style.${left.property.name}`;
434
+ }
435
+ });
436
+ return found;
437
+ }
336
438
  function isObjectProperty(prop) {
337
439
  return prop?.type === "ObjectProperty" || prop?.type === "Property";
338
440
  }
@@ -798,8 +900,13 @@ function tweenCallToAnimation(call, scope, source) {
798
900
  if (duration === void 0 && keyframesData) {
799
901
  duration = computeKeyframesTotalDuration(call.varsArg, scope, source);
800
902
  }
903
+ let selector = call.selector;
904
+ if (selector === "__unresolved__") {
905
+ const proxyLabel = describeProxyTarget(call.node.arguments?.[0], call.varsArg, scope);
906
+ if (proxyLabel) selector = proxyLabel;
907
+ }
801
908
  const anim = {
802
- targetSelector: call.selector,
909
+ targetSelector: selector,
803
910
  method: call.method,
804
911
  position,
805
912
  properties,
@@ -822,7 +929,7 @@ function tweenCallToAnimation(call, scope, source) {
822
929
  if (keyframesData) anim.keyframes = keyframesData;
823
930
  if (motionPathResult) anim.arcPath = motionPathResult.arcPath;
824
931
  if (hasUnresolvedKeyframes) anim.hasUnresolvedKeyframes = true;
825
- if (call.selector === "__unresolved__") anim.hasUnresolvedSelector = true;
932
+ if (selector === "__unresolved__") anim.hasUnresolvedSelector = true;
826
933
  const provenance = readProvenance(call.node);
827
934
  if (provenance) anim.provenance = provenance;
828
935
  return anim;
@@ -864,31 +971,61 @@ function applyTimelineDefaults(anims, defaults) {
864
971
  }
865
972
  }
866
973
  }
867
- function resolveTimelinePositions(anims) {
974
+ function resolveLabelPosition(pos, labels, cursor) {
975
+ const m = /^([A-Za-z_$][\w$]*)\s*(?:([+-])=\s*([\d.]+))?$/.exec(pos.trim());
976
+ if (!m) return null;
977
+ const name = m[1];
978
+ let base = labels.get(name);
979
+ if (base === void 0) {
980
+ base = cursor;
981
+ labels.set(name, base);
982
+ }
983
+ if (m[2] && m[3]) {
984
+ const n = Number.parseFloat(m[3]);
985
+ if (Number.isFinite(n)) return m[2] === "+" ? base + n : base - n;
986
+ }
987
+ return base;
988
+ }
989
+ function resolveAnimStart(anim, cursor, prevStart, labels) {
990
+ if (anim.implicitPosition) return cursor;
991
+ if (typeof anim.position === "number") return anim.position;
992
+ if (typeof anim.position === "string") {
993
+ return resolveLabelPosition(anim.position, labels, cursor) ?? resolvePositionString(anim.position, cursor, prevStart);
994
+ }
995
+ return cursor;
996
+ }
997
+ function resolveTimelinePositions(anims, labelDefs = []) {
868
998
  let cursor = 0;
869
999
  let prevStart = 0;
870
- for (const anim of anims) {
1000
+ const labels = /* @__PURE__ */ new Map();
1001
+ let labelIdx = 0;
1002
+ const sortedLabels = [...labelDefs].sort((a, b) => a.order - b.order);
1003
+ const defineLabel = (def) => {
1004
+ let value;
1005
+ if (typeof def.position === "number") value = def.position;
1006
+ else if (typeof def.position === "string") {
1007
+ value = resolveLabelPosition(def.position, labels, cursor) ?? cursor;
1008
+ } else value = cursor;
1009
+ labels.set(def.name, Math.max(0, value));
1010
+ };
1011
+ anims.forEach((anim, i) => {
1012
+ while (labelIdx < sortedLabels.length && sortedLabels[labelIdx].order <= i) {
1013
+ defineLabel(sortedLabels[labelIdx]);
1014
+ labelIdx++;
1015
+ }
871
1016
  if (anim.method === "set" && anim.global) {
872
1017
  anim.resolvedStart = 0;
873
- continue;
1018
+ return;
874
1019
  }
875
1020
  const duration = anim.method === "set" ? 0 : anim.duration ?? GSAP_DEFAULT_DURATION;
876
- let start;
877
- if (anim.implicitPosition) {
878
- start = cursor;
879
- } else if (typeof anim.position === "number") {
880
- start = anim.position;
881
- } else if (typeof anim.position === "string") {
882
- start = resolvePositionString(anim.position, cursor, prevStart);
883
- } else {
884
- start = cursor;
885
- }
1021
+ const start = resolveAnimStart(anim, cursor, prevStart, labels);
886
1022
  if (start != null) {
887
1023
  anim.resolvedStart = Math.max(0, start);
888
1024
  prevStart = anim.resolvedStart;
889
1025
  cursor = Math.max(cursor, anim.resolvedStart + duration);
890
1026
  }
891
- }
1027
+ });
1028
+ while (labelIdx < sortedLabels.length) defineLabel(sortedLabels[labelIdx++]);
892
1029
  }
893
1030
  function compareByLoc(a, b) {
894
1031
  const aLoc = a.node.callee?.property?.loc?.start;
@@ -1651,12 +1788,12 @@ function removeKeyframeFromScript(script, animationId, percentage) {
1651
1788
  return ms.toString();
1652
1789
  }
1653
1790
  function moveKeyframeInScript(script, animationId, fromPercentage, toPercentage) {
1654
- const located = locateWithKeyframes(script, animationId);
1791
+ const located = ensureKeyframesNode(script, animationId);
1655
1792
  if (!located) return script;
1656
- const { kfNode } = located;
1793
+ const { script: src, kfNode } = located;
1657
1794
  const match = findKfPropByPct(kfNode, fromPercentage);
1658
- if (!match) return script;
1659
- if (Math.abs(fromPercentage - toPercentage) < MOVE_NOOP_EPSILON_PCT) return script;
1795
+ if (!match) return src;
1796
+ if (Math.abs(fromPercentage - toPercentage) < MOVE_NOOP_EPSILON_PCT) return src;
1660
1797
  const dest = findKfPropByPct(kfNode, toPercentage);
1661
1798
  const collision = dest && dest.prop !== match.prop ? dest : null;
1662
1799
  const entries = [];
@@ -1665,19 +1802,19 @@ function moveKeyframeInScript(script, animationId, fromPercentage, toPercentage)
1665
1802
  if (collision && prop === collision.prop) continue;
1666
1803
  const pct = percentageFromKey(propKeyName2(prop) ?? "");
1667
1804
  if (Number.isNaN(pct)) continue;
1668
- entries.push({ pct, record: valueNodeToRecord(prop.value, script) });
1805
+ entries.push({ pct, record: valueNodeToRecord(prop.value, src) });
1669
1806
  }
1670
- entries.push({ pct: toPercentage, record: valueNodeToRecord(match.prop.value, script) });
1807
+ entries.push({ pct: toPercentage, record: valueNodeToRecord(match.prop.value, src) });
1671
1808
  entries.sort((a, b) => a.pct - b.pct);
1672
1809
  const body = entries.map((e) => `${JSON.stringify(`${e.pct}%`)}: ${recordToCode(e.record)}`).join(", ");
1673
- const ms = new MagicString(script);
1810
+ const ms = new MagicString(src);
1674
1811
  ms.overwrite(kfNode.start, kfNode.end, `{ ${body} }`);
1675
1812
  return ms.toString();
1676
1813
  }
1677
1814
  function resizeKeyframedTweenInScript(script, animationId, newPosition, newDuration, pctRemap) {
1678
- const located = locateWithKeyframes(script, animationId);
1815
+ const located = ensureKeyframesNode(script, animationId);
1679
1816
  if (!located) return script;
1680
- const { target, kfNode } = located;
1817
+ const { script: src, target, kfNode } = located;
1681
1818
  const edits = [];
1682
1819
  const seen = /* @__PURE__ */ new Set();
1683
1820
  for (const { from, to } of pctRemap) {
@@ -1686,7 +1823,7 @@ function resizeKeyframedTweenInScript(script, animationId, newPosition, newDurat
1686
1823
  seen.add(match.prop.key);
1687
1824
  edits.push({ keyNode: match.prop.key, to });
1688
1825
  }
1689
- const ms = new MagicString(script);
1826
+ const ms = new MagicString(src);
1690
1827
  for (const { keyNode, to } of edits) {
1691
1828
  ms.overwrite(keyNode.start, keyNode.end, JSON.stringify(`${to}%`));
1692
1829
  }