@hyperframes/parsers 0.9.28-alpha.1 → 0.9.28

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.
@@ -1,3 +1,4 @@
1
+ import * as acorn from 'acorn';
1
2
  import { P as ParsedGsap, d as GsapMethod, G as GsapAnimation } from './gsapSerialize-BXsRZWdm.js';
2
3
  export { A as ArcPathConfig, a as ArcPathSegment, n as GsapProvenance, o as GsapProvenanceKind, K as KeyframeEditability, M as MotionPathShape, p as buildArcPath, q as editabilityForProvenance } from './gsapSerialize-BXsRZWdm.js';
3
4
  import './types-C1bWHQbs.js';
@@ -8,6 +9,37 @@ import './types-C1bWHQbs.js';
8
9
  */
9
10
  declare function scriptShape(code: string, maskNumbers?: boolean): string | null;
10
11
 
12
+ /**
13
+ * Browser-safe GSAP read path — acorn + acorn-walk.
14
+ *
15
+ * T6b oracle: produces identical ParsedGsap output to gsapParser.ts (recast).
16
+ * Replaces recast as the shared implementation once T6d passes.
17
+ *
18
+ * Write path (T6c) will add magic-string splice once read parity is confirmed.
19
+ * No Node globals, no fs, no require — safe to bundle for browser use.
20
+ */
21
+
22
+ interface TimelineDefaults {
23
+ ease?: string;
24
+ duration?: number;
25
+ durationUnresolved?: boolean;
26
+ }
27
+ type TimelineRef = {
28
+ kind: "identifier";
29
+ name: string;
30
+ } | {
31
+ kind: "member";
32
+ node: any;
33
+ };
34
+ interface TimelineDetection {
35
+ /** Identifier name for the canonical form, else null for member/none. */
36
+ timelineVar: string | null;
37
+ /** Structural reference: identifier or member expression. Null when none found. */
38
+ ref: TimelineRef | null;
39
+ timelineCount: number;
40
+ defaults?: TimelineDefaults;
41
+ declaration?: Pick<acorn.Node, "start" | "end">;
42
+ }
11
43
  interface TweenCallInfo {
12
44
  node: any;
13
45
  /** acorn-walk ancestor array at the call site (root→call, call is last). */
@@ -25,6 +57,7 @@ interface ParsedGsapAcornForWrite {
25
57
  ast: any;
26
58
  timelineVar: string;
27
59
  hasTimeline: boolean;
60
+ timelineDeclaration?: TimelineDetection["declaration"];
28
61
  located: Array<{
29
62
  id: string;
30
63
  call: TweenCallInfo;
@@ -1170,6 +1170,7 @@ function findTimelineVar(ast, scope) {
1170
1170
  let ref = null;
1171
1171
  let timelineCount = 0;
1172
1172
  let defaults;
1173
+ let declaration;
1173
1174
  const emptyScope = scope ?? /* @__PURE__ */ new Map();
1174
1175
  acornWalk.simple(ast, {
1175
1176
  VariableDeclarator(node) {
@@ -1179,6 +1180,7 @@ function findTimelineVar(ast, scope) {
1179
1180
  timelineVar = node.id.name;
1180
1181
  ref = { kind: "identifier", name: node.id.name };
1181
1182
  defaults = extractTimelineDefaults(node.init, emptyScope);
1183
+ declaration = { start: node.start, end: node.end };
1182
1184
  }
1183
1185
  }
1184
1186
  },
@@ -1195,11 +1197,12 @@ function findTimelineVar(ast, scope) {
1195
1197
  ref = { kind: "member", node: left };
1196
1198
  defaults = extractTimelineDefaults(node.right, emptyScope);
1197
1199
  }
1200
+ if (ref) declaration = { start: node.start, end: node.end };
1198
1201
  }
1199
1202
  }
1200
1203
  }
1201
1204
  });
1202
- return { timelineVar, ref, timelineCount, defaults };
1205
+ return { timelineVar, ref, timelineCount, defaults, declaration };
1203
1206
  }
