@hyperframes/lint 0.7.71 → 0.7.72
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 +51 -21
- package/dist/browser.js.map +1 -1
- package/dist/index.js +51 -21
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -861,6 +861,7 @@ var coreRules = [
|
|
|
861
861
|
];
|
|
862
862
|
|
|
863
863
|
// src/rules/media.ts
|
|
864
|
+
import { validateColorGradingContract } from "@hyperframes/parsers/color-grading-contract";
|
|
864
865
|
function escapeRegExp2(value) {
|
|
865
866
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
866
867
|
}
|
|
@@ -1063,6 +1064,56 @@ var mediaRules = [
|
|
|
1063
1064
|
}
|
|
1064
1065
|
return findings;
|
|
1065
1066
|
},
|
|
1067
|
+
// color_grading_* — grading is a structured media-only contract. Unknown
|
|
1068
|
+
// keys are ignored by the runtime, so catch them before an agent can report
|
|
1069
|
+
// controls that never actually rendered.
|
|
1070
|
+
({ tags }) => {
|
|
1071
|
+
const findings = [];
|
|
1072
|
+
for (const tag of tags) {
|
|
1073
|
+
const raw = readDecodedAttr(tag.raw, "data-color-grading");
|
|
1074
|
+
if (raw === null) continue;
|
|
1075
|
+
const elementId = readAttr(tag.raw, "id") || void 0;
|
|
1076
|
+
const report = (code, message, fixHint) => {
|
|
1077
|
+
findings.push({
|
|
1078
|
+
code,
|
|
1079
|
+
severity: "error",
|
|
1080
|
+
message,
|
|
1081
|
+
elementId,
|
|
1082
|
+
fixHint,
|
|
1083
|
+
snippet: truncateSnippet(tag.raw)
|
|
1084
|
+
});
|
|
1085
|
+
};
|
|
1086
|
+
if (tag.name !== "video" && tag.name !== "img") {
|
|
1087
|
+
report(
|
|
1088
|
+
"color_grading_non_media",
|
|
1089
|
+
`data-color-grading on <${tag.name}> has no effect. The shader runtime only grades real <video> and <img> elements.`,
|
|
1090
|
+
"Move the grading attribute to the real <video> or <img> media element. Do not attach it to a wrapper or CSS background."
|
|
1091
|
+
);
|
|
1092
|
+
continue;
|
|
1093
|
+
}
|
|
1094
|
+
const trimmed = raw.trim();
|
|
1095
|
+
if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) continue;
|
|
1096
|
+
let parsed;
|
|
1097
|
+
try {
|
|
1098
|
+
parsed = JSON.parse(trimmed);
|
|
1099
|
+
} catch {
|
|
1100
|
+
report(
|
|
1101
|
+
"color_grading_invalid_json",
|
|
1102
|
+
"data-color-grading contains malformed JSON and will not render.",
|
|
1103
|
+
'Use valid JSON, for example {"preset":"skin-soft","intensity":0.6,"adjust":{"highlights":-0.08}}.'
|
|
1104
|
+
);
|
|
1105
|
+
continue;
|
|
1106
|
+
}
|
|
1107
|
+
for (const issue of validateColorGradingContract(parsed)) {
|
|
1108
|
+
report(
|
|
1109
|
+
"color_grading_invalid_structure",
|
|
1110
|
+
`data-color-grading ${issue.path} ${issue.message}.`,
|
|
1111
|
+
issue.hint ?? "Use the documented media-treatment contract and correct or remove the invalid value."
|
|
1112
|
+
);
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
return findings;
|
|
1116
|
+
},
|
|
1066
1117
|
// video_missing_muted
|
|
1067
1118
|
({ tags }) => {
|
|
1068
1119
|
const findings = [];
|
|
@@ -1149,27 +1200,6 @@ var mediaRules = [
|
|
|
1149
1200
|
}
|
|
1150
1201
|
return findings;
|
|
1151
1202
|
},
|
|
1152
|
-
// media_in_subcomposition — <video>/<audio> only render as a DIRECT child of the host
|
|
1153
|
-
// root (index.html). Inside a sub-composition <template> the runtime never seeks/decodes
|
|
1154
|
-
// them, so they render BLANK/black in preview and renders — and the other lint/validate
|
|
1155
|
-
// passes otherwise miss it (only a per-frame snapshot reveals the blank panel).
|
|
1156
|
-
({ tags, options }) => {
|
|
1157
|
-
const findings = [];
|
|
1158
|
-
if (!options.isSubComposition) return findings;
|
|
1159
|
-
for (const tag of tags) {
|
|
1160
|
-
if (tag.name !== "video" && tag.name !== "audio") continue;
|
|
1161
|
-
const elementId = readAttr(tag.raw, "id") || void 0;
|
|
1162
|
-
findings.push({
|
|
1163
|
-
code: "media_in_subcomposition",
|
|
1164
|
-
severity: "error",
|
|
1165
|
-
message: `<${tag.name}${elementId ? ` id="${elementId}"` : ""}> is inside a sub-composition. The runtime only drives media that is a DIRECT child of the host root (index.html); media inside a sub-comp <template> is never seeked/decoded and renders BLANK/black in preview and renders.`,
|
|
1166
|
-
elementId,
|
|
1167
|
-
fixHint: "Move the media OUT of the sub-composition: place the <video>/<audio> as a direct child of #root in index.html, positioned over the scene, and drive any per-scene motion on the MAIN timeline at global time (a sub-comp timeline cannot reach host elements). See composition-patterns.md archetype B.",
|
|
1168
|
-
snippet: truncateSnippet(tag.raw)
|
|
1169
|
-
});
|
|
1170
|
-
}
|
|
1171
|
-
return findings;
|
|
1172
|
-
},
|
|
1173
1203
|
// self_closing_media_tag
|
|
1174
1204
|
({ source }) => {
|
|
1175
1205
|
const findings = [];
|