@hyperframes/lint 0.8.194 → 0.8.195
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/browser.js +173 -20
- package/dist/index.js +173 -20
- package/package.json +2 -2
package/dist/browser.js
CHANGED
|
@@ -2709,6 +2709,7 @@ function containingCallOffset(script, tokenOffset) {
|
|
|
2709
2709
|
}
|
|
2710
2710
|
|
|
2711
2711
|
// src/rules/composition.ts
|
|
2712
|
+
import selectorParser2 from "postcss-selector-parser";
|
|
2712
2713
|
import {
|
|
2713
2714
|
COMPOSITION_VARIABLE_TYPES,
|
|
2714
2715
|
isCompositionVariable,
|
|
@@ -2876,12 +2877,154 @@ function firstRescalingZoom(css) {
|
|
|
2876
2877
|
}
|
|
2877
2878
|
return null;
|
|
2878
2879
|
}
|
|
2879
|
-
function
|
|
2880
|
+
function canvasScopeCandidate(selector, root) {
|
|
2880
2881
|
const leftmost = selector.trim().split(/[\s>+~]+/)[0] ?? "";
|
|
2881
|
-
|
|
2882
|
-
if (
|
|
2883
|
-
|
|
2884
|
-
|
|
2882
|
+
if (["html", "body", ":root", "*"].includes(leftmost.toLowerCase())) return true;
|
|
2883
|
+
if (root.id && leftmostCompoundId(selector) === root.id) return true;
|
|
2884
|
+
return leftmostCompoundClasses(selector).some((name) => root.classes.includes(name));
|
|
2885
|
+
}
|
|
2886
|
+
function canvasIdentity(tag) {
|
|
2887
|
+
return {
|
|
2888
|
+
name: tag.name,
|
|
2889
|
+
raw: tag.raw,
|
|
2890
|
+
id: readDecodedAttr(tag.raw, "id"),
|
|
2891
|
+
classes: (readDecodedAttr(tag.raw, "class") ?? "").split(/[\t\n\f\r ]+/)
|
|
2892
|
+
};
|
|
2893
|
+
}
|
|
2894
|
+
function anyCanvasMatch(matches) {
|
|
2895
|
+
if (matches.includes(true)) return true;
|
|
2896
|
+
return matches.includes(void 0) ? void 0 : false;
|
|
2897
|
+
}
|
|
2898
|
+
function allCanvasMatch(matches) {
|
|
2899
|
+
if (matches.includes(false)) return false;
|
|
2900
|
+
return matches.includes(void 0) ? void 0 : true;
|
|
2901
|
+
}
|
|
2902
|
+
function canvasTokenMatch(tokens, value) {
|
|
2903
|
+
if (tokens.includes(value)) return true;
|
|
2904
|
+
const fold = (token) => token.replace(/[A-Z]/g, (char) => char.toLowerCase());
|
|
2905
|
+
return tokens.some((token) => fold(token) === fold(value)) ? void 0 : false;
|
|
2906
|
+
}
|
|
2907
|
+
function canvasPseudoMatch(node, element, hasIdentity) {
|
|
2908
|
+
const name = node.value.toLowerCase();
|
|
2909
|
+
if (name.startsWith("::") || [":before", ":after", ":first-letter", ":first-line"].includes(name))
|
|
2910
|
+
return { match: false, hasIdentity: false };
|
|
2911
|
+
if ([":is", ":where"].includes(name)) {
|
|
2912
|
+
const branches = node.nodes.map(
|
|
2913
|
+
(branch) => canvasPathMatch(branch.nodes, element, hasIdentity)
|
|
2914
|
+
);
|
|
2915
|
+
const match = anyCanvasMatch(branches.map((branch) => branch.match));
|
|
2916
|
+
return { match, hasIdentity: match === true || branches.some((branch) => branch.hasIdentity) };
|
|
2917
|
+
}
|
|
2918
|
+
if (name === ":root") {
|
|
2919
|
+
const match = element.name === "html";
|
|
2920
|
+
return { match, hasIdentity: match };
|
|
2921
|
+
}
|
|
2922
|
+
if (name === ":nth-child" && element.name === "body") {
|
|
2923
|
+
const argument = node.nodes.map((branch) => branch.toString()).join(",").trim();
|
|
2924
|
+
if (/^[1-9]\d*$/.test(argument)) {
|
|
2925
|
+
const match = Number(argument) === 2;
|
|
2926
|
+
return { match, hasIdentity: match };
|
|
2927
|
+
}
|
|
2928
|
+
}
|
|
2929
|
+
return { match: void 0, hasIdentity: false };
|
|
2930
|
+
}
|
|
2931
|
+
function canvasTagMatch(node, element) {
|
|
2932
|
+
if (node.namespace !== void 0) return { match: void 0, hasIdentity: false };
|
|
2933
|
+
if (node.value.toLowerCase() !== element.name.toLowerCase())
|
|
2934
|
+
return { match: false, hasIdentity: false };
|
|
2935
|
+
return { match: ["html", "body"].includes(element.name) ? true : void 0, hasIdentity: true };
|
|
2936
|
+
}
|
|
2937
|
+
function canvasAttributeMatch(node, element) {
|
|
2938
|
+
if (node.namespace === void 0 && node.operator === void 0 && /^data-[a-z0-9_-]+$/.test(node.attribute))
|
|
2939
|
+
return readDecodedAttr(element.raw, node.attribute) !== null;
|
|
2940
|
+
return void 0;
|
|
2941
|
+
}
|
|
2942
|
+
function canvasNodeMatch(node, element, hasIdentity) {
|
|
2943
|
+
switch (node.type) {
|
|
2944
|
+
case "id": {
|
|
2945
|
+
const match = canvasTokenMatch(element.id === null ? [] : [element.id], node.value);
|
|
2946
|
+
return { match, hasIdentity: match === true };
|
|
2947
|
+
}
|
|
2948
|
+
case "class": {
|
|
2949
|
+
const match = canvasTokenMatch(element.classes, node.value);
|
|
2950
|
+
return { match, hasIdentity: match === true };
|
|
2951
|
+
}
|
|
2952
|
+
case "tag":
|
|
2953
|
+
return canvasTagMatch(node, element);
|
|
2954
|
+
case "universal":
|
|
2955
|
+
return { match: node.toString().trim() === "*" ? true : void 0, hasIdentity: false };
|
|
2956
|
+
case "attribute":
|
|
2957
|
+
return { match: canvasAttributeMatch(node, element), hasIdentity: false };
|
|
2958
|
+
case "pseudo":
|
|
2959
|
+
return canvasPseudoMatch(node, element, hasIdentity);
|
|
2960
|
+
default:
|
|
2961
|
+
return { match: void 0, hasIdentity: false };
|
|
2962
|
+
}
|
|
2963
|
+
}
|
|
2964
|
+
function canvasAncestorMatch(nodes, relation, element) {
|
|
2965
|
+
if (!["", ">"].includes(relation)) return void 0;
|
|
2966
|
+
const matches = [];
|
|
2967
|
+
let parent = element.parent;
|
|
2968
|
+
while (parent) {
|
|
2969
|
+
matches.push(canvasPathMatch(nodes, parent).match);
|
|
2970
|
+
if (relation === ">") break;
|
|
2971
|
+
parent = parent.parent;
|
|
2972
|
+
}
|
|
2973
|
+
if (parent === void 0) matches.push(void 0);
|
|
2974
|
+
return anyCanvasMatch(matches);
|
|
2975
|
+
}
|
|
2976
|
+
function canvasPathMatch(nodes, element, inheritedIdentity = false) {
|
|
2977
|
+
let split = -1;
|
|
2978
|
+
let relation = "";
|
|
2979
|
+
for (const [index, node] of nodes.entries()) {
|
|
2980
|
+
if (node.type === "combinator") {
|
|
2981
|
+
split = index;
|
|
2982
|
+
relation = node.value.trim();
|
|
2983
|
+
}
|
|
2984
|
+
}
|
|
2985
|
+
const subjectNodes = nodes.slice(split + 1);
|
|
2986
|
+
if (subjectNodes.length === 0) return { match: void 0, hasIdentity: false };
|
|
2987
|
+
const matches = subjectNodes.map((node) => canvasNodeMatch(node, element, inheritedIdentity));
|
|
2988
|
+
const hasIdentity = inheritedIdentity || matches.some((result) => result.hasIdentity);
|
|
2989
|
+
const subject = allCanvasMatch(
|
|
2990
|
+
subjectNodes.map((node, index) => {
|
|
2991
|
+
const match2 = matches[index]?.match;
|
|
2992
|
+
if (!hasIdentity || match2 !== false) return match2;
|
|
2993
|
+
if (["id", "class", "attribute"].includes(node.type)) return void 0;
|
|
2994
|
+
if (node.type === "pseudo" && !inheritedIdentity)
|
|
2995
|
+
return canvasNodeMatch(node, element, true).match;
|
|
2996
|
+
return match2;
|
|
2997
|
+
})
|
|
2998
|
+
);
|
|
2999
|
+
const match = subject === false || split === -1 ? subject : allCanvasMatch([subject, canvasAncestorMatch(nodes.slice(0, split), relation, element)]);
|
|
3000
|
+
return { match, hasIdentity: match !== false && hasIdentity };
|
|
3001
|
+
}
|
|
3002
|
+
function canvasElements(rootTag, tags) {
|
|
3003
|
+
const root = canvasIdentity(rootTag);
|
|
3004
|
+
const html = {
|
|
3005
|
+
...root.name === "html" ? root : canvasIdentity(findHtmlTag(tags) ?? { name: "html", raw: "<html>" }),
|
|
3006
|
+
parent: null
|
|
3007
|
+
};
|
|
3008
|
+
const body = {
|
|
3009
|
+
...root.name === "body" ? root : canvasIdentity(tags.find((tag) => tag.name === "body") ?? { name: "body", raw: "<body>" }),
|
|
3010
|
+
parent: html
|
|
3011
|
+
};
|
|
3012
|
+
const elements = [html, body];
|
|
3013
|
+
if (!["html", "body"].includes(root.name))
|
|
3014
|
+
elements.push({ ...root, parent: ["head", "template"].includes(root.name) ? void 0 : body });
|
|
3015
|
+
return { root, elements };
|
|
3016
|
+
}
|
|
3017
|
+
function canvasSelectorMatcher(rootTag, tags) {
|
|
3018
|
+
let canvas;
|
|
3019
|
+
return (selector, allowNewHits) => {
|
|
3020
|
+
const { root, elements } = canvas ??= canvasElements(rootTag, tags);
|
|
3021
|
+
const match = anyCanvasMatch(
|
|
3022
|
+
elements.map((element) => canvasPathMatch(selector.nodes, element).match)
|
|
3023
|
+
);
|
|
3024
|
+
if (match === false) return false;
|
|
3025
|
+
if (match === true && allowNewHits) return true;
|
|
3026
|
+
return selector.toString().split(",").some((part) => canvasScopeCandidate(part, root));
|
|
3027
|
+
};
|
|
2885
3028
|
}
|
|
2886
3029
|
function inlineCanvasZoomHits(rootTag, tags) {
|
|
2887
3030
|
const hits = [];
|
|
@@ -2899,19 +3042,23 @@ function inlineCanvasZoomHits(rootTag, tags) {
|
|
|
2899
3042
|
}
|
|
2900
3043
|
return hits;
|
|
2901
3044
|
}
|
|
2902
|
-
function firstCanvasSelector(header,
|
|
2903
|
-
|
|
2904
|
-
const
|
|
2905
|
-
|
|
3045
|
+
function firstCanvasSelector(header, matchesCanvas) {
|
|
3046
|
+
try {
|
|
3047
|
+
for (const selector of selectorParser2().astSync(header).nodes) {
|
|
3048
|
+
const trimmed = selector.toString().trim();
|
|
3049
|
+
if (matchesCanvas(selector)) return trimmed;
|
|
3050
|
+
}
|
|
3051
|
+
} catch {
|
|
3052
|
+
return null;
|
|
2906
3053
|
}
|
|
2907
3054
|
return null;
|
|
2908
3055
|
}
|
|
2909
|
-
function canvasZoomInRule(header, body,
|
|
3056
|
+
function canvasZoomInRule(header, body, matchesCanvas) {
|
|
2910
3057
|
const trimmedHeader = header.trim();
|
|
2911
3058
|
if (!trimmedHeader || trimmedHeader.startsWith("@")) return null;
|
|
2912
3059
|
const value = firstRescalingZoom(body);
|
|
2913
3060
|
if (!value) return null;
|
|
2914
|
-
const selector = firstCanvasSelector(trimmedHeader,
|
|
3061
|
+
const selector = firstCanvasSelector(trimmedHeader, matchesCanvas);
|
|
2915
3062
|
if (!selector) return null;
|
|
2916
3063
|
return {
|
|
2917
3064
|
where: `\`${selector}\``,
|
|
@@ -2919,23 +3066,28 @@ function canvasZoomInRule(header, body, rootId, rootClasses) {
|
|
|
2919
3066
|
snippet: truncateSnippet(`${selector} { zoom: ${value} }`)
|
|
2920
3067
|
};
|
|
2921
3068
|
}
|
|
2922
|
-
function stylesheetCanvasZoomHits(styles,
|
|
3069
|
+
function stylesheetCanvasZoomHits(styles, matchesCanvas) {
|
|
2923
3070
|
const hits = [];
|
|
2924
3071
|
for (const style of styles) {
|
|
2925
3072
|
const ruleWithBody = /([^{}]+)\{([^{}]*)\}/g;
|
|
2926
3073
|
const content = stripCssComments(style.content);
|
|
3074
|
+
const allowNewHits = style.attrs.trim() === "" && !content.includes("@");
|
|
2927
3075
|
let match;
|
|
2928
3076
|
while ((match = ruleWithBody.exec(content)) !== null) {
|
|
2929
|
-
const hit = canvasZoomInRule(
|
|
3077
|
+
const hit = canvasZoomInRule(
|
|
3078
|
+
match[1] ?? "",
|
|
3079
|
+
match[2] ?? "",
|
|
3080
|
+
(selector) => matchesCanvas(selector, allowNewHits)
|
|
3081
|
+
);
|
|
2930
3082
|
if (hit) hits.push(hit);
|
|
2931
3083
|
}
|
|
2932
3084
|
}
|
|
2933
3085
|
return hits;
|
|
2934
3086
|
}
|
|
2935
|
-
function canvasZoomHits(rootTag, tags, styles
|
|
3087
|
+
function canvasZoomHits(rootTag, tags, styles) {
|
|
2936
3088
|
return [
|
|
2937
3089
|
...inlineCanvasZoomHits(rootTag, tags),
|
|
2938
|
-
...stylesheetCanvasZoomHits(styles,
|
|
3090
|
+
...stylesheetCanvasZoomHits(styles, canvasSelectorMatcher(rootTag, tags))
|
|
2939
3091
|
];
|
|
2940
3092
|
}
|
|
2941
3093
|
function collectDeclaredVariableIds(htmlTagRaw) {
|
|
@@ -3833,9 +3985,7 @@ ${allInlineStyles}`.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
|
3833
3985
|
// fired on every `zoom` would be flagging correct authoring.
|
|
3834
3986
|
({ rootTag, tags, styles }) => {
|
|
3835
3987
|
if (!rootTag) return [];
|
|
3836
|
-
const
|
|
3837
|
-
const rootClasses = (readAttr(rootTag.raw, "class") || "").split(/\s+/).filter(Boolean);
|
|
3838
|
-
const hits = canvasZoomHits(rootTag, tags, styles, rootId, rootClasses);
|
|
3988
|
+
const hits = canvasZoomHits(rootTag, tags, styles);
|
|
3839
3989
|
const hit = hits[0];
|
|
3840
3990
|
if (!hit) return [];
|
|
3841
3991
|
const enlarging = !hit.value.startsWith("-") && parseFloat(hit.value) > (hit.value.includes("%") ? 100 : 1);
|
|
@@ -4883,9 +5033,12 @@ ${right.raw}`)
|
|
|
4883
5033
|
const usesGsap = allScriptTexts.some(
|
|
4884
5034
|
(t) => /gsap\.(to|from|fromTo|timeline|set|registerPlugin)\b/.test(t)
|
|
4885
5035
|
);
|
|
4886
|
-
const
|
|
5036
|
+
const isGsapCoreSrc = (src) => /(^|\/)gsap(-\d+(\.\d+)*)?(\.min)?\.js$/i.test(src.split(/[?#]/)[0] ?? "");
|
|
5037
|
+
const hasGsapScript = allScriptSrcs.some(isGsapCoreSrc);
|
|
4887
5038
|
const hasInlineGsap = allScriptTexts.some(
|
|
4888
|
-
(t) => /\/\*\s*inlined
|
|
5039
|
+
(t) => [...t.matchAll(/\/\*\s*inlined:\s*(\S+)\s*\*\//gi)].some(
|
|
5040
|
+
(m) => isGsapCoreSrc(m[1] ?? "")
|
|
5041
|
+
) || /\/\*!\s*\*\s*GSAP\s+\d/.test(t) || /Missing plugin\? gsap\.registerPlugin\(\)/.test(t) || /\b_gsScope\b/.test(t)
|
|
4889
5042
|
);
|
|
4890
5043
|
if (!usesGsap || hasGsapScript || hasInlineGsap || canInheritGsapFromHost) return [];
|
|
4891
5044
|
return [
|
package/dist/index.js
CHANGED
|
@@ -2715,6 +2715,7 @@ function containingCallOffset(script, tokenOffset) {
|
|
|
2715
2715
|
}
|
|
2716
2716
|
|
|
2717
2717
|
// src/rules/composition.ts
|
|
2718
|
+
import selectorParser2 from "postcss-selector-parser";
|
|
2718
2719
|
import {
|
|
2719
2720
|
COMPOSITION_VARIABLE_TYPES,
|
|
2720
2721
|
isCompositionVariable,
|
|
@@ -2882,12 +2883,154 @@ function firstRescalingZoom(css) {
|
|
|
2882
2883
|
}
|
|
2883
2884
|
return null;
|
|
2884
2885
|
}
|
|
2885
|
-
function
|
|
2886
|
+
function canvasScopeCandidate(selector, root) {
|
|
2886
2887
|
const leftmost = selector.trim().split(/[\s>+~]+/)[0] ?? "";
|
|
2887
|
-
|
|
2888
|
-
if (
|
|
2889
|
-
|
|
2890
|
-
|
|
2888
|
+
if (["html", "body", ":root", "*"].includes(leftmost.toLowerCase())) return true;
|
|
2889
|
+
if (root.id && leftmostCompoundId(selector) === root.id) return true;
|
|
2890
|
+
return leftmostCompoundClasses(selector).some((name) => root.classes.includes(name));
|
|
2891
|
+
}
|
|
2892
|
+
function canvasIdentity(tag) {
|
|
2893
|
+
return {
|
|
2894
|
+
name: tag.name,
|
|
2895
|
+
raw: tag.raw,
|
|
2896
|
+
id: readDecodedAttr(tag.raw, "id"),
|
|
2897
|
+
classes: (readDecodedAttr(tag.raw, "class") ?? "").split(/[\t\n\f\r ]+/)
|
|
2898
|
+
};
|
|
2899
|
+
}
|
|
2900
|
+
function anyCanvasMatch(matches) {
|
|
2901
|
+
if (matches.includes(true)) return true;
|
|
2902
|
+
return matches.includes(void 0) ? void 0 : false;
|
|
2903
|
+
}
|
|
2904
|
+
function allCanvasMatch(matches) {
|
|
2905
|
+
if (matches.includes(false)) return false;
|
|
2906
|
+
return matches.includes(void 0) ? void 0 : true;
|
|
2907
|
+
}
|
|
2908
|
+
function canvasTokenMatch(tokens, value) {
|
|
2909
|
+
if (tokens.includes(value)) return true;
|
|
2910
|
+
const fold = (token) => token.replace(/[A-Z]/g, (char) => char.toLowerCase());
|
|
2911
|
+
return tokens.some((token) => fold(token) === fold(value)) ? void 0 : false;
|
|
2912
|
+
}
|
|
2913
|
+
function canvasPseudoMatch(node, element, hasIdentity) {
|
|
2914
|
+
const name = node.value.toLowerCase();
|
|
2915
|
+
if (name.startsWith("::") || [":before", ":after", ":first-letter", ":first-line"].includes(name))
|
|
2916
|
+
return { match: false, hasIdentity: false };
|
|
2917
|
+
if ([":is", ":where"].includes(name)) {
|
|
2918
|
+
const branches = node.nodes.map(
|
|
2919
|
+
(branch) => canvasPathMatch(branch.nodes, element, hasIdentity)
|
|
2920
|
+
);
|
|
2921
|
+
const match = anyCanvasMatch(branches.map((branch) => branch.match));
|
|
2922
|
+
return { match, hasIdentity: match === true || branches.some((branch) => branch.hasIdentity) };
|
|
2923
|
+
}
|
|
2924
|
+
if (name === ":root") {
|
|
2925
|
+
const match = element.name === "html";
|
|
2926
|
+
return { match, hasIdentity: match };
|
|
2927
|
+
}
|
|
2928
|
+
if (name === ":nth-child" && element.name === "body") {
|
|
2929
|
+
const argument = node.nodes.map((branch) => branch.toString()).join(",").trim();
|
|
2930
|
+
if (/^[1-9]\d*$/.test(argument)) {
|
|
2931
|
+
const match = Number(argument) === 2;
|
|
2932
|
+
return { match, hasIdentity: match };
|
|
2933
|
+
}
|
|
2934
|
+
}
|
|
2935
|
+
return { match: void 0, hasIdentity: false };
|
|
2936
|
+
}
|
|
2937
|
+
function canvasTagMatch(node, element) {
|
|
2938
|
+
if (node.namespace !== void 0) return { match: void 0, hasIdentity: false };
|
|
2939
|
+
if (node.value.toLowerCase() !== element.name.toLowerCase())
|
|
2940
|
+
return { match: false, hasIdentity: false };
|
|
2941
|
+
return { match: ["html", "body"].includes(element.name) ? true : void 0, hasIdentity: true };
|
|
2942
|
+
}
|
|
2943
|
+
function canvasAttributeMatch(node, element) {
|
|
2944
|
+
if (node.namespace === void 0 && node.operator === void 0 && /^data-[a-z0-9_-]+$/.test(node.attribute))
|
|
2945
|
+
return readDecodedAttr(element.raw, node.attribute) !== null;
|
|
2946
|
+
return void 0;
|
|
2947
|
+
}
|
|
2948
|
+
function canvasNodeMatch(node, element, hasIdentity) {
|
|
2949
|
+
switch (node.type) {
|
|
2950
|
+
case "id": {
|
|
2951
|
+
const match = canvasTokenMatch(element.id === null ? [] : [element.id], node.value);
|
|
2952
|
+
return { match, hasIdentity: match === true };
|
|
2953
|
+
}
|
|
2954
|
+
case "class": {
|
|
2955
|
+
const match = canvasTokenMatch(element.classes, node.value);
|
|
2956
|
+
return { match, hasIdentity: match === true };
|
|
2957
|
+
}
|
|
2958
|
+
case "tag":
|
|
2959
|
+
return canvasTagMatch(node, element);
|
|
2960
|
+
case "universal":
|
|
2961
|
+
return { match: node.toString().trim() === "*" ? true : void 0, hasIdentity: false };
|
|
2962
|
+
case "attribute":
|
|
2963
|
+
return { match: canvasAttributeMatch(node, element), hasIdentity: false };
|
|
2964
|
+
case "pseudo":
|
|
2965
|
+
return canvasPseudoMatch(node, element, hasIdentity);
|
|
2966
|
+
default:
|
|
2967
|
+
return { match: void 0, hasIdentity: false };
|
|
2968
|
+
}
|
|
2969
|
+
}
|
|
2970
|
+
function canvasAncestorMatch(nodes, relation, element) {
|
|
2971
|
+
if (!["", ">"].includes(relation)) return void 0;
|
|
2972
|
+
const matches = [];
|
|
2973
|
+
let parent = element.parent;
|
|
2974
|
+
while (parent) {
|
|
2975
|
+
matches.push(canvasPathMatch(nodes, parent).match);
|
|
2976
|
+
if (relation === ">") break;
|
|
2977
|
+
parent = parent.parent;
|
|
2978
|
+
}
|
|
2979
|
+
if (parent === void 0) matches.push(void 0);
|
|
2980
|
+
return anyCanvasMatch(matches);
|
|
2981
|
+
}
|
|
2982
|
+
function canvasPathMatch(nodes, element, inheritedIdentity = false) {
|
|
2983
|
+
let split = -1;
|
|
2984
|
+
let relation = "";
|
|
2985
|
+
for (const [index, node] of nodes.entries()) {
|
|
2986
|
+
if (node.type === "combinator") {
|
|
2987
|
+
split = index;
|
|
2988
|
+
relation = node.value.trim();
|
|
2989
|
+
}
|
|
2990
|
+
}
|
|
2991
|
+
const subjectNodes = nodes.slice(split + 1);
|
|
2992
|
+
if (subjectNodes.length === 0) return { match: void 0, hasIdentity: false };
|
|
2993
|
+
const matches = subjectNodes.map((node) => canvasNodeMatch(node, element, inheritedIdentity));
|
|
2994
|
+
const hasIdentity = inheritedIdentity || matches.some((result) => result.hasIdentity);
|
|
2995
|
+
const subject = allCanvasMatch(
|
|
2996
|
+
subjectNodes.map((node, index) => {
|
|
2997
|
+
const match2 = matches[index]?.match;
|
|
2998
|
+
if (!hasIdentity || match2 !== false) return match2;
|
|
2999
|
+
if (["id", "class", "attribute"].includes(node.type)) return void 0;
|
|
3000
|
+
if (node.type === "pseudo" && !inheritedIdentity)
|
|
3001
|
+
return canvasNodeMatch(node, element, true).match;
|
|
3002
|
+
return match2;
|
|
3003
|
+
})
|
|
3004
|
+
);
|
|
3005
|
+
const match = subject === false || split === -1 ? subject : allCanvasMatch([subject, canvasAncestorMatch(nodes.slice(0, split), relation, element)]);
|
|
3006
|
+
return { match, hasIdentity: match !== false && hasIdentity };
|
|
3007
|
+
}
|
|
3008
|
+
function canvasElements(rootTag, tags) {
|
|
3009
|
+
const root = canvasIdentity(rootTag);
|
|
3010
|
+
const html = {
|
|
3011
|
+
...root.name === "html" ? root : canvasIdentity(findHtmlTag(tags) ?? { name: "html", raw: "<html>" }),
|
|
3012
|
+
parent: null
|
|
3013
|
+
};
|
|
3014
|
+
const body = {
|
|
3015
|
+
...root.name === "body" ? root : canvasIdentity(tags.find((tag) => tag.name === "body") ?? { name: "body", raw: "<body>" }),
|
|
3016
|
+
parent: html
|
|
3017
|
+
};
|
|
3018
|
+
const elements = [html, body];
|
|
3019
|
+
if (!["html", "body"].includes(root.name))
|
|
3020
|
+
elements.push({ ...root, parent: ["head", "template"].includes(root.name) ? void 0 : body });
|
|
3021
|
+
return { root, elements };
|
|
3022
|
+
}
|
|
3023
|
+
function canvasSelectorMatcher(rootTag, tags) {
|
|
3024
|
+
let canvas;
|
|
3025
|
+
return (selector, allowNewHits) => {
|
|
3026
|
+
const { root, elements } = canvas ??= canvasElements(rootTag, tags);
|
|
3027
|
+
const match = anyCanvasMatch(
|
|
3028
|
+
elements.map((element) => canvasPathMatch(selector.nodes, element).match)
|
|
3029
|
+
);
|
|
3030
|
+
if (match === false) return false;
|
|
3031
|
+
if (match === true && allowNewHits) return true;
|
|
3032
|
+
return selector.toString().split(",").some((part) => canvasScopeCandidate(part, root));
|
|
3033
|
+
};
|
|
2891
3034
|
}
|
|
2892
3035
|
function inlineCanvasZoomHits(rootTag, tags) {
|
|
2893
3036
|
const hits = [];
|
|
@@ -2905,19 +3048,23 @@ function inlineCanvasZoomHits(rootTag, tags) {
|
|
|
2905
3048
|
}
|
|
2906
3049
|
return hits;
|
|
2907
3050
|
}
|
|
2908
|
-
function firstCanvasSelector(header,
|
|
2909
|
-
|
|
2910
|
-
const
|
|
2911
|
-
|
|
3051
|
+
function firstCanvasSelector(header, matchesCanvas) {
|
|
3052
|
+
try {
|
|
3053
|
+
for (const selector of selectorParser2().astSync(header).nodes) {
|
|
3054
|
+
const trimmed = selector.toString().trim();
|
|
3055
|
+
if (matchesCanvas(selector)) return trimmed;
|
|
3056
|
+
}
|
|
3057
|
+
} catch {
|
|
3058
|
+
return null;
|
|
2912
3059
|
}
|
|
2913
3060
|
return null;
|
|
2914
3061
|
}
|
|
2915
|
-
function canvasZoomInRule(header, body,
|
|
3062
|
+
function canvasZoomInRule(header, body, matchesCanvas) {
|
|
2916
3063
|
const trimmedHeader = header.trim();
|
|
2917
3064
|
if (!trimmedHeader || trimmedHeader.startsWith("@")) return null;
|
|
2918
3065
|
const value = firstRescalingZoom(body);
|
|
2919
3066
|
if (!value) return null;
|
|
2920
|
-
const selector = firstCanvasSelector(trimmedHeader,
|
|
3067
|
+
const selector = firstCanvasSelector(trimmedHeader, matchesCanvas);
|
|
2921
3068
|
if (!selector) return null;
|
|
2922
3069
|
return {
|
|
2923
3070
|
where: `\`${selector}\``,
|
|
@@ -2925,23 +3072,28 @@ function canvasZoomInRule(header, body, rootId, rootClasses) {
|
|
|
2925
3072
|
snippet: truncateSnippet(`${selector} { zoom: ${value} }`)
|
|
2926
3073
|
};
|
|
2927
3074
|
}
|
|
2928
|
-
function stylesheetCanvasZoomHits(styles,
|
|
3075
|
+
function stylesheetCanvasZoomHits(styles, matchesCanvas) {
|
|
2929
3076
|
const hits = [];
|
|
2930
3077
|
for (const style of styles) {
|
|
2931
3078
|
const ruleWithBody = /([^{}]+)\{([^{}]*)\}/g;
|
|
2932
3079
|
const content = stripCssComments(style.content);
|
|
3080
|
+
const allowNewHits = style.attrs.trim() === "" && !content.includes("@");
|
|
2933
3081
|
let match;
|
|
2934
3082
|
while ((match = ruleWithBody.exec(content)) !== null) {
|
|
2935
|
-
const hit = canvasZoomInRule(
|
|
3083
|
+
const hit = canvasZoomInRule(
|
|
3084
|
+
match[1] ?? "",
|
|
3085
|
+
match[2] ?? "",
|
|
3086
|
+
(selector) => matchesCanvas(selector, allowNewHits)
|
|
3087
|
+
);
|
|
2936
3088
|
if (hit) hits.push(hit);
|
|
2937
3089
|
}
|
|
2938
3090
|
}
|
|
2939
3091
|
return hits;
|
|
2940
3092
|
}
|
|
2941
|
-
function canvasZoomHits(rootTag, tags, styles
|
|
3093
|
+
function canvasZoomHits(rootTag, tags, styles) {
|
|
2942
3094
|
return [
|
|
2943
3095
|
...inlineCanvasZoomHits(rootTag, tags),
|
|
2944
|
-
...stylesheetCanvasZoomHits(styles,
|
|
3096
|
+
...stylesheetCanvasZoomHits(styles, canvasSelectorMatcher(rootTag, tags))
|
|
2945
3097
|
];
|
|
2946
3098
|
}
|
|
2947
3099
|
function collectDeclaredVariableIds(htmlTagRaw) {
|
|
@@ -3839,9 +3991,7 @@ ${allInlineStyles}`.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
|
3839
3991
|
// fired on every `zoom` would be flagging correct authoring.
|
|
3840
3992
|
({ rootTag, tags, styles }) => {
|
|
3841
3993
|
if (!rootTag) return [];
|
|
3842
|
-
const
|
|
3843
|
-
const rootClasses = (readAttr(rootTag.raw, "class") || "").split(/\s+/).filter(Boolean);
|
|
3844
|
-
const hits = canvasZoomHits(rootTag, tags, styles, rootId, rootClasses);
|
|
3994
|
+
const hits = canvasZoomHits(rootTag, tags, styles);
|
|
3845
3995
|
const hit = hits[0];
|
|
3846
3996
|
if (!hit) return [];
|
|
3847
3997
|
const enlarging = !hit.value.startsWith("-") && parseFloat(hit.value) > (hit.value.includes("%") ? 100 : 1);
|
|
@@ -4889,9 +5039,12 @@ ${right.raw}`)
|
|
|
4889
5039
|
const usesGsap = allScriptTexts.some(
|
|
4890
5040
|
(t) => /gsap\.(to|from|fromTo|timeline|set|registerPlugin)\b/.test(t)
|
|
4891
5041
|
);
|
|
4892
|
-
const
|
|
5042
|
+
const isGsapCoreSrc = (src) => /(^|\/)gsap(-\d+(\.\d+)*)?(\.min)?\.js$/i.test(src.split(/[?#]/)[0] ?? "");
|
|
5043
|
+
const hasGsapScript = allScriptSrcs.some(isGsapCoreSrc);
|
|
4893
5044
|
const hasInlineGsap = allScriptTexts.some(
|
|
4894
|
-
(t) => /\/\*\s*inlined
|
|
5045
|
+
(t) => [...t.matchAll(/\/\*\s*inlined:\s*(\S+)\s*\*\//gi)].some(
|
|
5046
|
+
(m) => isGsapCoreSrc(m[1] ?? "")
|
|
5047
|
+
) || /\/\*!\s*\*\s*GSAP\s+\d/.test(t) || /Missing plugin\? gsap\.registerPlugin\(\)/.test(t) || /\b_gsScope\b/.test(t)
|
|
4895
5048
|
);
|
|
4896
5049
|
if (!usesGsap || hasGsapScript || hasInlineGsap || canInheritGsapFromHost) return [];
|
|
4897
5050
|
return [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/lint",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.195",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/heygen-com/hyperframes",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"linkedom": "^0.18.12",
|
|
36
36
|
"postcss": "^8.5.8",
|
|
37
37
|
"postcss-selector-parser": "^7.1.4",
|
|
38
|
-
"@hyperframes/parsers": "0.8.
|
|
38
|
+
"@hyperframes/parsers": "0.8.195"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@types/node": "^25.0.10",
|