1204
1207
  function isTimelineRootedCall(callNode, ref) {
1205
1208
  let obj = callNode.callee?.object;
@@ -1903,7 +1906,13 @@ function parseGsapScriptAcornForWrite(script) {
1903
1906
  call,
1904
1907
  animation: animations[i]
1905
1908
  }));
1906
- return { ast, timelineVar, hasTimeline: detection.ref !== null, located };
1909
+ return {
1910
+ ast,
1911
+ timelineVar,
1912
+ hasTimeline: detection.ref !== null,
1913
+ timelineDeclaration: detection.declaration,
1914
+ located
1915
+ };
1907
1916
  } catch {
1908
1917
  return null;
1909
1918
  }
@@ -3,6 +3,7 @@ export { isStudioHoldSet } from './gsapParser.js';
3
3
  export { SPRING_PRESETS, SpringPreset, generateSpringEaseData } from './springEase.js';
4
4
  export { parseGsapScriptAcorn as parseGsapScript } from './gsapParserAcorn.js';
5
5
  import './types-C1bWHQbs.js';
6
+ import 'acorn';
6
7
 
7
8
  interface ObjectArrayKeyframeTiming {
8
9
  percentages: number[];
@@ -1461,6 +1461,7 @@ function findTimelineVar(ast, scope) {
1461
1461
  let ref = null;
1462
1462
  let timelineCount = 0;
1463
1463
  let defaults;
1464
+ let declaration;
1464
1465
  const emptyScope = scope ?? /* @__PURE__ */ new Map();
1465
1466
  acornWalk.simple(ast, {
1466
1467
  VariableDeclarator(node) {
@@ -1470,6 +1471,7 @@ function findTimelineVar(ast, scope) {
1470
1471
  timelineVar = node.id.name;
1471
1472
  ref = { kind: "identifier", name: node.id.name };
1472
1473
  defaults = extractTimelineDefaults(node.init, emptyScope);
1474
+ declaration = { start: node.start, end: node.end };
1473
1475
  }
1474
1476
  }
1475
1477
  },
@@ -1486,11 +1488,12 @@ function findTimelineVar(ast, scope) {
1486
1488
  ref = { kind: "member", node: left };
1487
1489
  defaults = extractTimelineDefaults(node.right, emptyScope);
1488
1490
  }
1491
+ if (ref) declaration = { start: node.start, end: node.end };
1489
1492
  }
1490
1493
  }
1491
1494
  }
1492
1495
  });
1493
- return { timelineVar, ref, timelineCount, defaults };
1496
+ return { timelineVar, ref, timelineCount, defaults, declaration };
1494
1497
  }
