@hyperframes/lint 0.8.207 → 0.8.209

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 CHANGED
@@ -4117,6 +4117,23 @@ ${allInlineStyles}`.replace(/\/\*[\s\S]*?\*\//g, "");
4117
4117
  snippet: truncateSnippet(rootTag.raw)
4118
4118
  }
4119
4119
  ];
4120
+ },
4121
+ // subcomposition_linked_style_names_root_id
4122
+ // The compiler flattens a sub-composition root into its host and rewrites inline <style>
4123
+ // selectors to match; a linked stylesheet is not rewritten, so `#root-id` in it matches nothing.
4124
+ ({ styles, rootTag, options }) => {
4125
+ if (!options.isSubComposition || !rootTag) return [];
4126
+ const rootId = readAttr(rootTag.raw, "id");
4127
+ if (!rootId) return [];
4128
+ const escaped = rootId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4129
+ const names = new RegExp(`#${escaped}(?![\\w-])`);
4130
+ return styles.filter((style) => style.index === -1 && names.test(stripCssComments(style.content))).map((style) => ({
4131
+ code: "subcomposition_linked_style_names_root_id",
4132
+ severity: "warning",
4133
+ message: `The linked stylesheet "${style.rootRelativePath ?? style.file}" has a rule on #${rootId}, the id of this sub-composition's root. The root is merged into its host when the composition is compiled, so that selector matches nothing (the same rule in an inline <style> is rewritten and works).`,
4134
+ fixHint: `Move the #${rootId} rules into a <style> inside the <template>, where they are rewritten for the merged root, or select a child element of the root in the linked file instead of the root itself.`,
4135
+ snippet: truncateSnippet(style.content.slice(0, 120))
4136
+ }));
4120
4137
  }
4121
4138
  ];
4122
4139
  var CLIP_MEDIA_TAGS = /* @__PURE__ */ new Set(["img", "video", "audio"]);
@@ -6872,6 +6889,55 @@ var shaderRules = [
6872
6889
  })
6873
6890
  ];
6874
6891
 
