release: WRNexusJS 0.7.0
This commit is contained in:
@@ -78,3 +78,76 @@ export function contrast(foreground: string, background: string): ContrastResult
|
||||
level: ratio >= 7 ? "aaa" : ratio >= 4.5 ? "aa" : ratio >= 3 ? "aa-large" : "fail",
|
||||
};
|
||||
}
|
||||
|
||||
export interface CssPerformanceAuditIssue {
|
||||
code: string;
|
||||
severity: "error" | "warning" | "info";
|
||||
message: string;
|
||||
line?: number;
|
||||
}
|
||||
|
||||
function cssLineAt(source: string, offset: number): number {
|
||||
return source.slice(0, offset).split(/\r?\n/).length;
|
||||
}
|
||||
|
||||
/** Detect CSS patterns that commonly increase style, paint, or compositing cost. */
|
||||
export function auditCssPerformance(source: string): CssPerformanceAuditIssue[] {
|
||||
const issues: CssPerformanceAuditIssue[] = [];
|
||||
const checks: Array<{
|
||||
pattern: RegExp;
|
||||
code: string;
|
||||
severity: CssPerformanceAuditIssue["severity"];
|
||||
message: string;
|
||||
}> = [
|
||||
{
|
||||
pattern: /transition\s*:\s*all\b/gi,
|
||||
code: "WRN-CSS-TRANSITION-ALL",
|
||||
severity: "warning",
|
||||
message: "Avoid transition: all; list only properties that should animate.",
|
||||
},
|
||||
{
|
||||
pattern: /backdrop-filter\s*:\s*[^;]*(?:blur\((?:[3-9]\d|\d{3,})px\))/gi,
|
||||
code: "WRN-CSS-BACKDROP-BLUR",
|
||||
severity: "warning",
|
||||
message: "Large backdrop blur areas can be expensive to composite.",
|
||||
},
|
||||
{
|
||||
pattern: /box-shadow\s*:[^;]*(?:,\s*[^;]+){4,}/gi,
|
||||
code: "WRN-CSS-MANY-SHADOWS",
|
||||
severity: "warning",
|
||||
message: "Many layered shadows can increase paint cost.",
|
||||
},
|
||||
{
|
||||
pattern: /(?:^|[},])\s*\*\s*(?:[,{])/gm,
|
||||
code: "WRN-CSS-UNIVERSAL-SELECTOR",
|
||||
severity: "info",
|
||||
message: "Review universal selectors used in large DOM subtrees.",
|
||||
},
|
||||
];
|
||||
for (const check of checks) {
|
||||
for (const match of source.matchAll(check.pattern)) {
|
||||
issues.push({
|
||||
code: check.code,
|
||||
severity: check.severity,
|
||||
message: check.message,
|
||||
line: cssLineAt(source, match.index ?? 0),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const keyframes = new Map<string, number>();
|
||||
for (const match of source.matchAll(/@keyframes\s+([A-Za-z_][\w-]*)/g)) {
|
||||
const name = match[1]!;
|
||||
keyframes.set(name, (keyframes.get(name) ?? 0) + 1);
|
||||
}
|
||||
for (const [name, count] of keyframes) {
|
||||
if (count > 1) {
|
||||
issues.push({
|
||||
code: "WRN-CSS-DUPLICATE-KEYFRAMES",
|
||||
severity: "warning",
|
||||
message: `@keyframes ${name} is declared ${count} times.`,
|
||||
});
|
||||
}
|
||||
}
|
||||
return issues;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user