@hyperframes/lint 0.8.7 → 0.8.8
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 +18 -1
- package/dist/browser.js.map +1 -1
- package/dist/index.js +26 -6
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -287,6 +287,9 @@ function truncateSnippet(value, maxLength = 220) {
|
|
|
287
287
|
if (normalized.length <= maxLength) return normalized;
|
|
288
288
|
return `${normalized.slice(0, maxLength - 3)}...`;
|
|
289
289
|
}
|
|
290
|
+
function mediaSrcTagRe(tagAlternation) {
|
|
291
|
+
return new RegExp(`<(${tagAlternation})\\b[^>]*\\ssrc\\s*=\\s*["']([^"']+)["'][^>]*>`, "gi");
|
|
292
|
+
}
|
|
290
293
|
|
|
291
294
|
// src/context.ts
|
|
292
295
|
function buildLintContext(html, options = {}) {
|
|
@@ -3266,7 +3269,7 @@ var captionRules = [
|
|
|
3266
3269
|
];
|
|
3267
3270
|
|
|
3268
3271
|
// src/rules/composition.ts
|
|
3269
|
-
import { COMPOSITION_VARIABLE_TYPES } from "@hyperframes/parsers/composition";
|
|
3272
|
+
import { COMPOSITION_VARIABLE_TYPES, isSafeMediaUrl } from "@hyperframes/parsers/composition";
|
|
3270
3273
|
import { COMPOSITION_ATTRIBUTES, readClipTiming } from "@hyperframes/parsers/composition-contract";
|
|
3271
3274
|
var MAX_COMPOSITION_LINES = 300;
|
|
3272
3275
|
var MAX_TIMED_ELEMENTS_PER_TRACK = 3;
|
|
@@ -3434,6 +3437,7 @@ var compositionRules = [
|
|
|
3434
3437
|
const tagsByCompositionId = /* @__PURE__ */ new Map();
|
|
3435
3438
|
for (const tag of tags) {
|
|
3436
3439
|
if (isInsideInertTemplate(tag, tags)) continue;
|
|
3440
|
+
if (readAttr(tag.raw, "data-composition-src")) continue;
|
|
3437
3441
|
const compositionId = readDecodedAttr(tag.raw, "data-composition-id");
|
|
3438
3442
|
if (!compositionId || compositionId.trim().length === 0) continue;
|
|
3439
3443
|
const matchingTags = tagsByCompositionId.get(compositionId) ?? [];
|
|
@@ -3836,6 +3840,11 @@ var compositionRules = [
|
|
|
3836
3840
|
}
|
|
3837
3841
|
const findings = [];
|
|
3838
3842
|
const knownTypes = new Set(COMPOSITION_VARIABLE_TYPES);
|
|
3843
|
+
const varSrcIds = /* @__PURE__ */ new Set();
|
|
3844
|
+
for (const tag of tags) {
|
|
3845
|
+
const bound = readAttr(tag.raw, "data-var-src");
|
|
3846
|
+
if (bound) varSrcIds.add(bound);
|
|
3847
|
+
}
|
|
3839
3848
|
for (let i = 0; i < parsed.length; i += 1) {
|
|
3840
3849
|
const entry = parsed[i];
|
|
3841
3850
|
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
@@ -3860,6 +3869,17 @@ var compositionRules = [
|
|
|
3860
3869
|
message: `data-composition-variables entry [${i}] is missing or has invalid: ${missing.join(", ")}. Type must be one of string, number, color, boolean, enum, font, image.`,
|
|
3861
3870
|
snippet: truncateSnippet(htmlTag.raw)
|
|
3862
3871
|
});
|
|
3872
|
+
continue;
|
|
3873
|
+
}
|
|
3874
|
+
const id = String(e.id);
|
|
3875
|
+
if ((e.type === "image" || varSrcIds.has(id)) && typeof e.default === "string" && e.default.length > 0 && !isSafeMediaUrl(e.default)) {
|
|
3876
|
+
findings.push({
|
|
3877
|
+
code: "unloadable_media_variable_default",
|
|
3878
|
+
severity: "error",
|
|
3879
|
+
message: `Variable "${id}" defaults to a URL the runtime will refuse to load, so any element bound to it renders its authored fallback src instead and the render still exits 0.`,
|
|
3880
|
+
fixHint: `Media URLs must be relative, http(s), blob:, or a data:image/* URI. Copy the file into the project and reference it relatively (e.g. "assets/bg.png") rather than by absolute path.`,
|
|
3881
|
+
snippet: truncateSnippet(htmlTag.raw)
|
|
3882
|
+
});
|
|
3863
3883
|
}
|
|
3864
3884
|
}
|
|
3865
3885
|
return findings;
|
|
@@ -4771,13 +4791,13 @@ async function probeIsHevc(ffprobePath, filePath) {
|
|
|
4771
4791
|
}
|
|
4772
4792
|
function collectLocalVideoCandidates(projectDir, htmlSources) {
|
|
4773
4793
|
const candidates = /* @__PURE__ */ new Map();
|
|
4774
|
-
const videoSrcRe =
|
|
4794
|
+
const videoSrcRe = mediaSrcTagRe("video");
|
|
4775
4795
|
for (const { html, compSrcPath } of htmlSources) {
|
|
4776
4796
|
const scannable = maskNonScannableRanges(html);
|
|
4777
4797
|
const re = new RegExp(videoSrcRe.source, videoSrcRe.flags);
|
|
4778
4798
|
let match;
|
|
4779
4799
|
while ((match = re.exec(scannable)) !== null) {
|
|
4780
|
-
const rawSrc = match[
|
|
4800
|
+
const rawSrc = match[2] ?? "";
|
|
4781
4801
|
if (isUnresolvedAssetPlaceholder(rawSrc)) continue;
|
|
4782
4802
|
const src = cleanAssetUrl(rawSrc);
|
|
4783
4803
|
if (!src) continue;
|
|
@@ -5041,12 +5061,12 @@ function lintProjectAudioFiles(projectDir, htmlSources) {
|
|
|
5041
5061
|
}
|
|
5042
5062
|
function lintAudioSrcNotFound(projectDir, htmlSources) {
|
|
5043
5063
|
const findings = [];
|
|
5044
|
-
const audioSrcRe =
|
|
5064
|
+
const audioSrcRe = mediaSrcTagRe("audio");
|
|
5045
5065
|
const missingSrcs = [];
|
|
5046
5066
|
for (const { html, compSrcPath } of htmlSources) {
|
|
5047
5067
|
let match;
|
|
5048
5068
|
while ((match = audioSrcRe.exec(html)) !== null) {
|
|
5049
|
-
const src = match[
|
|
5069
|
+
const src = match[2];
|
|
5050
5070
|
if (/^(https?:|data:|blob:)/i.test(src)) continue;
|
|
5051
5071
|
if (isUnresolvedAssetPlaceholder2(src)) continue;
|
|
5052
5072
|
const rootRelative = compSrcPath ? rewriteAssetPath2(compSrcPath, src, (path) => existsSync2(join2(projectDir, path))) : src;
|
|
@@ -5068,7 +5088,7 @@ function lintAudioSrcNotFound(projectDir, htmlSources) {
|
|
|
5068
5088
|
}
|
|
5069
5089
|
function lintMissingLocalAsset(projectDir, htmlSources) {
|
|
5070
5090
|
const findings = [];
|
|
5071
|
-
const localAssetSrcRe =
|
|
5091
|
+
const localAssetSrcRe = mediaSrcTagRe("video|img|source");
|
|
5072
5092
|
const missingByTag = /* @__PURE__ */ new Map();
|
|
5073
5093
|
for (const { html, compSrcPath } of htmlSources) {
|
|
5074
5094
|
const scannable = maskNonScannableRanges2(html);
|