@hyperframes/lint 0.8.27 → 0.8.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.
- package/dist/browser.js +81 -1
- package/dist/browser.js.map +1 -1
- package/dist/index.js +81 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/browser.js
CHANGED
|
@@ -714,7 +714,7 @@ var coreRules = [
|
|
|
714
714
|
{
|
|
715
715
|
pattern: /crypto\.getRandomValues\s*\(/,
|
|
716
716
|
label: "crypto.getRandomValues()",
|
|
717
|
-
hint: "
|
|
717
|
+
hint: "Use a seeded PRNG (e.g. a simple mulberry32) so renders are deterministic across frames."
|
|
718
718
|
},
|
|
719
719
|
{
|
|
720
720
|
pattern: /gsap\.utils\.random\s*\(/,
|
|
@@ -778,6 +778,84 @@ function hasAttrName(tagSource, attr) {
|
|
|
778
778
|
const attrs = tagSource.replace(/^<\s*[a-z][\w:-]*/i, "");
|
|
779
779
|
return new RegExp(`(?:^|\\s)${escaped}(?:\\s*=|\\s|/?>)`, "i").test(attrs);
|
|
780
780
|
}
|
|
781
|
+
var IMAGE_SRC_EXT = /* @__PURE__ */ new Set([
|
|
782
|
+
"jpg",
|
|
783
|
+
"jpeg",
|
|
784
|
+
"png",
|
|
785
|
+
"gif",
|
|
786
|
+
"bmp",
|
|
787
|
+
"webp",
|
|
788
|
+
"svg",
|
|
789
|
+
"heic",
|
|
790
|
+
"heif",
|
|
791
|
+
"tiff",
|
|
792
|
+
"ico"
|
|
793
|
+
]);
|
|
794
|
+
var VIDEO_SRC_EXT = /* @__PURE__ */ new Set([
|
|
795
|
+
"mp4",
|
|
796
|
+
"mov",
|
|
797
|
+
"avi",
|
|
798
|
+
"webm",
|
|
799
|
+
"mkv",
|
|
800
|
+
"flv",
|
|
801
|
+
"wmv",
|
|
802
|
+
"m4v",
|
|
803
|
+
"mpg",
|
|
804
|
+
"mpeg"
|
|
805
|
+
]);
|
|
806
|
+
function srcKind(src) {
|
|
807
|
+
const stripped = src.trim();
|
|
808
|
+
if (!stripped) return null;
|
|
809
|
+
const lower = stripped.toLowerCase();
|
|
810
|
+
if (lower.startsWith("data:")) {
|
|
811
|
+
const mime = /^data:([^;,]+)/i.exec(stripped)?.[1]?.toLowerCase();
|
|
812
|
+
if (!mime) return null;
|
|
813
|
+
if (mime.startsWith("image/")) return "image";
|
|
814
|
+
if (mime.startsWith("video/")) return "video";
|
|
815
|
+
return null;
|
|
816
|
+
}
|
|
817
|
+
if (lower.startsWith("blob:")) return null;
|
|
818
|
+
let pathname = stripped;
|
|
819
|
+
try {
|
|
820
|
+
if (/^https?:/i.test(stripped)) {
|
|
821
|
+
pathname = decodeURIComponent(new URL(stripped).pathname);
|
|
822
|
+
} else {
|
|
823
|
+
pathname = stripped.split("?")[0]?.split("#")[0] ?? stripped;
|
|
824
|
+
}
|
|
825
|
+
} catch {
|
|
826
|
+
pathname = stripped.split("?")[0]?.split("#")[0] ?? stripped;
|
|
827
|
+
}
|
|
828
|
+
const base = pathname.split("/").pop() ?? "";
|
|
829
|
+
const dot = base.lastIndexOf(".");
|
|
830
|
+
if (dot < 0) return null;
|
|
831
|
+
const ext = base.slice(dot + 1).toLowerCase();
|
|
832
|
+
if (IMAGE_SRC_EXT.has(ext)) return "image";
|
|
833
|
+
if (VIDEO_SRC_EXT.has(ext)) return "video";
|
|
834
|
+
return null;
|
|
835
|
+
}
|
|
836
|
+
function findMediaSrcKindMismatchFindings(ctx) {
|
|
837
|
+
const findings = [];
|
|
838
|
+
for (const tag of ctx.tags) {
|
|
839
|
+
if (tag.name !== "video" && tag.name !== "img") continue;
|
|
840
|
+
const src = readAttr(tag.raw, "src");
|
|
841
|
+
if (!src) continue;
|
|
842
|
+
const kind = srcKind(src);
|
|
843
|
+
if (kind === null) continue;
|
|
844
|
+
if (tag.name === "video" && kind !== "image") continue;
|
|
845
|
+
if (tag.name === "img" && kind !== "video") continue;
|
|
846
|
+
const elementId = readAttr(tag.raw, "id") || void 0;
|
|
847
|
+
const expected = tag.name === "video" ? "video" : "image";
|
|
848
|
+
findings.push({
|
|
849
|
+
code: "media_src_kind_mismatch",
|
|
850
|
+
severity: "error",
|
|
851
|
+
message: `<${tag.name}${elementId ? ` id="${elementId}"` : ""}> src is a ${kind}, not a ${expected}. The producer fail-closes when the tag and file kind disagree.`,
|
|
852
|
+
elementId,
|
|
853
|
+
fixHint: tag.name === "video" ? "Use <img> for a still, or point <video> at a video URL (mp4/webm/mov/\u2026)." : "Use <video> for a video URL, or point <img> at a still (png/jpg/webp/\u2026).",
|
|
854
|
+
snippet: truncateSnippet(tag.raw)
|
|
855
|
+
});
|
|
856
|
+
}
|
|
857
|
+
return findings;
|
|
858
|
+
}
|
|
781
859
|
function mediaHasResolvableSrc(tag, tags) {
|
|
782
860
|
if (readAttr(tag.raw, "src")) return true;
|
|
783
861
|
const end = tag.closeIndex ?? tag.endIndex;
|
|
@@ -1135,6 +1213,8 @@ var mediaRules = [
|
|
|
1135
1213
|
}
|
|
1136
1214
|
return findings;
|
|
1137
1215
|
},
|
|
1216
|
+
// media_src_kind_mismatch
|
|
1217
|
+
findMediaSrcKindMismatchFindings,
|
|
1138
1218
|
// placeholder_media_url
|
|
1139
1219
|
({ tags }) => {
|
|
1140
1220
|
const findings = [];
|