1495
1498
  function isTimelineRootedCall(callNode, ref) {
1496
1499
  let obj = callNode.callee?.object;
@@ -55,6 +55,7 @@ declare function addAnimationToScript(script: string, animation: Omit<GsapAnimat
55
55
  script: string;
56
56
  id: string;
57
57
  };
58
+ declare function removeAnimationsForSelectors(script: string, selectors: ReadonlySet<string>): string;
58
59
  declare function removeAnimationFromScript(script: string, animationId: string): string;
59
60
  /**
60
61
  * Enforce "exactly one position write per element". Position commits (drag, add
@@ -200,4 +201,4 @@ type UnrollElement = {
200
201
  */
201
202
  declare function unrollDynamicAnimations(script: string, animationId: string, elements: UnrollElement[]): string;
202
203
 
203
- export { type ClipTweenRetime, type UnrollElement, addAnimationToScript, addAnimationWithKeyframesToScript, addKeyframeToScript, addLabelToScript, addMotionPathPointInScript, addMotionPathToScript, clipQueryRoot, clipTweenMatcher, convertToKeyframesFromScript, copyAnimationsInScript, dedupePositionWritesInScript, hasExplicitTime, materializeKeyframesFromScript, moveKeyframeInScript, removeAllKeyframesFromScript, removeAnimationFromScript, removeArcPathFromScript, removeKeyframeFromScript, removeLabelFromScript, removeMotionPathPointInScript, removePropertyFromAnimation, replaceTweenWithKeyframesInScript, resizeKeyframedTweenInScript, retimeClipTweensInScript, scalePositionsInScript, setArcPathInScript, shiftPositionsInScript, splitAnimationsInScript, splitIntoPropertyGroupsFromScript, syncPositionHoldsBeforeKeyframes, trimTrailingKeyframeSpans, unrollDynamicAnimations, updateAnimationInScript, updateArcSegmentInScript, updateKeyframeInScript, updateMotionPathPointInScript };
204
+ export { type ClipTweenRetime, type UnrollElement, addAnimationToScript, addAnimationWithKeyframesToScript, addKeyframeToScript, addLabelToScript, addMotionPathPointInScript, addMotionPathToScript, clipQueryRoot, clipTweenMatcher, convertToKeyframesFromScript, copyAnimationsInScript, dedupePositionWritesInScript, hasExplicitTime, materializeKeyframesFromScript, moveKeyframeInScript, removeAllKeyframesFromScript, removeAnimationFromScript, removeAnimationsForSelectors, removeArcPathFromScript, removeKeyframeFromScript, removeLabelFromScript, removeMotionPathPointInScript, removePropertyFromAnimation, replaceTweenWithKeyframesInScript, resizeKeyframedTweenInScript, retimeClipTweensInScript, scalePositionsInScript, setArcPathInScript, shiftPositionsInScript, splitAnimationsInScript, splitIntoPropertyGroupsFromScript, syncPositionHoldsBeforeKeyframes, trimTrailingKeyframeSpans, unrollDynamicAnimations, updateAnimationInScript, updateArcSegmentInScript, updateKeyframeInScript, updateMotionPathPointInScript };
@@ -784,6 +784,7 @@ function findTimelineVar(ast, scope) {
784
784
  let ref = null;
785
785
  let timelineCount = 0;
786
786
  let defaults;
787
+ let declaration;
787
788
  const emptyScope = scope ?? /* @__PURE__ */ new Map();
788
789
  acornWalk.simple(ast, {
789
790
  VariableDeclarator(node) {
@@ -793,6 +794,7 @@ function findTimelineVar(ast, scope) {
793
794
  timelineVar = node.id.name;
794
795
  ref = { kind: "identifier", name: node.id.name };
795
796
  defaults = extractTimelineDefaults(node.init, emptyScope);
797
+ declaration = { start: node.start, end: node.end };
796
798
  }
797
799
  }
798
800
  },
@@ -809,11 +811,12 @@ function findTimelineVar(ast, scope) {
809
811
  ref = { kind: "member", node: left };
810
812
  defaults = extractTimelineDefaults(node.right, emptyScope);
811
813
  }
814
+ if (ref) declaration = { start: node.start, end: node.end };
812
815
  }
813
816
  }
814
817
  }
815
818
  });
816
- return { timelineVar, ref, timelineCount, defaults };
819
+ return { timelineVar, ref, timelineCount, defaults, declaration };
817
820
  }
818
821
  function isTimelineRootedCall(callNode, ref) {
819
822
  let obj = callNode.callee?.object;
@@ -1420,7 +1423,13 @@ function parseGsapScriptAcornForWrite(script) {
1420
1423
  call,
1421
1424
  animation: animations[i]
1422
1425
  }));
1423
- return { ast, timelineVar, hasTimeline: detection.ref !== null, located };
1426
+ return {
1427
+ ast,
1428
+ timelineVar,
1429
+ hasTimeline: detection.ref !== null,
1430
+ timelineDeclaration: detection.declaration,
1431
+ located
1432
+ };
1424
1433
  } catch {
1425
1434
  return null;
1426
1435
  }
