@jay-framework/design-system-validator 0.24.6 → 0.25.0
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/tools.d.ts +3 -1
- package/dist/tools.js +62 -10
- package/package.json +13 -13
- package/plugin.yaml +4 -0
package/dist/tools.d.ts
CHANGED
|
@@ -17,6 +17,8 @@ declare const validateFontFallbacks: JayHtmlValidatorFn;
|
|
|
17
17
|
|
|
18
18
|
declare const validateUndefinedVars: JayHtmlValidatorFn;
|
|
19
19
|
|
|
20
|
+
declare const validateViewportHeight: JayHtmlValidatorFn;
|
|
21
|
+
|
|
20
22
|
declare const ADD_MENU_GENERATED_REL = "agent-kit/aiditor/add-menu/design-system.generated.yaml";
|
|
21
23
|
|
|
22
24
|
/**
|
|
@@ -98,4 +100,4 @@ declare const regenerateDesignSystemAddMenu: _jay_framework_fullstack_component.
|
|
|
98
100
|
message: any;
|
|
99
101
|
}, []>;
|
|
100
102
|
|
|
101
|
-
export { ADD_MENU_GENERATED_REL, generateDesignSystemAgentKit, getDesignSystemSettingsStatus, loadDesignSystemAddMenuCatalog, regenerateDesignSystemAddMenu, runDesignSystemAnalysisAction as runDesignSystemAnalysis, saveDesignSystemAddMenuCatalog, validateComponents, validateContrast, validateFontFallbacks, validateStructure, validateTokens, validateUndefinedVars };
|
|
103
|
+
export { ADD_MENU_GENERATED_REL, generateDesignSystemAgentKit, getDesignSystemSettingsStatus, loadDesignSystemAddMenuCatalog, regenerateDesignSystemAddMenu, runDesignSystemAnalysisAction as runDesignSystemAnalysis, saveDesignSystemAddMenuCatalog, validateComponents, validateContrast, validateFontFallbacks, validateStructure, validateTokens, validateUndefinedVars, validateViewportHeight };
|
package/dist/tools.js
CHANGED
|
@@ -189,16 +189,26 @@ function parseInlineStyles(style) {
|
|
|
189
189
|
}
|
|
190
190
|
return declarations;
|
|
191
191
|
}
|
|
192
|
+
function selectorTargetsRoot(root, selector) {
|
|
193
|
+
const trimmed = selector.trim();
|
|
194
|
+
if (trimmed === "html" || trimmed === ":root") return true;
|
|
195
|
+
try {
|
|
196
|
+
return root.closest(trimmed) === root;
|
|
197
|
+
} catch {
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
192
201
|
function buildSelectorCache(rules, root) {
|
|
193
202
|
const cache = /* @__PURE__ */ new Map();
|
|
194
203
|
for (const rule of rules) {
|
|
195
204
|
if (cache.has(rule.selector)) continue;
|
|
205
|
+
const matched = /* @__PURE__ */ new Set();
|
|
196
206
|
try {
|
|
197
|
-
const
|
|
198
|
-
cache.set(rule.selector, new Set(matches));
|
|
207
|
+
for (const el of root.querySelectorAll(rule.selector)) matched.add(el);
|
|
199
208
|
} catch {
|
|
200
|
-
cache.set(rule.selector, /* @__PURE__ */ new Set());
|
|
201
209
|
}
|
|
210
|
+
if (selectorTargetsRoot(root, rule.selector)) matched.add(root);
|
|
211
|
+
cache.set(rule.selector, matched);
|
|
202
212
|
}
|
|
203
213
|
return cache;
|
|
204
214
|
}
|
|
@@ -279,9 +289,7 @@ function resolveCascade(cssSources, root) {
|
|
|
279
289
|
if (child.nodeType === 1) walk(child);
|
|
280
290
|
}
|
|
281
291
|
}
|
|
282
|
-
|
|
283
|
-
if (child.nodeType === 1) walk(child);
|
|
284
|
-
}
|
|
292
|
+
walk(root);
|
|
285
293
|
return result;
|
|
286
294
|
}
|
|
287
295
|
function resolveCascadeByBreakpoint(cssSources, root) {
|
|
@@ -320,9 +328,7 @@ function resolveCascadeByBreakpoint(cssSources, root) {
|
|
|
320
328
|
);
|
|
321
329
|
const selectorCache = buildSelectorCache(rulesForBreakpoint, root);
|
|
322
330
|
const breakpointResult = /* @__PURE__ */ new Map();
|
|
323
|
-
|
|
324
|
-
if (child.nodeType === 1) walk(child);
|
|
325
|
-
}
|
|
331
|
+
walk(root);
|
|
326
332
|
result.set(breakpoint, breakpointResult);
|
|
327
333
|
}
|
|
328
334
|
return result;
|
|
@@ -1251,6 +1257,51 @@ See agent-kit/designer/design-system.md for usage guide.`
|
|
|
1251
1257
|
}
|
|
1252
1258
|
return findings;
|
|
1253
1259
|
};
|
|
1260
|
+
const VIEWPORT_HEIGHT_UNIT = /\d*\.?\d+(vh|svh|lvh|dvh|vmax)\b/i;
|
|
1261
|
+
const TOP_LEVEL_TAGS = /* @__PURE__ */ new Set(["html", "body", "main"]);
|
|
1262
|
+
const PARENT_TAGS = /* @__PURE__ */ new Set(["body", "main"]);
|
|
1263
|
+
const OUT_OF_FLOW = /* @__PURE__ */ new Set(["fixed", "absolute", "sticky"]);
|
|
1264
|
+
const HEIGHT_PROPS = ["height", "min-height"];
|
|
1265
|
+
function tagOf(el) {
|
|
1266
|
+
return (el?.rawTagName ?? "").toLowerCase();
|
|
1267
|
+
}
|
|
1268
|
+
function usesViewportHeight(value) {
|
|
1269
|
+
return value != null && VIEWPORT_HEIGHT_UNIT.test(value);
|
|
1270
|
+
}
|
|
1271
|
+
function isTopLevel(el) {
|
|
1272
|
+
if (TOP_LEVEL_TAGS.has(tagOf(el))) return true;
|
|
1273
|
+
return PARENT_TAGS.has(tagOf(el.parentNode));
|
|
1274
|
+
}
|
|
1275
|
+
const validateViewportHeight = (ctx) => {
|
|
1276
|
+
if (!ctx.css) return [];
|
|
1277
|
+
if (!ctx.filePath.includes("/pages/") && !ctx.filePath.startsWith("src/pages/")) {
|
|
1278
|
+
return [];
|
|
1279
|
+
}
|
|
1280
|
+
if (ctx.validationOverrides?.["design-system"]?.["allow-viewport-height"] === true) {
|
|
1281
|
+
return [];
|
|
1282
|
+
}
|
|
1283
|
+
const base = resolveCascadeByBreakpoint([ctx.css], ctx.body).get(void 0);
|
|
1284
|
+
if (!base) return [];
|
|
1285
|
+
const findings = [];
|
|
1286
|
+
for (const [el, styles] of base) {
|
|
1287
|
+
if (!isTopLevel(el)) continue;
|
|
1288
|
+
if (OUT_OF_FLOW.has(styles["position"]?.value?.trim().toLowerCase() ?? "")) continue;
|
|
1289
|
+
const maxHeight = styles["max-height"]?.value?.trim();
|
|
1290
|
+
const bounded = maxHeight != null && maxHeight.toLowerCase() !== "none" && !usesViewportHeight(maxHeight);
|
|
1291
|
+
if (bounded) continue;
|
|
1292
|
+
for (const property of HEIGHT_PROPS) {
|
|
1293
|
+
const decl = styles[property];
|
|
1294
|
+
if (!usesViewportHeight(decl?.value)) continue;
|
|
1295
|
+
findings.push({
|
|
1296
|
+
severity: "warning",
|
|
1297
|
+
message: `Top-level container "${decl.selector}" sets ${property}: ${decl.value}. Googlebot renders into a very tall viewport (~12,000px), so viewport-height units expand this section and distort Search Console screenshots / mobile-usability reports.`,
|
|
1298
|
+
suggestion: `Choose a fix by content type — text: chain height from a bounded ancestor; hero/visual: cap with max-height inside a mobile @media; overlay: this is safe, suppress with design-system: { allow-viewport-height: true }. Note: swapping vh → dvh/svh/lvh is NOT a fix (all resolve tall under Googlebot). See agent-kit/designer/jay-html-styling.md (and validation-guide.md for suppression).`,
|
|
1299
|
+
element: `<${tagOf(el)}>`
|
|
1300
|
+
});
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
return findings;
|
|
1304
|
+
};
|
|
1254
1305
|
const PLUGIN_ATTRS = {
|
|
1255
1306
|
pluginName: "design-system-validator",
|
|
1256
1307
|
packageName: "@jay-framework/design-system-validator"
|
|
@@ -1871,5 +1922,6 @@ export {
|
|
|
1871
1922
|
validateFontFallbacks,
|
|
1872
1923
|
validateStructure,
|
|
1873
1924
|
validateTokens,
|
|
1874
|
-
validateUndefinedVars
|
|
1925
|
+
validateUndefinedVars,
|
|
1926
|
+
validateViewportHeight
|
|
1875
1927
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jay-framework/design-system-validator",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Design system validation plugin for Jay Framework — validates jay-html CSS against DESIGN.md tokens",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -37,25 +37,25 @@
|
|
|
37
37
|
"@capsizecss/metrics": "^4.2.0",
|
|
38
38
|
"@capsizecss/unpack": "^4.0.1",
|
|
39
39
|
"@csstools/selector-specificity": "^5.0.0",
|
|
40
|
-
"@jay-framework/component": "^0.
|
|
41
|
-
"@jay-framework/fullstack-component": "^0.
|
|
42
|
-
"@jay-framework/plugin-validator": "^0.
|
|
43
|
-
"@jay-framework/stack-server-runtime": "^0.
|
|
40
|
+
"@jay-framework/component": "^0.25.0",
|
|
41
|
+
"@jay-framework/fullstack-component": "^0.25.0",
|
|
42
|
+
"@jay-framework/plugin-validator": "^0.25.0",
|
|
43
|
+
"@jay-framework/stack-server-runtime": "^0.25.0",
|
|
44
44
|
"js-yaml": "^4.1.0",
|
|
45
45
|
"postcss": "^8.5.6",
|
|
46
46
|
"postcss-selector-parser": "^7.1.0"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
|
-
"@jay-framework/compiler-jay-html": "^0.
|
|
50
|
-
"@jay-framework/compiler-shared": "^0.
|
|
49
|
+
"@jay-framework/compiler-jay-html": "^0.25.0",
|
|
50
|
+
"@jay-framework/compiler-shared": "^0.25.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@jay-framework/compiler-jay-html": "^0.
|
|
54
|
-
"@jay-framework/compiler-jay-stack": "^0.
|
|
55
|
-
"@jay-framework/compiler-shared": "^0.
|
|
56
|
-
"@jay-framework/dev-environment": "^0.
|
|
57
|
-
"@jay-framework/jay-cli": "^0.
|
|
58
|
-
"@jay-framework/jay-stack-cli": "^0.
|
|
53
|
+
"@jay-framework/compiler-jay-html": "^0.25.0",
|
|
54
|
+
"@jay-framework/compiler-jay-stack": "^0.25.0",
|
|
55
|
+
"@jay-framework/compiler-shared": "^0.25.0",
|
|
56
|
+
"@jay-framework/dev-environment": "^0.25.0",
|
|
57
|
+
"@jay-framework/jay-cli": "^0.25.0",
|
|
58
|
+
"@jay-framework/jay-stack-cli": "^0.25.0",
|
|
59
59
|
"@types/js-yaml": "^4.0.9",
|
|
60
60
|
"@types/node": "^22.15.21",
|
|
61
61
|
"node-html-parser": "^6.1.0",
|
package/plugin.yaml
CHANGED
|
@@ -51,3 +51,7 @@ validators:
|
|
|
51
51
|
- name: undefined-vars
|
|
52
52
|
handler: validateUndefinedVars
|
|
53
53
|
description: Flags CSS var(--name) references that are never defined as custom properties
|
|
54
|
+
|
|
55
|
+
- name: design-viewport-height
|
|
56
|
+
handler: validateViewportHeight
|
|
57
|
+
description: Flags unbounded viewport-height units (vh/svh/lvh/dvh/vmax) on top-level containers that distort Googlebot's tall-viewport render (Search Console screenshots / mobile-usability)
|