@hyperframes/parsers 0.7.15 → 0.7.16
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/gsapParser.js +76 -25
- package/dist/gsapParser.js.map +1 -1
- package/dist/gsapParserAcorn.js +67 -27
- package/dist/gsapParserAcorn.js.map +1 -1
- package/dist/gsapParserExports.js +60 -22
- package/dist/gsapParserExports.js.map +1 -1
- package/dist/gsapWriterAcorn.js +70 -26
- package/dist/gsapWriterAcorn.js.map +1 -1
- package/dist/index.js +64 -25
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/gsapParser.js
CHANGED
|
@@ -572,6 +572,35 @@ function objectExpressionToRecord(node, scope) {
|
|
|
572
572
|
function isGsapTimelineCall(node) {
|
|
573
573
|
return node?.type === "CallExpression" && node.callee?.type === "MemberExpression" && node.callee.object?.name === "gsap" && node.callee.property?.name === "timeline";
|
|
574
574
|
}
|
|
575
|
+
function staticMemberKey(node) {
|
|
576
|
+
if (!node || node.type !== "MemberExpression") return null;
|
|
577
|
+
if (node.computed) {
|
|
578
|
+
const p = node.property;
|
|
579
|
+
if (p?.type === "StringLiteral") return p.value;
|
|
580
|
+
if (p?.type === "Literal" && typeof p.value === "string") return p.value;
|
|
581
|
+
return null;
|
|
582
|
+
}
|
|
583
|
+
return node.property?.type === "Identifier" ? node.property.name : null;
|
|
584
|
+
}
|
|
585
|
+
function isStaticMemberRef(node) {
|
|
586
|
+
return node?.type === "MemberExpression" && staticMemberKey(node) !== null;
|
|
587
|
+
}
|
|
588
|
+
function sameMemberAccess(a, b) {
|
|
589
|
+
if (a?.type !== "MemberExpression" || b?.type !== "MemberExpression") return false;
|
|
590
|
+
if (staticMemberKey(a) !== staticMemberKey(b) || staticMemberKey(a) === null) return false;
|
|
591
|
+
const ao = a.object;
|
|
592
|
+
const bo = b.object;
|
|
593
|
+
if (ao?.type === "Identifier" && bo?.type === "Identifier") return ao.name === bo.name;
|
|
594
|
+
if (ao?.type === "MemberExpression" && bo?.type === "MemberExpression")
|
|
595
|
+
return sameMemberAccess(ao, bo);
|
|
596
|
+
return false;
|
|
597
|
+
}
|
|
598
|
+
function timelineRootSource(ref) {
|
|
599
|
+
return ref.kind === "identifier" ? ref.name : recast.print(ref.node).code;
|
|
600
|
+
}
|
|
601
|
+
function escapeRegExp(s) {
|
|
602
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
603
|
+
}
|
|
575
604
|
function extractTimelineDefaults(callNode, scope) {
|
|
576
605
|
const arg = callNode.arguments?.[0];
|
|
577
606
|
if (!arg || arg.type !== "ObjectExpression") return void 0;
|
|
@@ -587,6 +616,7 @@ function extractTimelineDefaults(callNode, scope) {
|
|
|
587
616
|
}
|
|
588
617
|
function findTimelineVar(ast, scope) {
|
|
589
618
|
let timelineVar = null;
|
|
619
|
+
let ref = null;
|
|
590
620
|
let timelineCount = 0;
|
|
591
621
|
let defaults;
|
|
592
622
|
const emptyScope = scope ?? /* @__PURE__ */ new Map();
|
|
@@ -594,8 +624,9 @@ function findTimelineVar(ast, scope) {
|
|
|
594
624
|
visitVariableDeclarator(path) {
|
|
595
625
|
if (isGsapTimelineCall(path.node.init)) {
|
|
596
626
|
timelineCount += 1;
|
|
597
|
-
if (!
|
|
598
|
-
timelineVar = path.node.id
|
|
627
|
+
if (!ref && path.node.id?.type === "Identifier") {
|
|
628
|
+
timelineVar = path.node.id.name;
|
|
629
|
+
ref = { kind: "identifier", name: path.node.id.name };
|
|
599
630
|
defaults = extractTimelineDefaults(path.node.init, emptyScope);
|
|
600
631
|
}
|
|
601
632
|
}
|
|
@@ -604,25 +635,32 @@ function findTimelineVar(ast, scope) {
|
|
|
604
635
|
visitAssignmentExpression(path) {
|
|
605
636
|
if (isGsapTimelineCall(path.node.right)) {
|
|
606
637
|
timelineCount += 1;
|
|
607
|
-
if (!
|
|
638
|
+
if (!ref) {
|
|
608
639
|
const left = path.node.left;
|
|
609
|
-
if (left?.type === "Identifier")
|
|
610
|
-
|
|
640
|
+
if (left?.type === "Identifier") {
|
|
641
|
+
timelineVar = left.name;
|
|
642
|
+
ref = { kind: "identifier", name: left.name };
|
|
643
|
+
defaults = extractTimelineDefaults(path.node.right, emptyScope);
|
|
644
|
+
} else if (isStaticMemberRef(left)) {
|
|
645
|
+
ref = { kind: "member", node: left };
|
|
646
|
+
defaults = extractTimelineDefaults(path.node.right, emptyScope);
|
|
647
|
+
}
|
|
611
648
|
}
|
|
612
649
|
}
|
|
613
650
|
this.traverse(path);
|
|
614
651
|
}
|
|
615
652
|
});
|
|
616
|
-
return { timelineVar, timelineCount, defaults };
|
|
653
|
+
return { timelineVar, ref, timelineCount, defaults };
|
|
617
654
|
}
|
|
618
|
-
function isTimelineRootedCall(callNode,
|
|
655
|
+
function isTimelineRootedCall(callNode, ref) {
|
|
619
656
|
let obj = callNode.callee?.object;
|
|
620
657
|
while (obj?.type === "CallExpression") {
|
|
621
658
|
obj = obj.callee?.object;
|
|
622
659
|
}
|
|
623
|
-
return obj?.type === "Identifier" && obj.name ===
|
|
660
|
+
if (ref.kind === "identifier") return obj?.type === "Identifier" && obj.name === ref.name;
|
|
661
|
+
return sameMemberAccess(obj, ref.node);
|
|
624
662
|
}
|
|
625
|
-
function findAllTweenCalls(ast,
|
|
663
|
+
function findAllTweenCalls(ast, ref, scope, targetBindings) {
|
|
626
664
|
const results = [];
|
|
627
665
|
recast.types.visit(ast, {
|
|
628
666
|
visitCallExpression(path) {
|
|
@@ -630,7 +668,7 @@ function findAllTweenCalls(ast, timelineVar, scope, targetBindings) {
|
|
|
630
668
|
const callee = node.callee;
|
|
631
669
|
const gsapSetArg = node.arguments?.[0];
|
|
632
670
|
const isGlobalSet = callee?.type === "MemberExpression" && callee.object?.type === "Identifier" && callee.object.name === "gsap" && callee.property?.type === "Identifier" && callee.property.name === "set" && (gsapSetArg?.type === "StringLiteral" || gsapSetArg?.type === "Literal" && typeof gsapSetArg.value === "string");
|
|
633
|
-
if (callee?.type === "MemberExpression" && callee.property?.type === "Identifier" && (isTimelineRootedCall(node,
|
|
671
|
+
if (callee?.type === "MemberExpression" && callee.property?.type === "Identifier" && (isTimelineRootedCall(node, ref) || isGlobalSet)) {
|
|
634
672
|
const method = callee.property.name;
|
|
635
673
|
if (!GSAP_METHODS.has(method)) {
|
|
636
674
|
this.traverse(path);
|
|
@@ -1108,8 +1146,9 @@ function parseGsapAst(script) {
|
|
|
1108
1146
|
const scope = collectScopeBindings(ast);
|
|
1109
1147
|
const targetBindings = collectTargetBindings(ast, scope);
|
|
1110
1148
|
const detection = findTimelineVar(ast, scope);
|
|
1111
|
-
const
|
|
1112
|
-
const
|
|
1149
|
+
const ref = detection.ref ?? { kind: "identifier", name: "tl" };
|
|
1150
|
+
const timelineVar = timelineRootSource(ref);
|
|
1151
|
+
const calls = findAllTweenCalls(ast, ref, scope, targetBindings);
|
|
1113
1152
|
sortBySourcePosition(calls);
|
|
1114
1153
|
const rawAnims = calls.map((call) => tweenCallToAnimation(call, scope));
|
|
1115
1154
|
applyTimelineDefaults(rawAnims, detection.defaults);
|
|
@@ -1125,13 +1164,12 @@ function parseGsapAst(script) {
|
|
|
1125
1164
|
function parseGsapScript(script) {
|
|
1126
1165
|
try {
|
|
1127
1166
|
const { detection, timelineVar, located } = parseGsapAst(script);
|
|
1167
|
+
const ref = detection.ref ?? { kind: "identifier", name: "tl" };
|
|
1128
1168
|
const animations = located.map((l) => l.animation);
|
|
1129
|
-
const
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
);
|
|
1134
|
-
const preamble = timelineMatch?.[0] ?? `const ${timelineVar} = gsap.timeline({ paused: true });`;
|
|
1169
|
+
const declPattern = ref.kind === "identifier" ? `(?:const|let|var)\\s+${timelineVar}\\s*=\\s*gsap\\.timeline\\s*\\([^)]*\\)\\s*;?` : `${escapeRegExp(timelineVar)}\\s*=\\s*gsap\\.timeline\\s*\\([^)]*\\)\\s*;?`;
|
|
1170
|
+
const timelineMatch = script.match(new RegExp(`^[\\s\\S]*?${declPattern}`));
|
|
1171
|
+
const fallbackPreamble = ref.kind === "identifier" ? `const ${timelineVar} = gsap.timeline({ paused: true });` : `${timelineVar} = gsap.timeline({ paused: true });`;
|
|
1172
|
+
const preamble = timelineMatch?.[0] ?? fallbackPreamble;
|
|
1135
1173
|
const lastCallIdx = script.lastIndexOf(`${timelineVar}.`);
|
|
1136
1174
|
let postamble = "";
|
|
1137
1175
|
if (lastCallIdx !== -1) {
|
|
@@ -1143,7 +1181,7 @@ function parseGsapScript(script) {
|
|
|
1143
1181
|
}
|
|
1144
1182
|
const result = { animations, timelineVar, preamble, postamble };
|
|
1145
1183
|
if (detection.timelineCount > 1) result.multipleTimelines = true;
|
|
1146
|
-
if (detection.timelineCount > 0 && detection.
|
|
1184
|
+
if (detection.timelineCount > 0 && detection.ref === null)
|
|
1147
1185
|
result.unsupportedTimelinePattern = true;
|
|
1148
1186
|
return result;
|
|
1149
1187
|
} catch {
|
|
@@ -1355,7 +1393,7 @@ function addAnimationToScript(script, animation) {
|
|
|
1355
1393
|
console.warn("[gsap-parser] addAnimationToScript parse failed:", e);
|
|
1356
1394
|
return { script, id: "" };
|
|
1357
1395
|
}
|
|
1358
|
-
if (parsed.located.length === 0 && parsed.detection.
|
|
1396
|
+
if (parsed.located.length === 0 && parsed.detection.ref === null) {
|
|
1359
1397
|
return { script, id: "" };
|
|
1360
1398
|
}
|
|
1361
1399
|
const id = `anim-${Date.now()}`;
|
|
@@ -1372,7 +1410,7 @@ function addAnimationWithKeyframesToScript(script, targetSelector, position, dur
|
|
|
1372
1410
|
console.warn("[gsap-parser] addAnimationWithKeyframesToScript parse failed:", e);
|
|
1373
1411
|
return { script, id: "" };
|
|
1374
1412
|
}
|
|
1375
|
-
if (parsed.located.length === 0 && parsed.detection.
|
|
1413
|
+
if (parsed.located.length === 0 && parsed.detection.ref === null) {
|
|
1376
1414
|
return { script, id: "" };
|
|
1377
1415
|
}
|
|
1378
1416
|
const selector = JSON.stringify(targetSelector);
|
|
@@ -1889,9 +1927,9 @@ function updateKeyframeInScript(script, animationId, percentage, properties, eas
|
|
|
1889
1927
|
const match = findKeyframePropByPct(kfNode, percentage);
|
|
1890
1928
|
if (!match) return script;
|
|
1891
1929
|
if (Object.keys(properties).length === 0 && ease) {
|
|
1892
|
-
const
|
|
1893
|
-
if (
|
|
1894
|
-
const props =
|
|
1930
|
+
const existing2 = match.prop.value;
|
|
1931
|
+
if (existing2?.type === "ObjectExpression") {
|
|
1932
|
+
const props = existing2.properties ?? [];
|
|
1895
1933
|
const easeIdx = props.findIndex(
|
|
1896
1934
|
(p) => isObjectProperty(p) && propKeyName(p) === "ease"
|
|
1897
1935
|
);
|
|
@@ -1905,6 +1943,19 @@ function updateKeyframeInScript(script, animationId, percentage, properties, eas
|
|
|
1905
1943
|
}
|
|
1906
1944
|
return script;
|
|
1907
1945
|
}
|
|
1946
|
+
const existing = match.prop.value;
|
|
1947
|
+
if (existing?.type === "ObjectExpression") {
|
|
1948
|
+
const props = existing.properties ?? [];
|
|
1949
|
+
const upsert = (key, valueCode) => {
|
|
1950
|
+
const idx = props.findIndex((p) => isObjectProperty(p) && propKeyName(p) === key);
|
|
1951
|
+
const node = parseExpr(`({ ${safeJsKey(key)}: ${valueCode} })`).properties[0];
|
|
1952
|
+
if (idx >= 0) props[idx] = node;
|
|
1953
|
+
else props.push(node);
|
|
1954
|
+
};
|
|
1955
|
+
for (const [k, v] of Object.entries(properties)) upsert(k, serializeValue(v));
|
|
1956
|
+
if (ease !== void 0) upsert("ease", JSON.stringify(ease));
|
|
1957
|
+
return recast.print(loc.parsed.ast).code;
|
|
1958
|
+
}
|
|
1908
1959
|
match.prop.value = buildKeyframeValueNode(properties, ease);
|
|
1909
1960
|
return recast.print(loc.parsed.ast).code;
|
|
1910
1961
|
}
|
|
@@ -2210,7 +2261,7 @@ function addMotionPathToScript(script, targetSelector, position, duration, point
|
|
|
2210
2261
|
console.warn("[gsap-parser] addMotionPathToScript parse failed:", e);
|
|
2211
2262
|
return { script, id: null };
|
|
2212
2263
|
}
|
|
2213
|
-
if (parsed.located.length === 0 && parsed.detection.
|
|
2264
|
+
if (parsed.located.length === 0 && parsed.detection.ref === null) {
|
|
2214
2265
|
return { script, id: null };
|
|
2215
2266
|
}
|
|
2216
2267
|
const motionPathCode = buildMotionPathObjectCode({
|