@hyperframes/lint 0.8.81 → 0.8.83
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 +26 -1
- package/dist/browser.js.map +1 -1
- package/dist/index.js +64 -32
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -5822,6 +5822,9 @@ import {
|
|
|
5822
5822
|
topLevelElements,
|
|
5823
5823
|
trackKindOf
|
|
5824
5824
|
} from "@hyperframes/parsers/top-level-elements";
|
|
5825
|
+
import { readClipTiming as readClipTiming2 } from "@hyperframes/parsers/composition-contract";
|
|
5826
|
+
import { readDataDurationSeconds } from "@hyperframes/parsers/media-duration";
|
|
5827
|
+
import { TIMING_TOLERANCE_SECONDS } from "@hyperframes/parsers/composition-duration";
|
|
5825
5828
|
var INLINE_TEXT_TAGS = /* @__PURE__ */ new Set([
|
|
5826
5829
|
"br",
|
|
5827
5830
|
"wbr",
|
|
@@ -5950,6 +5953,27 @@ function captionFindings(rows, severity) {
|
|
|
5950
5953
|
}
|
|
5951
5954
|
return findings;
|
|
5952
5955
|
}
|
|
5956
|
+
var hundredths = (seconds) => Math.round(seconds * 100) / 100;
|
|
5957
|
+
function clipsPastRootFindings(root, rows) {
|
|
5958
|
+
if (root.attrs["data-composition-id"] === void 0) return [];
|
|
5959
|
+
const rootDuration = readDataDurationSeconds((name) => root.attrs[name]);
|
|
5960
|
+
if (rootDuration === null) return [];
|
|
5961
|
+
const limit = hundredths(rootDuration);
|
|
5962
|
+
return rows.flatMap((row) => {
|
|
5963
|
+
const { start, end } = readClipTiming2({ getAttribute: (name) => row.attrs[name] ?? null });
|
|
5964
|
+
if (start === null || end === null || end <= rootDuration + TIMING_TOLERANCE_SECONDS) return [];
|
|
5965
|
+
return [
|
|
5966
|
+
{
|
|
5967
|
+
code: "clip_ends_past_root_duration",
|
|
5968
|
+
severity: "warning",
|
|
5969
|
+
message: `${describe(row)} runs from ${hundredths(start)}s to ${hundredths(end)}s, past the root composition's data-duration of ${limit}s, so it is cut off in previews, posters and renders.`,
|
|
5970
|
+
elementId: row.attrs.id,
|
|
5971
|
+
fixHint: `Extend the root data-duration to ${hundredths(end)}, or make ${describe(row)} end at or before ${limit}s.`,
|
|
5972
|
+
snippet: truncateSnippet(row.open.raw)
|
|
5973
|
+
}
|
|
5974
|
+
];
|
|
5975
|
+
});
|
|
5976
|
+
}
|
|
5953
5977
|
var structureRules = [
|
|
5954
5978
|
(ctx) => {
|
|
5955
5979
|
if (ctx.options.isSubComposition) return [];
|
|
@@ -5960,7 +5984,8 @@ var structureRules = [
|
|
|
5960
5984
|
return [
|
|
5961
5985
|
...nestedStructureFindings(rows, severity),
|
|
5962
5986
|
...missingDurationFindings(rows, severity),
|
|
5963
|
-
...captionFindings(rows, severity)
|
|
5987
|
+
...captionFindings(rows, severity),
|
|
5988
|
+
...clipsPastRootFindings(root, rows)
|
|
5964
5989
|
];
|
|
5965
5990
|
}
|
|
5966
5991
|
];
|
|
@@ -6378,6 +6403,7 @@ async function lintHevcPreviewCodec(candidates) {
|
|
|
6378
6403
|
function parseSubCompHtml(html) {
|
|
6379
6404
|
return parseHTML3(html).document;
|
|
6380
6405
|
}
|
|
6406
|
+
var sourceFile = (projectDir, compSrcPath) => resolve(projectDir, compSrcPath ?? "index.html");
|
|
6381
6407
|
function querySelectorAllIncludingTemplates(root, selector) {
|
|
6382
6408
|
const matches = [...root.querySelectorAll(selector)];
|
|
6383
6409
|
for (const template of root.querySelectorAll("template")) {
|
|
@@ -6529,20 +6555,20 @@ async function lintProject(projectDir, entryFile, hostOptions = {}) {
|
|
|
6529
6555
|
...await lintVideoMediaStartPastEof(projectDir, allHtmlSources),
|
|
6530
6556
|
...await lintHevcPreviewCodec(collectLocalVideoCandidates(projectDir, allHtmlSources))
|
|
6531
6557
|
];
|
|
6532
|
-
|
|
6533
|
-
|
|
6534
|
-
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
|
|
6538
|
-
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
|
|
6545
|
-
|
|
6558
|
+
for (const finding of projectFindings) {
|
|
6559
|
+
const ownFile = finding.file && resolve(projectDir, finding.file);
|
|
6560
|
+
const owner = results.find((entry) => resolve(projectDir, entry.file) === ownFile)?.result ?? rootResult;
|
|
6561
|
+
owner.findings.push(finding);
|
|
6562
|
+
if (finding.severity === "error") {
|
|
6563
|
+
owner.errorCount++;
|
|
6564
|
+
owner.ok = false;
|
|
6565
|
+
totalErrors++;
|
|
6566
|
+
} else if (finding.severity === "warning") {
|
|
6567
|
+
owner.warningCount++;
|
|
6568
|
+
totalWarnings++;
|
|
6569
|
+
} else {
|
|
6570
|
+
owner.infoCount++;
|
|
6571
|
+
totalInfos++;
|
|
6546
6572
|
}
|
|
6547
6573
|
}
|
|
6548
6574
|
return { results, totalErrors, totalWarnings, totalInfos };
|
|
@@ -6602,7 +6628,7 @@ function lintProjectAudioFiles(projectDir, htmlSources) {
|
|
|
6602
6628
|
function lintAudioSrcNotFound(projectDir, htmlSources) {
|
|
6603
6629
|
const findings = [];
|
|
6604
6630
|
const audioSrcRe = mediaSrcTagRe("audio");
|
|
6605
|
-
const
|
|
6631
|
+
const missingByFile = /* @__PURE__ */ new Map();
|
|
6606
6632
|
for (const { html, compSrcPath } of htmlSources) {
|
|
6607
6633
|
let match;
|
|
6608
6634
|
while ((match = audioSrcRe.exec(html)) !== null) {
|
|
@@ -6611,15 +6637,17 @@ function lintAudioSrcNotFound(projectDir, htmlSources) {
|
|
|
6611
6637
|
if (isUnresolvedAssetPlaceholder2(src)) continue;
|
|
6612
6638
|
const rootRelative = compSrcPath ? rewriteAssetPath2(compSrcPath, src, (path) => existsSync2(join2(projectDir, path))) : src;
|
|
6613
6639
|
if (!existsSync2(resolveProjectRelativeSrc(rootRelative, projectDir))) {
|
|
6614
|
-
|
|
6640
|
+
const file = sourceFile(projectDir, compSrcPath);
|
|
6641
|
+
missingByFile.set(file, (missingByFile.get(file) ?? /* @__PURE__ */ new Set()).add(src));
|
|
6615
6642
|
}
|
|
6616
6643
|
}
|
|
6617
6644
|
}
|
|
6618
|
-
|
|
6619
|
-
const unique = [...
|
|
6645
|
+
for (const [file, srcs] of missingByFile) {
|
|
6646
|
+
const unique = [...srcs];
|
|
6620
6647
|
findings.push({
|
|
6621
6648
|
code: "audio_src_not_found",
|
|
6622
6649
|
severity: "error",
|
|
6650
|
+
file,
|
|
6623
6651
|
message: `<audio> element references file(s) not found in the project: ${unique.join(", ")}. The rendered video will be silent.`,
|
|
6624
6652
|
fixHint: unique.length === 1 ? `Add the file "${unique[0]}" to the project directory, or update the src attribute to point to an existing file.` : `Add the missing files to the project directory, or update the src attributes to point to existing files.`
|
|
6625
6653
|
});
|
|
@@ -6645,19 +6673,22 @@ function lintMissingLocalAsset(projectDir, htmlSources) {
|
|
|
6645
6673
|
const resolvedAsset = resolveExistingLocalAsset2(projectDir, rootRelative);
|
|
6646
6674
|
if (resolvedAsset) continue;
|
|
6647
6675
|
const resolvedKey = resolve(projectDir, rootRelative);
|
|
6648
|
-
|
|
6676
|
+
const file = sourceFile(projectDir, compSrcPath);
|
|
6677
|
+
const bucketKey = `${file}\0${tagName}`;
|
|
6678
|
+
let bucket = missingByTag.get(bucketKey);
|
|
6649
6679
|
if (!bucket) {
|
|
6650
|
-
bucket = /* @__PURE__ */ new Map();
|
|
6651
|
-
missingByTag.set(
|
|
6680
|
+
bucket = { file, tagName, byResolved: /* @__PURE__ */ new Map() };
|
|
6681
|
+
missingByTag.set(bucketKey, bucket);
|
|
6652
6682
|
}
|
|
6653
|
-
if (!bucket.has(resolvedKey)) bucket.set(resolvedKey, src);
|
|
6683
|
+
if (!bucket.byResolved.has(resolvedKey)) bucket.byResolved.set(resolvedKey, src);
|
|
6654
6684
|
}
|
|
6655
6685
|
}
|
|
6656
|
-
for (const
|
|
6686
|
+
for (const { file, tagName, byResolved } of missingByTag.values()) {
|
|
6657
6687
|
const unique = [...byResolved.values()];
|
|
6658
6688
|
findings.push({
|
|
6659
6689
|
code: "missing_local_asset",
|
|
6660
6690
|
severity: "error",
|
|
6691
|
+
file,
|
|
6661
6692
|
message: `<${tagName}> element references local file(s) not found in the project: ${unique.join(", ")}. The renderer will silently skip these and produce a video with missing visuals.`,
|
|
6662
6693
|
fixHint: unique.length === 1 ? `Add "${unique[0]}" to the project directory, or update the src attribute to point to an existing file. Common cause: captured asset filenames are unreliable (heygen-logo.svg often contains Google, nvidia-logo.svg may contain Autodesk, etc.). Open the contact sheets and verify the file actually exists at this path before referencing it.` : "Add the missing files to the project directory, or update the src attributes to point to existing files. Captured asset filenames are unreliable \u2014 verify against capture/contact-sheets/ and capture/extracted/asset-descriptions.md."
|
|
6663
6694
|
});
|
|
@@ -6665,8 +6696,9 @@ function lintMissingLocalAsset(projectDir, htmlSources) {
|
|
|
6665
6696
|
return findings;
|
|
6666
6697
|
}
|
|
6667
6698
|
function lintTextureMaskAssetNotFound(projectDir, htmlSources) {
|
|
6668
|
-
const
|
|
6699
|
+
const missingByFile = /* @__PURE__ */ new Map();
|
|
6669
6700
|
for (const { html, compSrcPath } of htmlSources) {
|
|
6701
|
+
const file = sourceFile(projectDir, compSrcPath);
|
|
6670
6702
|
for (const cssSource of collectCssSources(projectDir, html, compSrcPath)) {
|
|
6671
6703
|
let match;
|
|
6672
6704
|
const pattern = new RegExp(MASK_IMAGE_URL_RE.source, MASK_IMAGE_URL_RE.flags);
|
|
@@ -6682,20 +6714,20 @@ function lintTextureMaskAssetNotFound(projectDir, htmlSources) {
|
|
|
6682
6714
|
cssSource.rootRelativePath
|
|
6683
6715
|
);
|
|
6684
6716
|
if (candidates.some(existsSync2)) continue;
|
|
6685
|
-
|
|
6717
|
+
missingByFile.set(file, (missingByFile.get(file) ?? /* @__PURE__ */ new Set()).add(url));
|
|
6686
6718
|
}
|
|
6687
6719
|
}
|
|
6688
6720
|
}
|
|
6689
|
-
|
|
6690
|
-
|
|
6691
|
-
|
|
6692
|
-
{
|
|
6721
|
+
return [...missingByFile].map(([file, found]) => {
|
|
6722
|
+
const urls = [...found];
|
|
6723
|
+
return {
|
|
6693
6724
|
code: "texture_mask_asset_not_found",
|
|
6694
6725
|
severity: "error",
|
|
6726
|
+
file,
|
|
6695
6727
|
message: `CSS mask-image references file(s) not found in the project: ${urls.join(", ")}.`,
|
|
6696
6728
|
fixHint: urls.length === 1 ? `Add "${urls[0]}" to the project, or update the mask-image URL to point to an existing texture mask.` : "Add the missing texture mask files to the project, or update the mask-image URLs to point to existing files."
|
|
6697
|
-
}
|
|
6698
|
-
|
|
6729
|
+
};
|
|
6730
|
+
});
|
|
6699
6731
|
}
|
|
6700
6732
|
function lintMultipleRootCompositions(projectDir) {
|
|
6701
6733
|
const findings = [];
|