@hyperframes/lint 0.8.37 → 0.8.38

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
@@ -2843,10 +2843,6 @@ function targetHasNoStableIdentity(selector, identity) {
2843
2843
  if (identity) return false;
2844
2844
  return selector === UNRESOLVED_TARGET || selector === "dwell/hold" || selector.startsWith("proxy \u2192 ");
2845
2845
  }
2846
- function readRegisteredTimelineCompositionId(script) {
2847
- const match = script.match(WINDOW_TIMELINE_ASSIGN_PATTERN);
2848
- return match?.[1] || match?.[2] || null;
2849
- }
2850
2846
  function unwrapRaw(value) {
2851
2847
  if (typeof value === "number") return value;
2852
2848
  if (typeof value !== "string") return void 0;
@@ -3014,21 +3010,6 @@ function makesOverlayVisible(win) {
3014
3010
  if (win.method === "from" && isHiddenGsapState(win.propertyValues)) return true;
3015
3011
  return isVisibleGsapState(win.propertyValues);
3016
3012
  }
3017
- function isSceneBoundaryExit(win) {
3018
- if (win.end <= win.position) return false;
3019
- if (win.method !== "to" && win.method !== "fromTo") return false;
3020
- return isHiddenGsapState(win.propertyValues);
3021
- }
3022
- function isHardKillSet(win, selector, boundary) {
3023
- return win.method === "set" && win.targetSelector === selector && Math.abs(win.position - boundary) <= SCENE_BOUNDARY_EPSILON_SECONDS && isHiddenGsapState(win.propertyValues);
3024
- }
3025
- function hiddenStateLiteral(values) {
3026
- if (zeroValue(values.autoAlpha)) return "{ autoAlpha: 0 }";
3027
- if (zeroValue(values.opacity)) return "{ opacity: 0 }";
3028
- if (stringValue(values.visibility)?.toLowerCase() === "hidden") return '{ visibility: "hidden" }';
3029
- if (stringValue(values.display)?.toLowerCase() === "none") return '{ display: "none" }';
3030
- return "{ opacity: 0 }";
3031
- }
3032
3013
  function findTagEnd(source, tag) {
3033
3014
  const escapedTagName = tag.name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3034
3015
  const pattern = new RegExp(`<\\/?${escapedTagName}\\b[^>]*>`, "gi");
@@ -3045,56 +3026,11 @@ function findTagEnd(source, tag) {
3045
3026
  }
3046
3027
  return source.length;
3047
3028
  }
3048
- function collectCompositionRanges(source, tags) {
3049
- return tags.map((tag) => {
3050
- const id = readDecodedAttr(tag.raw, "data-composition-id");
3051
- if (!id) return null;
3052
- return {
3053
- id,
3054
- start: tag.index,
3055
- end: findTagEnd(source, tag)
3056
- };
3057
- }).filter((range) => range !== null);
3058
- }
3059
- function findContainingCompositionId(tag, ranges) {
3060
- let match = null;
3061
- for (const range of ranges) {
3062
- if (tag.index < range.start || tag.index >= range.end) continue;
3063
- if (!match || range.start >= match.start) match = range;
3064
- }
3065
- return match?.id || null;
3066
- }
3067
3029
  function getClipTagClasses(tag) {
3068
3030
  const classAttr = readAttr(tag.raw, "class") || "";
3069
3031
  const classes = classAttr.split(/\s+/).filter(Boolean);
3070
3032
  return classes.includes("clip") ? { classAttr, classes } : null;
3071
3033
  }
3072
- function collectClipStartBoundariesByComposition(source, tags) {
3073
- const ranges = collectCompositionRanges(source, tags);
3074
- const boundaries = /* @__PURE__ */ new Map();
3075
- for (const tag of tags) {
3076
- if (!getClipTagClasses(tag)) continue;
3077
- const compositionId = findContainingCompositionId(tag, ranges);
3078
- if (!compositionId) continue;
3079
- const start = numberValue(readAttr(tag.raw, "data-start") ?? void 0);
3080
- if (start == null || start <= 0) continue;
3081
- const compositionBoundaries = boundaries.get(compositionId) ?? /* @__PURE__ */ new Set();
3082
- compositionBoundaries.add(start);
3083
- boundaries.set(compositionId, compositionBoundaries);
3084
- }
3085
- return new Map(
3086
- [...boundaries.entries()].map(([compositionId, values]) => [
3087
- compositionId,
3088
- [...values].sort((a, b) => a - b)
3089
- ])
3090
- );
3091
- }
3092
- function findMatchingSceneBoundary(time, boundaries) {
3093
- for (const boundary of boundaries) {
3094
- if (Math.abs(time - boundary) <= SCENE_BOUNDARY_EPSILON_SECONDS) return boundary;
3095
- }
3096
- return null;
3097
- }
3098
3034
  function readStyleProperty(style, property) {
3099
3035
  const escapedProperty = property.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3100
3036
  const match = style.match(new RegExp(`(?:^|;)\\s*${escapedProperty}\\s*:\\s*([^;]+)`, "i"));
@@ -3593,7 +3529,7 @@ var gsapRules = [
3593
3529
  },
3594
3530
  // overlapping_gsap_tweens + gsap_animates_clip_element
3595
3531
  // fallow-ignore-next-line complexity
3596
- async ({ source, tags, scripts, styles, rootCompositionId }) => {
3532
+ async ({ tags, scripts, styles }) => {
3597
3533
  const findings = [];
3598
3534
  const authoredHiddenSelectors = new Set(
3599
3535
  scripts.flatMap((script) => [...extractStandaloneHiddenSelectors(script.content)])
@@ -3614,13 +3550,10 @@ var gsapRules = [
3614
3550
  if (cls !== "clip") clipClasses.set(`.${cls}`, info);
3615
3551
  }
3616
3552
  }
3617
- const clipStartBoundariesByComposition = collectClipStartBoundariesByComposition(source, tags);
3618
3553
  const styleRules = collectSimpleStyleRules(styles);
3619
3554
  const reportedVisibleOverlayKeys = /* @__PURE__ */ new Set();
3620
3555
  for (const script of scripts) {
3621
- const localTimelineCompId = readRegisteredTimelineCompositionId(script.content);
3622
3556
  const gsapWindows = await cachedExtractGsapWindows(script.content);
3623
- const clipStartBoundaries = clipStartBoundariesByComposition.get(localTimelineCompId || rootCompositionId || "") ?? [];
3624
3557
  for (let i = 0; i < gsapWindows.length; i++) {
3625
3558
  const left = gsapWindows[i];
3626
3559
  if (!left) continue;
@@ -3682,28 +3615,6 @@ ${right.raw}`)
3682
3615
  snippet: truncateSnippet(fromToWindows.map((win) => win.raw).join("\n"))
3683
3616
  });
3684
3617
  }
3685
- if (clipStartBoundaries.length > 0) {
3686
- for (const win of gsapWindows) {
3687
- if (win.targetSelector === UNRESOLVED_TARGET) continue;
3688
- if (!isSceneBoundaryExit(win)) continue;
3689
- const boundary = findMatchingSceneBoundary(win.end, clipStartBoundaries);
3690
- if (boundary == null) continue;
3691
- const hasHardKill = gsapWindows.some(
3692
- (candidate) => isHardKillSet(candidate, win.targetSelector, boundary)
3693
- );
3694
- if (hasHardKill) continue;
3695
- const exitClipInfo = clipIds.get(win.targetSelector) || clipClasses.get(win.targetSelector);
3696
- const fixHint = exitClipInfo ? `"${win.targetSelector}" is a clip element \u2014 the framework already manages its visibility. Wrap the scene's content in an inner non-clip <div>, move the exit tween and the hard kill (\`tl.set("<inner-selector>", ${hiddenStateLiteral(win.propertyValues)}, ${boundary.toFixed(2)})\`) onto that wrapper instead.` : `Add \`tl.set("${win.targetSelector}", ${hiddenStateLiteral(win.propertyValues)}, ${boundary.toFixed(2)})\` after the exit tween.`;
3697
- findings.push({
3698
- code: "gsap_exit_missing_hard_kill",
3699
- severity: "error",
3700
- message: `GSAP exit on "${win.targetSelector}" ends at the ${boundary.toFixed(2)}s clip start boundary without a matching tl.set hard kill. Non-linear seeking can land after the fade and leave stale visibility state.`,
3701
- selector: win.targetSelector,
3702
- fixHint,
3703
- snippet: truncateSnippet(win.raw)
3704
- });
3705
- }
3706
- }
3707
3618
  for (const tag of tags) {
3708
3619
  const selectors = tagSimpleSelectors(tag);
3709
3620
  if (selectors.length === 0) continue;