@hyperframes/lint 0.9.20 → 0.9.22

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/index.d.ts CHANGED
@@ -107,9 +107,15 @@ interface ProjectLintResult {
107
107
  totalErrors: number;
108
108
  totalWarnings: number;
109
109
  totalInfos: number;
110
+ unmountedCompositions?: string[];
111
+ }
112
+ /** The one line a run prints when it left unmounted compositions out. */
113
+ declare function unmountedNotice(count: number): string;
114
+ interface ProjectLintOptions {
115
+ includeUnmounted?: boolean;
110
116
  }
111
117
  declare function linkedSources(projectDir: string, html: string, compSrcPath?: string): Pick<HyperframeLinterOptions, "externalStyles" | "externalScripts">;
112
- declare function lintProject(projectDir: string, entryFile?: string, hostOptions?: Pick<HyperframeLinterOptions, "host" | "isSubComposition">): Promise<ProjectLintResult>;
118
+ declare function lintProject(projectDir: string, entryFile?: string, hostOptions?: Pick<HyperframeLinterOptions, "host" | "isSubComposition">, { includeUnmounted }?: ProjectLintOptions): Promise<ProjectLintResult>;
113
119
 
114
120
  /** What the project leaves out; ask with a relative `/` path, a folder with a trailing `/`. */
115
121
  declare function projectIgnore(projectDir: string): Ignore;
@@ -121,4 +127,4 @@ type AudioAttribute = "data-automation" | "data-fx-chain";
121
127
  */
122
128
  declare function audioAttributeShapeError(attr: AudioAttribute, json: string): string | null;
123
129
 
124
- export { type AudioAttribute, type HyperframeLintFinding, type HyperframeLintResult, type HyperframeLintSeverity, type HyperframeLinterOptions, LINT_RULE_COUNT, LINT_RULE_GROUP_COUNTS, type LintTimings, type ProjectLintResult, audioAttributeShapeError, linkedSources, lintHyperframeHtml, lintMediaUrls, lintProject, projectIgnore, shouldBlockRender };
130
+ export { type AudioAttribute, type HyperframeLintFinding, type HyperframeLintResult, type HyperframeLintSeverity, type HyperframeLinterOptions, LINT_RULE_COUNT, LINT_RULE_GROUP_COUNTS, type LintTimings, type ProjectLintOptions, type ProjectLintResult, audioAttributeShapeError, linkedSources, lintHyperframeHtml, lintMediaUrls, lintProject, projectIgnore, shouldBlockRender, unmountedNotice };
package/dist/index.js CHANGED
@@ -7616,6 +7616,10 @@ function querySelectorAllIncludingTemplates(root, selector) {
7616
7616
  }
7617
7617
  return matches;
7618
7618
  }
7619
+ function unmountedNotice(count) {
7620
+ const skipped = count === 1 ? "1 file in compositions/ is" : `${count} files in compositions/ are`;
7621
+ return `${skipped} not mounted from index.html, so not checked; --include-unmounted adds them.`;
7622
+ }
7619
7623
  function contentDigest(html) {
7620
7624
  return createHash("sha256").update(html).digest("hex").slice(0, 16);
7621
7625
  }
@@ -7755,7 +7759,7 @@ function declaredProjectFontFamilies(projectDir, sources) {
7755
7759
  }
7756
7760
  return [...families];
7757
7761
  }