@@ -1873,12 +1882,62 @@ function removeCallFromMagicString(ms, call, script) {
1873
1882
  const N = call.node;
1874
1883
  const exprStmt = findEnclosingExpressionStatement(call.ancestors);
1875
1884
  if (N.callee?.object?.type !== "CallExpression" && exprStmt?.expression === N) {
1876
- const end = exprStmt.end < script.length && script[exprStmt.end] === "\n" ? exprStmt.end + 1 : exprStmt.end;
1877
- ms.remove(exprStmt.start, end);
1885
+ removeStatementFromMagicString(ms, exprStmt, script);
1878
1886
  } else {
1879
1887
  ms.remove(N.callee.object.end, N.end);
1880
1888
  }
1881
1889
  }
1890
+ function removeStatementFromMagicString(ms, statement, script) {
1891
+ const end = statement.end + (script[statement.end] === "\n" ? 1 : 0);
1892
+ ms.remove(statement.start, end);
1893
+ }
1894
+ function removeAnimationsForSelectors(script, selectors) {
1895
+ let current = script;
1896
+ for (; ; ) {
1897
+ const parsed = parseGsapScriptAcornForWrite(current);
1898
+ if (!parsed) return current;
1899
+ const selected = parsed.located.filter(
1900
+ ({ animation }) => selectors.has(animation.targetSelector)
1901
+ );
1902
+ const first = selected[0];
1903
+ if (!first) return current;
1904
+ const declaration = parsed.timelineDeclaration;
1905
+ if (declaration && selected.some(
1906
+ ({ call }) => call.node.start <= declaration.start && call.node.end >= declaration.end
1907
+ )) {
1908
+ const updated = removeAnimationFromScript(current, first.id);
1909
+ if (updated === current) return current;
1910
+ current = updated;
1911
+ continue;
1912
+ }
1913
+ return removeCallsFromScript(
1914
+ current,
1915
+ selected.map(({ call }) => call)
1916
+ );
1917
+ }
1918
+ }
1919
+ function removeCallsFromScript(script, calls) {
1920
+ const removedNodes = new Set(calls.map(({ node }) => node));
1921
+ const statements = /* @__PURE__ */ new Set();
1922
+ for (const call of calls) {
1923
+ const statement = fullyRemovedStatement(call, removedNodes);
1924
+ if (statement) statements.add(statement);
1925
+ }
1926
+ const ms = new MagicString(script);
1927
+ for (const statement of statements) removeStatementFromMagicString(ms, statement, script);
1928
+ for (const call of calls) {
1929
+ if (statements.has(findEnclosingExpressionStatement(call.ancestors))) continue;
1930
+ removeCallFromMagicString(ms, call, script);
1931
+ }
1932
+ return ms.toString();
1933
+ }
1934
+ function fullyRemovedStatement(call, removedNodes) {
1935
+ const statement = findEnclosingExpressionStatement(call.ancestors);
1936
+ if (statement?.expression !== call.node) return null;
1937
+ let root = call.node;
1938
+ while (root?.type === "CallExpression" && removedNodes.has(root)) root = root.callee.object;
1939
+ return root && root.type !== "CallExpression" ? statement : null;
1940
+ }
1882
1941
  function removeAnimationFromScript(script, animationId) {
1883
1942
  const parsed = parseGsapScriptAcornForWrite(script);
1884
1943
  if (!parsed) return script;
@@ -3368,6 +3427,7 @@ export {
3368
3427
  moveKeyframeInScript,
3369
3428
  removeAllKeyframesFromScript,
3370
3429
  removeAnimationFromScript,
3430
+ removeAnimationsForSelectors,
3371
3431
  removeArcPathFromScript,
3372
3432
  removeKeyframeFromScript,
3373
3433
  removeLabelFromScript,
package/dist/index.d.ts CHANGED
@@ -14,6 +14,7 @@ export { AttrReader, DEFAULT_IMAGE_TIMELINE_DURATION_SECONDS, MAX_PLAYBACK_RATE,
14
14
  export { CompositionDurationResult, CompositionDurationSource, ResolveCompositionDurationInput, TIMING_TOLERANCE_SECONDS, resolveCompositionDuration } from './compositionDuration.js';
15
15
  export { d as decodeUrlPathVariants, c as decodedUrlPath, e as encodeUrlPath } from './urlPath-CYK47t9W.js';
16
16
  export { HTML_ATTRIBUTE_ENTITIES, HtmlAttributeSpan, HtmlOpeningTagSpan, decodeAuthoredAttribute, scanHtmlOpeningTags } from './htmlAttributeSpans.js';
17
+ import 'acorn';
17
18
 
18
19
  /**
19
20
  * Thrown by htmlParser functions when the input HTML is empty or does not
package/dist/index.js CHANGED
@@ -1578,6 +1578,7 @@ function findTimelineVar(ast, scope) {
1578
1578
  let ref = null;
1579
1579
  let timelineCount = 0;
1580
1580
  let defaults;
1581
+ let declaration;
1581
1582
  const emptyScope = scope ?? /* @__PURE__ */ new Map();
1582
1583
  acornWalk.simple(ast, {
1583
1584
  VariableDeclarator(node) {
@@ -1587,6 +1588,7 @@ function findTimelineVar(ast, scope) {
1587
1588
  timelineVar = node.id.name;
1588
1589
  ref = { kind: "identifier", name: node.id.name };
1589
1590
  defaults = extractTimelineDefaults(node.init, emptyScope);
1591
+ declaration = { start: node.start, end: node.end };
1590
1592
  }
1591
1593
  }
1592
1594
  },
@@ -1603,11 +1605,12 @@ function findTimelineVar(ast, scope) {
1603
1605
  ref = { kind: "member", node: left };
1604
1606
  defaults = extractTimelineDefaults(node.right, emptyScope);
1605
1607
  }
1608
+ if (ref) declaration = { start: node.start, end: node.end };
1606
1609
  }
1607
1610
  }
1608
1611
  }
1609
1612
  });
