mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 09:16:55 +00:00
fix(lint): recognise .avif and .m4a in the media src kind rule (#4779)
The media_src_kind_mismatch rule classified .mp3 and .jpeg but not .m4a or .avif, so an <img> pointed at an audio file or a <video> at a still slipped through for those two formats. Add .avif to IMAGE_SRC_EXT and .m4a to AUDIO_SRC_EXT. .ogg stays out: its container can carry Theora video as well as Vorbis or Opus, so the extension does not name the kind. .m4a is the opposite case -- it is audio-only, and video in the same MP4 container is .m4v, which VIDEO_SRC_EXT already lists. The .ogg case keeps its existing coverage and gains an explicit unknown-extension case alongside it. Refs #4382 Co-authored-by: Yi-111-a <Yi-111-a@users.noreply.github.com>
This commit is contained in:
@@ -1271,14 +1271,100 @@ describe("media_src_kind_mismatch", () => {
|
||||
expect(result.findings.find((f) => f.code === "media_src_kind_mismatch")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("does not flag .ogg or .m4a, whose containers can carry video too", async () => {
|
||||
it("errors when <img> src is an .m4a audio file", async () => {
|
||||
const html = `
|
||||
<html><body>
|
||||
<div id="root" data-composition-id="c1" data-width="1920" data-height="1080">
|
||||
<img id="logo" src="voice.m4a" data-start="0" data-duration="5" />
|
||||
</div>
|
||||
<script>window.__timelines = {};</script>
|
||||
</body></html>`;
|
||||
const result = await lintHyperframeHtml(html);
|
||||
const finding = result.findings.find((f) => f.code === "media_src_kind_mismatch");
|
||||
expect(finding?.severity).toBe("error");
|
||||
expect(finding?.elementId).toBe("logo");
|
||||
expect(finding?.message).toContain("an audio file");
|
||||
});
|
||||
|
||||
it("errors when <video> src is an .m4a audio file", async () => {
|
||||
const html = `
|
||||
<html><body>
|
||||
<div id="root" data-composition-id="c1" data-width="1920" data-height="1080">
|
||||
<video id="bg" src="voice.m4a" data-start="0" data-duration="5" muted></video>
|
||||
</div>
|
||||
<script>window.__timelines = {};</script>
|
||||
</body></html>`;
|
||||
const result = await lintHyperframeHtml(html);
|
||||
const finding = result.findings.find((f) => f.code === "media_src_kind_mismatch");
|
||||
expect(finding?.severity).toBe("error");
|
||||
expect(finding?.elementId).toBe("bg");
|
||||
expect(finding?.message).toContain("an audio file");
|
||||
});
|
||||
|
||||
it("errors when <video> src is an .avif image", async () => {
|
||||
const html = `
|
||||
<html><body>
|
||||
<div id="root" data-composition-id="c1" data-width="1920" data-height="1080">
|
||||
<video id="bg" src="photo.avif" data-start="0" data-duration="5" muted></video>
|
||||
</div>
|
||||
<script>window.__timelines = {};</script>
|
||||
</body></html>`;
|
||||
const result = await lintHyperframeHtml(html);
|
||||
const finding = result.findings.find((f) => f.code === "media_src_kind_mismatch");
|
||||
expect(finding?.severity).toBe("error");
|
||||
expect(finding?.elementId).toBe("bg");
|
||||
expect(finding?.message).toContain("an image");
|
||||
});
|
||||
|
||||
it("does not flag matching .avif and .m4a src kinds", async () => {
|
||||
const html = `
|
||||
<html><body>
|
||||
<div id="root" data-composition-id="c1" data-width="1920" data-height="1080">
|
||||
<img id="i1" src="photo.avif">
|
||||
<audio id="a1" src="voice.m4a" data-start="0" data-duration="5"></audio>
|
||||
<video id="v1" src="clip.m4v" data-start="0" data-duration="5" muted></video>
|
||||
</div>
|
||||
<script>window.__timelines = {};</script>
|
||||
</body></html>`;
|
||||
const result = await lintHyperframeHtml(html);
|
||||
expect(result.findings.find((f) => f.code === "media_src_kind_mismatch")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("reads .avif and .m4a extensions case-insensitively and past query/hash suffixes", async () => {
|
||||
const html = `
|
||||
<html><body>
|
||||
<div id="root" data-composition-id="c1" data-width="1920" data-height="1080">
|
||||
<video id="v1" src="photo.AVIF?v=2" data-start="0" data-duration="5" muted></video>
|
||||
<img id="i1" src="voice.M4A#t=5" data-start="0" data-duration="5" />
|
||||
</div>
|
||||
<script>window.__timelines = {};</script>
|
||||
</body></html>`;
|
||||
const result = await lintHyperframeHtml(html);
|
||||
const findings = result.findings.filter((f) => f.code === "media_src_kind_mismatch");
|
||||
expect(findings.map((f) => f.elementId)).toEqual(["v1", "i1"]);
|
||||
expect(findings[0]?.message).toContain("an image");
|
||||
expect(findings[1]?.message).toContain("an audio file");
|
||||
});
|
||||
|
||||
it("does not flag .ogg, whose container can carry video too", async () => {
|
||||
const html = `
|
||||
<html><body>
|
||||
<div id="root" data-composition-id="c1" data-width="1920" data-height="1080">
|
||||
<video id="v1" src="clip.ogg" data-start="0" data-duration="5" muted></video>
|
||||
<video id="v2" src="clip.m4a" data-start="0" data-duration="5" muted></video>
|
||||
<img id="i1" src="clip.ogg" data-start="0" data-duration="5" />
|
||||
<img id="i2" src="clip.m4a" data-start="0" data-duration="5" />
|
||||
</div>
|
||||
<script>window.__timelines = {};</script>
|
||||
</body></html>`;
|
||||
const result = await lintHyperframeHtml(html);
|
||||
expect(result.findings.find((f) => f.code === "media_src_kind_mismatch")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("does not flag unknown extensions, whose kind cannot be inferred", async () => {
|
||||
const html = `
|
||||
<html><body>
|
||||
<div id="root" data-composition-id="c1" data-width="1920" data-height="1080">
|
||||
<video id="v1" src="clip.xyz" data-start="0" data-duration="5" muted></video>
|
||||
<img id="i1" src="still.xyz" data-start="0" data-duration="5" />
|
||||
</div>
|
||||
<script>window.__timelines = {};</script>
|
||||
</body></html>`;
|
||||
|
||||
@@ -64,6 +64,7 @@ const IMAGE_SRC_EXT = new Set([
|
||||
"heif",
|
||||
"tiff",
|
||||
"ico",
|
||||
"avif",
|
||||
]);
|
||||
const VIDEO_SRC_EXT = new Set([
|
||||
"mp4",
|
||||
@@ -78,7 +79,7 @@ const VIDEO_SRC_EXT = new Set([
|
||||
"mpeg",
|
||||
]);
|
||||
|
||||
const AUDIO_SRC_EXT = new Set(["mp3", "wav", "aac", "flac", "opus", "aiff", "wma"]);
|
||||
const AUDIO_SRC_EXT = new Set(["mp3", "wav", "aac", "flac", "opus", "aiff", "wma", "m4a"]);
|
||||
|
||||
type SrcKind = "image" | "video" | "audio";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user