7758
- async function lintProject(projectDir, entryFile, hostOptions = {}) {
7762
+ async function lintProject(projectDir, entryFile, hostOptions = {}, { includeUnmounted = false } = {}) {
7759
7763
  const indexPath = entryFile ? resolve(entryFile) : resolve(projectDir, "index.html");
7760
7764
  if (entryFile && !isWithinProjectRoot2(projectDir, indexPath)) {
7761
7765
  throw new Error(`Explicit lint entry is outside the project directory: ${entryFile}`);
@@ -7767,10 +7771,11 @@ async function lintProject(projectDir, entryFile, hostOptions = {}) {
7767
7771
  let totalWarnings = 0;
7768
7772
  let totalInfos = 0;
7769
7773
  const rootHtml = readTextFile(indexPath);
7770
- const projectFontFamilies = declaredProjectFontFamilies(
7771
- projectDir,
7772
- mountedSources(projectDir, rootHtml, rootCompSrcPath)
7773
- );
7774
+ const mounted = mountedSources(projectDir, rootHtml, rootCompSrcPath);
7775
+ const mountedPaths = new Set(mounted.map((source) => source.compSrcPath));
7776
+ const unmountedCompositions = [];
7777
+ const unmountedSources = [];
7778
+ const projectFontFamilies = declaredProjectFontFamilies(projectDir, mounted);
7774
7779
  const rootResult = await lintHyperframeHtml(rootHtml, {
7775
7780
  ...hostOptions,
7776
7781
  filePath: indexPath,
@@ -7805,6 +7810,11 @@ async function lintProject(projectDir, entryFile, hostOptions = {}) {
7805
7810
  const filePath = join4(compositionsDir, file);
7806
7811
  const html = readTextFile(filePath);
7807
7812
  const compSrcPath = `compositions/${file}`;
7813
+ if (!includeUnmounted && !mountedPaths.has(compSrcPath)) {
7814
+ unmountedSources.push({ html, compSrcPath });
7815
+ if (!isSnippetFragment(html)) unmountedCompositions.push(compSrcPath);
7816
+ continue;
7817
+ }
7808
7818
  allHtmlSources.push({ html, compSrcPath });
7809
7819
  if (isSnippetFragment(html)) continue;
7810
7820
  const result = await lintHyperframeHtml(html, {
@@ -7833,7 +7843,7 @@ async function lintProject(projectDir, entryFile, hostOptions = {}) {
7833
7843
  ...lintTextureMaskAssetNotFound(projectDir, allHtmlSources),
7834
7844
  ...lintLinkedStylesheetAssets(projectDir, allHtmlSources),
7835
7845
  ...!entryFile ? lintMultipleRootCompositions(projectDir) : [],
7836
- ...!entryFile ? lintBlankRootWithStandaloneComposition(rootHtml, allHtmlSources) : [],
7846
+ ...!entryFile ? lintBlankRootWithStandaloneComposition(rootHtml, [...allHtmlSources, ...unmountedSources]) : [],
7837
7847
  ...lintDuplicateAudioTracks(projectDir, rootHtml),
7838
7848
  ...lintMissingOrEmptySubComposition(projectDir, rootHtml),
7839
7849
  ...await lintVideoMediaStartPastEof(projectDir, allHtmlSources),
@@ -7855,7 +7865,7 @@ async function lintProject(projectDir, entryFile, hostOptions = {}) {
7855
7865
  totalInfos++;
7856
7866
  }
7857
7867
  }
7858
- return { results, totalErrors, totalWarnings, totalInfos };
7868
+ return { results, totalErrors, totalWarnings, totalInfos, unmountedCompositions };
7859
7869
  }
7860
7870
  function lintBlankRootWithStandaloneComposition(rootHtml, htmlSources) {
7861
7871
  const { document: rootDocument } = parseHTML3(rootHtml);
@@ -8000,6 +8010,12 @@ function lintMissingLocalAsset(projectDir, htmlSources) {
8000
8010
  }
8001
8011
  return findings;
8002
8012
  }
8013
+ function localCssUrl(match) {
8014
+ const rawUrl = match[1] ?? match[2] ?? match[3] ?? "";
8015
+ if (isUnresolvedAssetPlaceholder2(rawUrl)) return void 0;
8016
+ const url = cleanAssetUrl2(rawUrl);
8017
+ return url && !isRemoteOrInlineUrl2(url) ? url : void 0;
8018
+ }
8003
8019
  function lintTextureMaskAssetNotFound(projectDir, htmlSources) {
8004
8020
  const missingByFile = /* @__PURE__ */ new Map();
8005
8021
  for (const { html, compSrcPath } of htmlSources) {
@@ -8015,10 +8031,8 @@ function lintTextureMaskAssetNotFound(projectDir, htmlSources) {
8015
8031
  matches = [...cssSource.content.matchAll(MASK_IMAGE_URL_RE)];
8016
8032
  }
8017
8033
  for (const match of matches) {
8018
- const rawUrl = match[1] ?? match[2] ?? match[3] ?? "";
8019
- if (isUnresolvedAssetPlaceholder2(rawUrl)) continue;
8020
- const url = cleanAssetUrl2(rawUrl);
8021
- if (!url || isRemoteOrInlineUrl2(url)) continue;
8034
+ const url = localCssUrl(match);
8035
+ if (!url) continue;
8022
8036
  const candidates = resolveCssAssetCandidates(
8023
8037
  projectDir,
8024
8038
  url,
@@ -8073,10 +8087,8 @@ function lintLinkedStylesheetAssets(projectDir, htmlSources) {
8073
8087
  root.walkDecls((declaration) => {
8074
8088
  if (/^(?:-webkit-)?mask-image$/i.test(declaration.prop)) return;
8075
8089
  for (const match of declaration.value.matchAll(CSS_URL_RE)) {
8076
- const rawUrl = match[1] ?? match[2] ?? match[3] ?? "";
8077
- if (isUnresolvedAssetPlaceholder2(rawUrl)) continue;
8078
- const url = cleanAssetUrl2(rawUrl);
8079
- if (!url || isRemoteOrInlineUrl2(url) || url.startsWith("/")) continue;
8090
+ const url = localCssUrl(match);
8091
+ if (!url || url.startsWith("/")) continue;
8080
8092
  if (resolveCssAssetCandidates(projectDir, url, void 0, rootRelativePath).some(existsSync3))
8081
8093
  continue;
8082
8094
  const key = `${rootRelativePath}\0${url}`;
@@ -8276,5 +8288,6 @@ export {
8276
8288
  lintMediaUrls,
8277
8289
  lintProject,
8278
8290
  projectIgnore,
8279
- shouldBlockRender
8291
+ shouldBlockRender,
8292
+ unmountedNotice
8280
8293
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperframes/lint",
3
- "version": "0.9.20",
3
+ "version": "0.9.22",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/heygen-com/hyperframes",
@@ -36,7 +36,7 @@
36
36
  "linkedom": "^0.18.12",
37
37
  "postcss": "^8.5.8",
38
38
  "postcss-selector-parser": "^7.1.4",
39
- "@hyperframes/parsers": "0.9.20"
39
+ "@hyperframes/parsers": "0.9.22"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@types/node": "^25.0.10",