1610
- return { timelineVar, ref, timelineCount, defaults };
1613
+ return { timelineVar, ref, timelineCount, defaults, declaration };
1611
1614
  }
1612
1615
  function isTimelineRootedCall(callNode, ref) {
1613
1616
  let obj = callNode.callee?.object;
@@ -2311,7 +2314,13 @@ function parseGsapScriptAcornForWrite(script) {
2311
2314
  call,
2312
2315
  animation: animations[i]
2313
2316
  }));
2314
- return { ast, timelineVar, hasTimeline: detection.ref !== null, located };
2317
+ return {
2318
+ ast,
2319
+ timelineVar,
2320
+ hasTimeline: detection.ref !== null,
2321
+ timelineDeclaration: detection.declaration,
2322
+ located
2323
+ };
2315
2324
  } catch {
2316
2325
  return null;
2317
2326
  }
@@ -2708,12 +2717,62 @@ function removeCallFromMagicString(ms, call, script) {
2708
2717
  const N = call.node;
2709
2718
  const exprStmt = findEnclosingExpressionStatement(call.ancestors);
2710
2719
  if (N.callee?.object?.type !== "CallExpression" && exprStmt?.expression === N) {
2711
- const end = exprStmt.end < script.length && script[exprStmt.end] === "\n" ? exprStmt.end + 1 : exprStmt.end;
2712
- ms.remove(exprStmt.start, end);
2720
+ removeStatementFromMagicString(ms, exprStmt, script);
2713
2721
  } else {
2714
2722
  ms.remove(N.callee.object.end, N.end);
2715
2723
  }
2716
2724
  }