6892
+ // src/rules/rootPaths.ts
6893
+ var CSS_ROOT_URL = /\burl\(\s*["']?(\/(?!\/)[^"')\s]*)/g;
6894
+ var SCRIPT_ROOT_URL = /\b(?:fetch|new\s+URL)\(\s*(["'`])(\/(?!\/)[^"'`$]*)\1/g;
6895
+ function relativeForm(path, cssFile) {
6896
+ const depth = (cssFile ?? "").split("/").filter(Boolean).length - 1;
6897
+ return `${"../".repeat(Math.max(depth, 0))}${path.slice(1)}`;
6898
+ }
6899
+ function rootPathFinding(path, cssFile, snippet) {
6900
+ return {
6901
+ code: "root_path_missing_in_preview",
6902
+ severity: "warning",
6903
+ message: `"${path}" starts at the server's root. Render and snapshot serve the project there, but Studio's preview serves it under the project's own path, so the preview cannot find this file.`,
6904
+ fixHint: `Use "${relativeForm(path, cssFile)}" instead.`,
6905
+ snippet: truncateSnippet(snippet)
6906
+ };
6907
+ }
6908
+ function cssRootPaths(css, cssFile) {
6909
+ return [...css.matchAll(CSS_ROOT_URL)].map(
6910
+ (match) => rootPathFinding(match[1] ?? "", cssFile, match[0])
6911
+ );
6912
+ }
6913
+ var scriptRootPaths = (script) => [...script.matchAll(SCRIPT_ROOT_URL)].map(
6914
+ (match) => rootPathFinding(match[2] ?? "", void 0, match[0])
6915
+ );
6916
+ function invalidImportMap(script) {
6917
+ if (!/\btype\s*=\s*["']?importmap\b/i.test(script.attrs)) return [];
6918
+ try {
6919
+ JSON.parse(script.content);
6920
+ return [];
6921
+ } catch (error) {
6922
+ return [
6923
+ {
6924
+ code: "import_map_invalid",
6925
+ severity: "warning",
6926
+ message: `This import map is not valid JSON (${error instanceof Error ? error.message : String(error)}). The browser ignores it, and preview cannot map root module paths ("/assets/x.js") to the project.`,
6927
+ fixHint: "Make the import map valid JSON: double-quoted keys and values, no trailing commas.",
6928
+ snippet: truncateSnippet(script.content)
6929
+ }
6930
+ ];
6931
+ }
6932
+ }
6933
+ var rootPathRules = [
6934
+ (ctx) => [
6935
+ ...ctx.styles.filter((style) => style.rootRelativePath).flatMap((style) => cssRootPaths(style.content, style.rootRelativePath)),
6936
+ ...ctx.scripts.flatMap((script) => scriptRootPaths(script.content)),
6937
+ ...ctx.scripts.flatMap(invalidImportMap)
6938
+ ]
6939
+ ];
6940
+
6875
6941
  // src/hyperframeLinter.ts
6876
6942
  var RULE_GROUPS = [
6877
6943
  { group: "core", rules: coreRules },
@@ -6884,7 +6950,8 @@ var RULE_GROUPS = [
6884
6950
  { group: "fonts", rules: fontRules },
6885
6951
  { group: "slideshow", rules: slideshowRules },
6886
6952
  { group: "structure", rules: structureRules },
6887
- { group: "shaders", rules: shaderRules }
6953
+ { group: "shaders", rules: shaderRules },
6954
+ { group: "rootPaths", rules: rootPathRules }
6888
6955
  ];
6889
6956
  var LINT_RULE_COUNT = RULE_GROUPS.reduce((n, g) => n + g.rules.length, 0);
6890
6957
  var LINT_RULE_GROUP_COUNTS = Object.fromEntries(
package/dist/index.js CHANGED
@@ -4123,6 +4123,23 @@ ${allInlineStyles}`.replace(/\/\*[\s\S]*?\*\//g, "");
4123
4123
  snippet: truncateSnippet(rootTag.raw)
4124
4124
  }
4125
4125
  ];
4126
+ },
4127
+ // subcomposition_linked_style_names_root_id
4128
+ // The compiler flattens a sub-composition root into its host and rewrites inline <style>
4129
+ // selectors to match; a linked stylesheet is not rewritten, so `#root-id` in it matches nothing.
4130
+ ({ styles, rootTag, options }) => {
4131
+ if (!options.isSubComposition || !rootTag) return [];
4132
+ const rootId = readAttr(rootTag.raw, "id");
4133
+ if (!rootId) return [];
4134
+ const escaped = rootId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4135
+ const names = new RegExp(`#${escaped}(?![\\w-])`);
4136
+ return styles.filter((style) => style.index === -1 && names.test(stripCssComments(style.content))).map((style) => ({
4137
+ code: "subcomposition_linked_style_names_root_id",
4138
+ severity: "warning",
4139
+ message: `The linked stylesheet "${style.rootRelativePath ?? style.file}" has a rule on #${rootId}, the id of this sub-composition's root. The root is merged into its host when the composition is compiled, so that selector matches nothing (the same rule in an inline <style> is rewritten and works).`,
4140
+ fixHint: `Move the #${rootId} rules into a <style> inside the <template>, where they are rewritten for the merged root, or select a child element of the root in the linked file instead of the root itself.`,
4141
+ snippet: truncateSnippet(style.content.slice(0, 120))
4142
+ }));
4126
4143
  }
4127
4144
  ];
4128
4145
  var CLIP_MEDIA_TAGS = /* @__PURE__ */ new Set(["img", "video", "audio"]);
@@ -6878,6 +6895,55 @@ var shaderRules = [
6878
6895
  })
6879
6896
  ];
6880
6897
 
6898
+ // src/rules/rootPaths.ts
6899
+ var CSS_ROOT_URL = /\burl\(\s*["']?(\/(?!\/)[^"')\s]*)/g;
6900
+ var SCRIPT_ROOT_URL = /\b(?:fetch|new\s+URL)\(\s*(["'`])(\/(?!\/)[^"'`$]*)\1/g;
6901
+ function relativeForm(path, cssFile) {
6902
+ const depth = (cssFile ?? "").split("/").filter(Boolean).length - 1;
6903
+ return `${"../".repeat(Math.max(depth, 0))}${path.slice(1)}`;
6904
+ }
6905
+ function rootPathFinding(path, cssFile, snippet) {
6906
+ return {
6907
+ code: "root_path_missing_in_preview",
6908
+ severity: "warning",
6909
+ message: `"${path}" starts at the server's root. Render and snapshot serve the project there, but Studio's preview serves it under the project's own path, so the preview cannot find this file.`,
6910
+ fixHint: `Use "${relativeForm(path, cssFile)}" instead.`,
6911
+ snippet: truncateSnippet(snippet)
6912
+ };
6913
+ }
6914
+ function cssRootPaths(css, cssFile) {
6915
+ return [...css.matchAll(CSS_ROOT_URL)].map(
6916
+ (match) => rootPathFinding(match[1] ?? "", cssFile, match[0])
6917
+ );
6918
+ }
6919
+ var scriptRootPaths = (script) => [...script.matchAll(SCRIPT_ROOT_URL)].map(
6920
+ (match) => rootPathFinding(match[2] ?? "", void 0, match[0])
6921
+ );
6922
+ function invalidImportMap(script) {
6923
+ if (!/\btype\s*=\s*["']?importmap\b/i.test(script.attrs)) return [];
6924
+ try {
6925
+ JSON.parse(script.content);
6926
+ return [];
6927
+ } catch (error) {
6928
+ return [
6929
+ {
6930
+ code: "import_map_invalid",
6931
+ severity: "warning",
6932
+ message: `This import map is not valid JSON (${error instanceof Error ? error.message : String(error)}). The browser ignores it, and preview cannot map root module paths ("/assets/x.js") to the project.`,
6933
+ fixHint: "Make the import map valid JSON: double-quoted keys and values, no trailing commas.",
6934
+ snippet: truncateSnippet(script.content)
6935
+ }
6936
+ ];
6937
+ }
6938
+ }
6939
+ var rootPathRules = [
6940
+ (ctx) => [
6941
+ ...ctx.styles.filter((style) => style.rootRelativePath).flatMap((style) => cssRootPaths(style.content, style.rootRelativePath)),
6942
+ ...ctx.scripts.flatMap((script) => scriptRootPaths(script.content)),
6943
+ ...ctx.scripts.flatMap(invalidImportMap)
6944
+ ]
6945
+ ];
6946
+
6881
6947
  // src/hyperframeLinter.ts
6882
6948
  var RULE_GROUPS = [
6883
6949
  { group: "core", rules: coreRules },
@@ -6890,7 +6956,8 @@ var RULE_GROUPS = [
6890
6956
  { group: "fonts", rules: fontRules },
6891
6957
  { group: "slideshow", rules: slideshowRules },
6892
6958
  { group: "structure", rules: structureRules },
6893
- { group: "shaders", rules: shaderRules }
6959
+ { group: "shaders", rules: shaderRules },
6960
+ { group: "rootPaths", rules: rootPathRules }
6894
6961
  ];
6895
6962
  var LINT_RULE_COUNT = RULE_GROUPS.reduce((n, g) => n + g.rules.length, 0);
6896
6963
  var LINT_RULE_GROUP_COUNTS = Object.fromEntries(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperframes/lint",
3
- "version": "0.8.207",
3
+ "version": "0.8.209",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/heygen-com/hyperframes",
@@ -35,7 +35,7 @@
35
35
  "linkedom": "^0.18.12",
36
36
  "postcss": "^8.5.8",
37
37
  "postcss-selector-parser": "^7.1.4",
38
- "@hyperframes/parsers": "0.8.207"
38
+ "@hyperframes/parsers": "0.8.209"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/node": "^25.0.10",