2725
+ function removeStatementFromMagicString(ms, statement, script) {
2726
+ const end = statement.end + (script[statement.end] === "\n" ? 1 : 0);
2727
+ ms.remove(statement.start, end);
2728
+ }
2729
+ function removeAnimationsForSelectors(script, selectors) {
2730
+ let current = script;
2731
+ for (; ; ) {
2732
+ const parsed = parseGsapScriptAcornForWrite(current);
2733
+ if (!parsed) return current;
2734
+ const selected = parsed.located.filter(
2735
+ ({ animation }) => selectors.has(animation.targetSelector)
2736
+ );
2737
+ const first = selected[0];
2738
+ if (!first) return current;
2739
+ const declaration = parsed.timelineDeclaration;
2740
+ if (declaration && selected.some(
2741
+ ({ call }) => call.node.start <= declaration.start && call.node.end >= declaration.end
2742
+ )) {
2743
+ const updated = removeAnimationFromScript(current, first.id);
2744
+ if (updated === current) return current;
2745
+ current = updated;
2746
+ continue;
2747
+ }
2748
+ return removeCallsFromScript(
2749
+ current,
2750
+ selected.map(({ call }) => call)
2751
+ );
2752
+ }
2753
+ }
2754
+ function removeCallsFromScript(script, calls) {
2755
+ const removedNodes = new Set(calls.map(({ node }) => node));
2756
+ const statements = /* @__PURE__ */ new Set();
2757
+ for (const call of calls) {
2758
+ const statement = fullyRemovedStatement(call, removedNodes);
2759
+ if (statement) statements.add(statement);
2760
+ }
2761
+ const ms = new MagicString(script);
2762
+ for (const statement of statements) removeStatementFromMagicString(ms, statement, script);
2763
+ for (const call of calls) {
2764
+ if (statements.has(findEnclosingExpressionStatement(call.ancestors))) continue;
2765
+ removeCallFromMagicString(ms, call, script);
2766
+ }
2767
+ return ms.toString();
2768
+ }
2769
+ function fullyRemovedStatement(call, removedNodes) {
2770
+ const statement = findEnclosingExpressionStatement(call.ancestors);
2771
+ if (statement?.expression !== call.node) return null;
2772
+ let root = call.node;
2773
+ while (root?.type === "CallExpression" && removedNodes.has(root)) root = root.callee.object;
2774
+ return root && root.type !== "CallExpression" ? statement : null;
2775
+ }
2717
2776
  function removeAnimationFromScript(script, animationId) {
2718
2777
  const parsed = parseGsapScriptAcornForWrite(script);
2719
2778
  if (!parsed) return script;
@@ -3542,19 +3601,10 @@ function removeElementWithGsapCascade(doc, element) {
3542
3601
  });
3543
3602
  if (removedSelectors.size === 0) return;
3544
3603
  for (const script of findScriptElementsDeep(doc)) {
3545
- let current = script.textContent ?? "";
3604
+ const current = script.textContent ?? "";
3546
3605
  if (!current.includes("gsap") && !current.includes("ScrollTrigger")) continue;
3547
- for (; ; ) {
3548
- const parsed = parseGsapScriptAcornForWrite(current);
3549
- const match = parsed?.located.find(
3550
- (located) => removedSelectors.has(located.animation.targetSelector)
3551
- );
3552
- if (!match) break;
3553
- const updated = removeAnimationFromScript(current, match.id);
3554
- if (updated === current) break;
3555
- current = updated;
3556
- }
3557
- if (current !== script.textContent) script.textContent = current;
3606
+ const updated = removeAnimationsForSelectors(current, removedSelectors);
3607
+ if (updated !== current) script.textContent = updated;
3558
3608
  }
3559
3609
  }
3560
3610
  function removeElementFromHtml(html, elementId) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperframes/parsers",
3
- "version": "0.9.28-alpha.1",
3
+ "version": "0.9.28",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/heygen-com/hyperframes",
@@ -139,7 +139,7 @@
139
139
  "tsx": "^4.21.0",
140
140
  "typescript": "^5.0.0",
141
141
  "vitest": "^4.1.11",
142
- "@hyperframes/core": "0.9.28-alpha.1"
142
+ "@hyperframes/core": "0.9.28"
143
143
  },
144
144
  "scripts": {
145
145
  "build": "tsup",