@harness-engineering/cli 1.6.2 → 1.8.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/agents/personas/documentation-maintainer.yaml +3 -1
- package/dist/agents/personas/performance-guardian.yaml +23 -0
- package/dist/agents/personas/planner.yaml +27 -0
- package/dist/agents/personas/verifier.yaml +30 -0
- package/dist/agents/skills/claude-code/align-documentation/SKILL.md +13 -0
- package/dist/agents/skills/claude-code/cleanup-dead-code/SKILL.md +25 -1
- package/dist/agents/skills/claude-code/cleanup-dead-code/skill.yaml +5 -2
- package/dist/agents/skills/claude-code/detect-doc-drift/SKILL.md +12 -0
- package/dist/agents/skills/claude-code/enforce-architecture/SKILL.md +67 -1
- package/dist/agents/skills/claude-code/enforce-architecture/skill.yaml +5 -2
- package/dist/agents/skills/claude-code/harness-accessibility/SKILL.md +281 -0
- package/dist/agents/skills/claude-code/harness-accessibility/skill.yaml +51 -0
- package/dist/agents/skills/claude-code/harness-autopilot/SKILL.md +119 -72
- package/dist/agents/skills/claude-code/harness-autopilot/skill.yaml +4 -2
- package/dist/agents/skills/claude-code/harness-brainstorming/SKILL.md +76 -4
- package/dist/agents/skills/claude-code/harness-brainstorming/skill.yaml +2 -0
- package/dist/agents/skills/claude-code/harness-code-review/SKILL.md +487 -234
- package/dist/agents/skills/claude-code/harness-code-review/skill.yaml +15 -2
- package/dist/agents/skills/claude-code/harness-codebase-cleanup/SKILL.md +226 -0
- package/dist/agents/skills/claude-code/harness-codebase-cleanup/skill.yaml +64 -0
- package/dist/agents/skills/claude-code/harness-dependency-health/SKILL.md +35 -6
- package/dist/agents/skills/claude-code/harness-dependency-health/skill.yaml +1 -1
- package/dist/agents/skills/claude-code/harness-design/SKILL.md +265 -0
- package/dist/agents/skills/claude-code/harness-design/skill.yaml +53 -0
- package/dist/agents/skills/claude-code/harness-design-mobile/SKILL.md +336 -0
- package/dist/agents/skills/claude-code/harness-design-mobile/skill.yaml +49 -0
- package/dist/agents/skills/claude-code/harness-design-system/SKILL.md +282 -0
- package/dist/agents/skills/claude-code/harness-design-system/skill.yaml +50 -0
- package/dist/agents/skills/claude-code/harness-design-web/SKILL.md +360 -0
- package/dist/agents/skills/claude-code/harness-design-web/skill.yaml +52 -0
- package/dist/agents/skills/claude-code/harness-docs-pipeline/SKILL.md +460 -0
- package/dist/agents/skills/claude-code/harness-docs-pipeline/skill.yaml +69 -0
- package/dist/agents/skills/claude-code/harness-execution/SKILL.md +73 -8
- package/dist/agents/skills/claude-code/harness-execution/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-hotspot-detector/SKILL.md +32 -6
- package/dist/agents/skills/claude-code/harness-hotspot-detector/skill.yaml +1 -1
- package/dist/agents/skills/claude-code/harness-i18n/SKILL.md +484 -0
- package/dist/agents/skills/claude-code/harness-i18n/skill.yaml +54 -0
- package/dist/agents/skills/claude-code/harness-i18n-process/SKILL.md +388 -0
- package/dist/agents/skills/claude-code/harness-i18n-process/skill.yaml +43 -0
- package/dist/agents/skills/claude-code/harness-i18n-workflow/SKILL.md +512 -0
- package/dist/agents/skills/claude-code/harness-i18n-workflow/skill.yaml +53 -0
- package/dist/agents/skills/claude-code/harness-impact-analysis/SKILL.md +51 -6
- package/dist/agents/skills/claude-code/harness-integrity/SKILL.md +35 -1
- package/dist/agents/skills/claude-code/harness-knowledge-mapper/SKILL.md +46 -5
- package/dist/agents/skills/claude-code/harness-knowledge-mapper/skill.yaml +1 -1
- package/dist/agents/skills/claude-code/harness-onboarding/SKILL.md +19 -1
- package/dist/agents/skills/claude-code/harness-perf/SKILL.md +37 -8
- package/dist/agents/skills/claude-code/harness-perf/skill.yaml +3 -0
- package/dist/agents/skills/claude-code/harness-perf-tdd/SKILL.md +17 -4
- package/dist/agents/skills/claude-code/harness-planning/SKILL.md +57 -3
- package/dist/agents/skills/claude-code/harness-planning/skill.yaml +2 -0
- package/dist/agents/skills/claude-code/harness-release-readiness/SKILL.md +29 -9
- package/dist/agents/skills/claude-code/harness-roadmap/SKILL.md +562 -0
- package/dist/agents/skills/claude-code/harness-roadmap/skill.yaml +43 -0
- package/dist/agents/skills/claude-code/harness-security-review/SKILL.md +36 -2
- package/dist/agents/skills/claude-code/harness-security-review/skill.yaml +8 -6
- package/dist/agents/skills/claude-code/harness-security-scan/skill.yaml +1 -1
- package/dist/agents/skills/claude-code/harness-soundness-review/SKILL.md +1267 -0
- package/dist/agents/skills/claude-code/harness-soundness-review/skill.yaml +48 -0
- package/dist/agents/skills/claude-code/harness-test-advisor/SKILL.md +35 -6
- package/dist/agents/skills/claude-code/harness-verification/SKILL.md +66 -0
- package/dist/agents/skills/claude-code/harness-verification/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-verify/SKILL.md +37 -0
- package/dist/agents/skills/claude-code/initialize-harness-project/SKILL.md +15 -1
- package/dist/agents/skills/claude-code/validate-context-engineering/SKILL.md +12 -0
- package/dist/agents/skills/gemini-cli/harness-accessibility/SKILL.md +281 -0
- package/dist/agents/skills/gemini-cli/harness-accessibility/skill.yaml +51 -0
- package/dist/agents/skills/gemini-cli/harness-autopilot/SKILL.md +119 -72
- package/dist/agents/skills/gemini-cli/harness-autopilot/skill.yaml +4 -2
- package/dist/agents/skills/gemini-cli/harness-codebase-cleanup/SKILL.md +226 -0
- package/dist/agents/skills/gemini-cli/harness-codebase-cleanup/skill.yaml +64 -0
- package/dist/agents/skills/gemini-cli/harness-dependency-health/SKILL.md +35 -6
- package/dist/agents/skills/gemini-cli/harness-dependency-health/skill.yaml +1 -1
- package/dist/agents/skills/gemini-cli/harness-design/SKILL.md +265 -0
- package/dist/agents/skills/gemini-cli/harness-design/skill.yaml +53 -0
- package/dist/agents/skills/gemini-cli/harness-design-mobile/SKILL.md +336 -0
- package/dist/agents/skills/gemini-cli/harness-design-mobile/skill.yaml +49 -0
- package/dist/agents/skills/gemini-cli/harness-design-system/SKILL.md +282 -0
- package/dist/agents/skills/gemini-cli/harness-design-system/skill.yaml +50 -0
- package/dist/agents/skills/gemini-cli/harness-design-web/SKILL.md +360 -0
- package/dist/agents/skills/gemini-cli/harness-design-web/skill.yaml +52 -0
- package/dist/agents/skills/gemini-cli/harness-docs-pipeline/SKILL.md +460 -0
- package/dist/agents/skills/gemini-cli/harness-docs-pipeline/skill.yaml +69 -0
- package/dist/agents/skills/gemini-cli/harness-hotspot-detector/SKILL.md +32 -6
- package/dist/agents/skills/gemini-cli/harness-hotspot-detector/skill.yaml +1 -1
- package/dist/agents/skills/gemini-cli/harness-i18n/SKILL.md +484 -0
- package/dist/agents/skills/gemini-cli/harness-i18n/skill.yaml +54 -0
- package/dist/agents/skills/gemini-cli/harness-i18n-process/SKILL.md +388 -0
- package/dist/agents/skills/gemini-cli/harness-i18n-process/skill.yaml +43 -0
- package/dist/agents/skills/gemini-cli/harness-i18n-workflow/SKILL.md +512 -0
- package/dist/agents/skills/gemini-cli/harness-i18n-workflow/skill.yaml +53 -0
- package/dist/agents/skills/gemini-cli/harness-impact-analysis/SKILL.md +51 -6
- package/dist/agents/skills/gemini-cli/harness-knowledge-mapper/SKILL.md +46 -5
- package/dist/agents/skills/gemini-cli/harness-knowledge-mapper/skill.yaml +1 -1
- package/dist/agents/skills/gemini-cli/harness-perf/SKILL.md +37 -8
- package/dist/agents/skills/gemini-cli/harness-perf/skill.yaml +3 -0
- package/dist/agents/skills/gemini-cli/harness-perf-tdd/SKILL.md +17 -4
- package/dist/agents/skills/gemini-cli/harness-release-readiness/SKILL.md +29 -9
- package/dist/agents/skills/gemini-cli/harness-roadmap/SKILL.md +562 -0
- package/dist/agents/skills/gemini-cli/harness-roadmap/skill.yaml +43 -0
- package/dist/agents/skills/gemini-cli/harness-security-review/skill.yaml +8 -6
- package/dist/agents/skills/gemini-cli/harness-security-scan/skill.yaml +1 -1
- package/dist/agents/skills/gemini-cli/harness-soundness-review/SKILL.md +1267 -0
- package/dist/agents/skills/gemini-cli/harness-soundness-review/skill.yaml +48 -0
- package/dist/agents/skills/gemini-cli/harness-test-advisor/SKILL.md +35 -6
- package/dist/agents/skills/node_modules/.bin/vitest +2 -2
- package/dist/agents/skills/shared/design-knowledge/anti-patterns/color.yaml +106 -0
- package/dist/agents/skills/shared/design-knowledge/anti-patterns/layout.yaml +109 -0
- package/dist/agents/skills/shared/design-knowledge/anti-patterns/motion.yaml +109 -0
- package/dist/agents/skills/shared/design-knowledge/anti-patterns/typography.yaml +112 -0
- package/dist/agents/skills/shared/design-knowledge/industries/creative.yaml +80 -0
- package/dist/agents/skills/shared/design-knowledge/industries/ecommerce.yaml +80 -0
- package/dist/agents/skills/shared/design-knowledge/industries/emerging-tech.yaml +83 -0
- package/dist/agents/skills/shared/design-knowledge/industries/fintech.yaml +80 -0
- package/dist/agents/skills/shared/design-knowledge/industries/healthcare.yaml +80 -0
- package/dist/agents/skills/shared/design-knowledge/industries/lifestyle.yaml +80 -0
- package/dist/agents/skills/shared/design-knowledge/industries/saas.yaml +80 -0
- package/dist/agents/skills/shared/design-knowledge/industries/services.yaml +80 -0
- package/dist/agents/skills/shared/design-knowledge/palettes/curated.yaml +234 -0
- package/dist/agents/skills/shared/design-knowledge/platform-rules/android.yaml +125 -0
- package/dist/agents/skills/shared/design-knowledge/platform-rules/flutter.yaml +144 -0
- package/dist/agents/skills/shared/design-knowledge/platform-rules/ios.yaml +106 -0
- package/dist/agents/skills/shared/design-knowledge/platform-rules/web.yaml +102 -0
- package/dist/agents/skills/shared/design-knowledge/typography/pairings.yaml +274 -0
- package/dist/agents/skills/shared/i18n-knowledge/accessibility/intersection.yaml +142 -0
- package/dist/agents/skills/shared/i18n-knowledge/anti-patterns/encoding.yaml +67 -0
- package/dist/agents/skills/shared/i18n-knowledge/anti-patterns/formatting.yaml +106 -0
- package/dist/agents/skills/shared/i18n-knowledge/anti-patterns/layout.yaml +80 -0
- package/dist/agents/skills/shared/i18n-knowledge/anti-patterns/pluralization.yaml +80 -0
- package/dist/agents/skills/shared/i18n-knowledge/anti-patterns/string-handling.yaml +106 -0
- package/dist/agents/skills/shared/i18n-knowledge/frameworks/android-resources.yaml +47 -0
- package/dist/agents/skills/shared/i18n-knowledge/frameworks/apple-strings.yaml +47 -0
- package/dist/agents/skills/shared/i18n-knowledge/frameworks/backend-patterns.yaml +50 -0
- package/dist/agents/skills/shared/i18n-knowledge/frameworks/flutter-intl.yaml +47 -0
- package/dist/agents/skills/shared/i18n-knowledge/frameworks/i18next.yaml +47 -0
- package/dist/agents/skills/shared/i18n-knowledge/frameworks/react-intl.yaml +47 -0
- package/dist/agents/skills/shared/i18n-knowledge/frameworks/vue-i18n.yaml +47 -0
- package/dist/agents/skills/shared/i18n-knowledge/industries/ecommerce.yaml +66 -0
- package/dist/agents/skills/shared/i18n-knowledge/industries/fintech.yaml +66 -0
- package/dist/agents/skills/shared/i18n-knowledge/industries/gaming.yaml +69 -0
- package/dist/agents/skills/shared/i18n-knowledge/industries/healthcare.yaml +66 -0
- package/dist/agents/skills/shared/i18n-knowledge/industries/legal.yaml +66 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/ar.yaml +41 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/de.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/en.yaml +32 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/es.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/fi.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/fr.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/he.yaml +41 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/hi.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/it.yaml +32 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/ja.yaml +38 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/ko.yaml +38 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/nl.yaml +32 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/pl.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/pt.yaml +32 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/ru.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/sv.yaml +32 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/th.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/tr.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/zh-Hans.yaml +38 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/zh-Hant.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/mcp-interop/i18next-mcp.yaml +56 -0
- package/dist/agents/skills/shared/i18n-knowledge/mcp-interop/lingo-dev.yaml +56 -0
- package/dist/agents/skills/shared/i18n-knowledge/mcp-interop/lokalise.yaml +60 -0
- package/dist/agents/skills/shared/i18n-knowledge/mcp-interop/tolgee.yaml +60 -0
- package/dist/agents/skills/shared/i18n-knowledge/testing/locale-testing.yaml +107 -0
- package/dist/agents/skills/shared/i18n-knowledge/testing/pseudo-localization.yaml +86 -0
- package/dist/bin/harness.js +64 -4
- package/dist/{chunk-UDWGSL3T.js → chunk-3JWCBVUZ.js} +3 -3
- package/dist/{chunk-IUFFBBYV.js → chunk-LNI4T7R6.js} +179 -61
- package/dist/{chunk-USEYPS7F.js → chunk-SJECMKSS.js} +2250 -40
- package/dist/{dist-4MYPT3OE.js → dist-BDO5GFEM.js} +295 -14
- package/dist/{dist-RBZXXJHG.js → dist-NT3GXHQZ.js} +95 -1
- package/dist/index.d.ts +266 -7
- package/dist/index.js +7 -3
- package/dist/validate-cross-check-2OPGCGGU.js +7 -0
- package/package.json +7 -7
- package/dist/validate-cross-check-CPEPNLOD.js +0 -7
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
description: "Web platform design rules — CSS, Tailwind, React/Vue/Svelte component patterns and constraints"
|
|
2
|
+
|
|
3
|
+
platform: web
|
|
4
|
+
frameworks: ["React", "Vue", "Svelte", "vanilla"]
|
|
5
|
+
styling: ["Tailwind CSS", "CSS Modules", "CSS-in-JS", "vanilla CSS"]
|
|
6
|
+
|
|
7
|
+
token_binding:
|
|
8
|
+
description: "How design tokens map to web platform primitives"
|
|
9
|
+
methods:
|
|
10
|
+
- name: "CSS Custom Properties"
|
|
11
|
+
priority: 1
|
|
12
|
+
example: "var(--color-primary)"
|
|
13
|
+
usage: "Default binding — works in all CSS contexts"
|
|
14
|
+
- name: "Tailwind Theme Extension"
|
|
15
|
+
priority: 2
|
|
16
|
+
example: "text-primary, bg-surface"
|
|
17
|
+
usage: "When project uses Tailwind — extend tailwind.config with token values"
|
|
18
|
+
- name: "CSS-in-JS Theme Object"
|
|
19
|
+
priority: 3
|
|
20
|
+
example: "theme.colors.primary"
|
|
21
|
+
usage: "When project uses styled-components, Emotion, or similar"
|
|
22
|
+
|
|
23
|
+
component_patterns:
|
|
24
|
+
- name: "Composition over configuration"
|
|
25
|
+
rule: "Prefer composable child components over prop-heavy monolithic components"
|
|
26
|
+
example: |
|
|
27
|
+
// Prefer:
|
|
28
|
+
<Card><CardHeader /><CardBody /><CardFooter /></Card>
|
|
29
|
+
// Over:
|
|
30
|
+
<Card header="..." body="..." footer="..." />
|
|
31
|
+
reason: "Composable components are more flexible, easier to test, and align with framework idioms"
|
|
32
|
+
|
|
33
|
+
- name: "Token-bound styling"
|
|
34
|
+
rule: "All visual properties must reference design tokens, never hardcoded values"
|
|
35
|
+
detect: "Grep for hex colors, px font sizes, and raw spacing values in component files"
|
|
36
|
+
example: |
|
|
37
|
+
// Correct:
|
|
38
|
+
className="text-primary bg-surface p-4"
|
|
39
|
+
// Wrong:
|
|
40
|
+
style={{ color: '#2563eb', padding: '16px' }}
|
|
41
|
+
|
|
42
|
+
- name: "Responsive-first"
|
|
43
|
+
rule: "Components must work at all breakpoints defined in the design system"
|
|
44
|
+
approach: "Mobile-first: base styles for mobile, progressive enhancement for larger screens"
|
|
45
|
+
|
|
46
|
+
- name: "Accessible by default"
|
|
47
|
+
rule: "Interactive components must include ARIA attributes, keyboard handlers, and focus management"
|
|
48
|
+
requirements:
|
|
49
|
+
- "All buttons and links have accessible names"
|
|
50
|
+
- "Focus is visible and follows a logical order"
|
|
51
|
+
- "Dynamic content changes are announced to screen readers"
|
|
52
|
+
- "Color is never the sole indicator of state"
|
|
53
|
+
|
|
54
|
+
css_guidelines:
|
|
55
|
+
custom_properties:
|
|
56
|
+
rule: "Define all design tokens as CSS custom properties on :root"
|
|
57
|
+
example: |
|
|
58
|
+
:root {
|
|
59
|
+
--color-primary: #2563eb;
|
|
60
|
+
--color-surface: #f8fafc;
|
|
61
|
+
--font-display: 'Inter', system-ui, sans-serif;
|
|
62
|
+
--spacing-4: 1rem;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
tailwind:
|
|
66
|
+
rule: "Extend Tailwind config with token values rather than using arbitrary values"
|
|
67
|
+
example: |
|
|
68
|
+
// tailwind.config.js
|
|
69
|
+
theme: {
|
|
70
|
+
extend: {
|
|
71
|
+
colors: {
|
|
72
|
+
primary: 'var(--color-primary)',
|
|
73
|
+
surface: 'var(--color-surface)',
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
avoid: "Arbitrary value syntax like bg-[#2563eb] when a token exists"
|
|
78
|
+
|
|
79
|
+
dark_mode:
|
|
80
|
+
rule: "Support dark mode via CSS custom property overrides, not duplicate stylesheets"
|
|
81
|
+
approach: "Redefine token values inside a [data-theme='dark'] or @media (prefers-color-scheme: dark) block"
|
|
82
|
+
|
|
83
|
+
performance:
|
|
84
|
+
- rule: "Limit CSS bundle to 50KB gzipped"
|
|
85
|
+
reason: "CSS blocks rendering — large stylesheets delay first paint"
|
|
86
|
+
- rule: "Use content-visibility: auto for below-fold sections"
|
|
87
|
+
reason: "Reduces initial layout cost for long pages"
|
|
88
|
+
- rule: "Lazy-load web fonts with font-display: swap"
|
|
89
|
+
reason: "Prevents invisible text (FOIT) during font download"
|
|
90
|
+
- rule: "Prefer CSS transitions over JavaScript animations"
|
|
91
|
+
reason: "CSS animations run on the compositor thread, avoiding main thread jank"
|
|
92
|
+
|
|
93
|
+
testing:
|
|
94
|
+
- type: "Visual regression"
|
|
95
|
+
tools: ["Chromatic", "Percy", "Playwright screenshots"]
|
|
96
|
+
rule: "All component variants must have visual regression coverage"
|
|
97
|
+
- type: "Accessibility"
|
|
98
|
+
tools: ["axe-core", "Lighthouse", "pa11y"]
|
|
99
|
+
rule: "Run axe-core in CI on all component stories"
|
|
100
|
+
- type: "Responsive"
|
|
101
|
+
tools: ["Playwright", "Cypress"]
|
|
102
|
+
rule: "Test at 320px, 768px, 1024px, and 1440px viewports minimum"
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
description: "Curated font pairings with complete fallback stacks and usage guidance"
|
|
2
|
+
|
|
3
|
+
pairings:
|
|
4
|
+
- name: "Modern Editorial"
|
|
5
|
+
tags: ["editorial", "creative", "premium"]
|
|
6
|
+
display:
|
|
7
|
+
family: "Instrument Serif"
|
|
8
|
+
fallback: "Georgia, 'Times New Roman', serif"
|
|
9
|
+
weights: [400, 700]
|
|
10
|
+
variable: false
|
|
11
|
+
source: "Google Fonts"
|
|
12
|
+
body:
|
|
13
|
+
family: "Geist"
|
|
14
|
+
fallback: "system-ui, -apple-system, sans-serif"
|
|
15
|
+
weights: [400, 500, 600]
|
|
16
|
+
variable: true
|
|
17
|
+
source: "Vercel"
|
|
18
|
+
mono:
|
|
19
|
+
family: "Geist Mono"
|
|
20
|
+
fallback: "'SF Mono', 'Fira Code', 'Cascadia Code', monospace"
|
|
21
|
+
weights: [400, 500]
|
|
22
|
+
source: "Vercel"
|
|
23
|
+
scale:
|
|
24
|
+
base: "1rem"
|
|
25
|
+
ratio: 1.25
|
|
26
|
+
sizes:
|
|
27
|
+
xs: "0.75rem"
|
|
28
|
+
sm: "0.875rem"
|
|
29
|
+
base: "1rem"
|
|
30
|
+
lg: "1.125rem"
|
|
31
|
+
xl: "1.25rem"
|
|
32
|
+
"2xl": "1.5rem"
|
|
33
|
+
"3xl": "1.875rem"
|
|
34
|
+
"4xl": "2.25rem"
|
|
35
|
+
"5xl": "3rem"
|
|
36
|
+
usage: "Best for editorial, blog, and content-heavy sites that want to feel premium and literary."
|
|
37
|
+
|
|
38
|
+
- name: "Clean Tech"
|
|
39
|
+
tags: ["tech", "saas", "dashboard", "modern"]
|
|
40
|
+
display:
|
|
41
|
+
family: "Inter"
|
|
42
|
+
fallback: "system-ui, -apple-system, 'Segoe UI', sans-serif"
|
|
43
|
+
weights: [500, 600, 700]
|
|
44
|
+
variable: true
|
|
45
|
+
source: "Google Fonts"
|
|
46
|
+
body:
|
|
47
|
+
family: "Inter"
|
|
48
|
+
fallback: "system-ui, -apple-system, 'Segoe UI', sans-serif"
|
|
49
|
+
weights: [400, 500, 600]
|
|
50
|
+
variable: true
|
|
51
|
+
source: "Google Fonts"
|
|
52
|
+
mono:
|
|
53
|
+
family: "JetBrains Mono"
|
|
54
|
+
fallback: "'SF Mono', 'Fira Code', 'Cascadia Code', monospace"
|
|
55
|
+
weights: [400, 500]
|
|
56
|
+
source: "Google Fonts"
|
|
57
|
+
scale:
|
|
58
|
+
base: "1rem"
|
|
59
|
+
ratio: 1.2
|
|
60
|
+
sizes:
|
|
61
|
+
xs: "0.75rem"
|
|
62
|
+
sm: "0.875rem"
|
|
63
|
+
base: "1rem"
|
|
64
|
+
lg: "1.125rem"
|
|
65
|
+
xl: "1.25rem"
|
|
66
|
+
"2xl": "1.5rem"
|
|
67
|
+
"3xl": "1.8rem"
|
|
68
|
+
"4xl": "2.16rem"
|
|
69
|
+
"5xl": "2.592rem"
|
|
70
|
+
usage: "Ideal for SaaS dashboards, developer tools, and data-heavy interfaces where clarity and density matter."
|
|
71
|
+
|
|
72
|
+
- name: "Traditional Pro"
|
|
73
|
+
tags: ["professional", "corporate", "legal", "finance"]
|
|
74
|
+
display:
|
|
75
|
+
family: "Playfair Display"
|
|
76
|
+
fallback: "Georgia, 'Times New Roman', 'Palatino Linotype', serif"
|
|
77
|
+
weights: [400, 700, 900]
|
|
78
|
+
variable: true
|
|
79
|
+
source: "Google Fonts"
|
|
80
|
+
body:
|
|
81
|
+
family: "Source Sans 3"
|
|
82
|
+
fallback: "'Segoe UI', 'Helvetica Neue', Arial, sans-serif"
|
|
83
|
+
weights: [400, 600, 700]
|
|
84
|
+
variable: true
|
|
85
|
+
source: "Google Fonts"
|
|
86
|
+
mono:
|
|
87
|
+
family: "Source Code Pro"
|
|
88
|
+
fallback: "'SF Mono', 'Courier New', monospace"
|
|
89
|
+
weights: [400, 500]
|
|
90
|
+
source: "Google Fonts"
|
|
91
|
+
scale:
|
|
92
|
+
base: "1rem"
|
|
93
|
+
ratio: 1.333
|
|
94
|
+
sizes:
|
|
95
|
+
xs: "0.75rem"
|
|
96
|
+
sm: "0.875rem"
|
|
97
|
+
base: "1rem"
|
|
98
|
+
lg: "1.125rem"
|
|
99
|
+
xl: "1.333rem"
|
|
100
|
+
"2xl": "1.777rem"
|
|
101
|
+
"3xl": "2.369rem"
|
|
102
|
+
"4xl": "3.157rem"
|
|
103
|
+
"5xl": "4.209rem"
|
|
104
|
+
usage: "Best for corporate sites, law firms, financial services, and publications that need gravitas and authority."
|
|
105
|
+
|
|
106
|
+
- name: "Friendly Rounded"
|
|
107
|
+
tags: ["friendly", "approachable", "lifestyle", "consumer"]
|
|
108
|
+
display:
|
|
109
|
+
family: "Nunito"
|
|
110
|
+
fallback: "'Varela Round', 'Helvetica Neue', Arial, sans-serif"
|
|
111
|
+
weights: [600, 700, 800]
|
|
112
|
+
variable: true
|
|
113
|
+
source: "Google Fonts"
|
|
114
|
+
body:
|
|
115
|
+
family: "DM Sans"
|
|
116
|
+
fallback: "'Helvetica Neue', Arial, sans-serif"
|
|
117
|
+
weights: [400, 500, 700]
|
|
118
|
+
variable: true
|
|
119
|
+
source: "Google Fonts"
|
|
120
|
+
mono:
|
|
121
|
+
family: "DM Mono"
|
|
122
|
+
fallback: "'SF Mono', 'Fira Code', monospace"
|
|
123
|
+
weights: [400, 500]
|
|
124
|
+
source: "Google Fonts"
|
|
125
|
+
scale:
|
|
126
|
+
base: "1rem"
|
|
127
|
+
ratio: 1.25
|
|
128
|
+
sizes:
|
|
129
|
+
xs: "0.75rem"
|
|
130
|
+
sm: "0.875rem"
|
|
131
|
+
base: "1rem"
|
|
132
|
+
lg: "1.125rem"
|
|
133
|
+
xl: "1.25rem"
|
|
134
|
+
"2xl": "1.5rem"
|
|
135
|
+
"3xl": "1.875rem"
|
|
136
|
+
"4xl": "2.25rem"
|
|
137
|
+
"5xl": "3rem"
|
|
138
|
+
usage: "Perfect for consumer apps, lifestyle brands, and friendly SaaS products that want to feel warm and approachable."
|
|
139
|
+
|
|
140
|
+
- name: "Geometric Minimal"
|
|
141
|
+
tags: ["minimal", "geometric", "startup", "clean"]
|
|
142
|
+
display:
|
|
143
|
+
family: "Space Grotesk"
|
|
144
|
+
fallback: "'Helvetica Neue', Arial, sans-serif"
|
|
145
|
+
weights: [500, 700]
|
|
146
|
+
variable: true
|
|
147
|
+
source: "Google Fonts"
|
|
148
|
+
body:
|
|
149
|
+
family: "Work Sans"
|
|
150
|
+
fallback: "'Helvetica Neue', Arial, sans-serif"
|
|
151
|
+
weights: [400, 500, 600]
|
|
152
|
+
variable: true
|
|
153
|
+
source: "Google Fonts"
|
|
154
|
+
mono:
|
|
155
|
+
family: "Space Mono"
|
|
156
|
+
fallback: "'SF Mono', 'Courier New', monospace"
|
|
157
|
+
weights: [400, 700]
|
|
158
|
+
source: "Google Fonts"
|
|
159
|
+
scale:
|
|
160
|
+
base: "1rem"
|
|
161
|
+
ratio: 1.2
|
|
162
|
+
sizes:
|
|
163
|
+
xs: "0.75rem"
|
|
164
|
+
sm: "0.875rem"
|
|
165
|
+
base: "1rem"
|
|
166
|
+
lg: "1.125rem"
|
|
167
|
+
xl: "1.25rem"
|
|
168
|
+
"2xl": "1.5rem"
|
|
169
|
+
"3xl": "1.8rem"
|
|
170
|
+
"4xl": "2.16rem"
|
|
171
|
+
"5xl": "2.592rem"
|
|
172
|
+
usage: "Great for startups, portfolios, and minimal landing pages that favor geometric precision over ornamentation."
|
|
173
|
+
|
|
174
|
+
- name: "Monospace Forward"
|
|
175
|
+
tags: ["developer", "technical", "code", "hacker"]
|
|
176
|
+
display:
|
|
177
|
+
family: "JetBrains Mono"
|
|
178
|
+
fallback: "'SF Mono', 'Fira Code', 'Cascadia Code', monospace"
|
|
179
|
+
weights: [500, 700, 800]
|
|
180
|
+
variable: true
|
|
181
|
+
source: "Google Fonts"
|
|
182
|
+
body:
|
|
183
|
+
family: "IBM Plex Sans"
|
|
184
|
+
fallback: "'Helvetica Neue', Arial, sans-serif"
|
|
185
|
+
weights: [400, 500, 600]
|
|
186
|
+
variable: false
|
|
187
|
+
source: "Google Fonts"
|
|
188
|
+
mono:
|
|
189
|
+
family: "JetBrains Mono"
|
|
190
|
+
fallback: "'SF Mono', 'Fira Code', 'Cascadia Code', monospace"
|
|
191
|
+
weights: [400, 500]
|
|
192
|
+
source: "Google Fonts"
|
|
193
|
+
scale:
|
|
194
|
+
base: "1rem"
|
|
195
|
+
ratio: 1.2
|
|
196
|
+
sizes:
|
|
197
|
+
xs: "0.75rem"
|
|
198
|
+
sm: "0.875rem"
|
|
199
|
+
base: "1rem"
|
|
200
|
+
lg: "1.125rem"
|
|
201
|
+
xl: "1.25rem"
|
|
202
|
+
"2xl": "1.5rem"
|
|
203
|
+
"3xl": "1.8rem"
|
|
204
|
+
"4xl": "2.16rem"
|
|
205
|
+
"5xl": "2.592rem"
|
|
206
|
+
usage: "Tailored for developer tools, documentation sites, and technical blogs where code is a first-class citizen."
|
|
207
|
+
|
|
208
|
+
- name: "High Contrast A11y"
|
|
209
|
+
tags: ["accessible", "healthcare", "government", "high-contrast"]
|
|
210
|
+
display:
|
|
211
|
+
family: "Atkinson Hyperlegible"
|
|
212
|
+
fallback: "Arial, 'Helvetica Neue', sans-serif"
|
|
213
|
+
weights: [400, 700]
|
|
214
|
+
variable: false
|
|
215
|
+
source: "Google Fonts"
|
|
216
|
+
body:
|
|
217
|
+
family: "Atkinson Hyperlegible"
|
|
218
|
+
fallback: "Arial, 'Helvetica Neue', sans-serif"
|
|
219
|
+
weights: [400, 700]
|
|
220
|
+
variable: false
|
|
221
|
+
source: "Google Fonts"
|
|
222
|
+
mono:
|
|
223
|
+
family: "Red Hat Mono"
|
|
224
|
+
fallback: "'SF Mono', 'Courier New', monospace"
|
|
225
|
+
weights: [400, 700]
|
|
226
|
+
source: "Google Fonts"
|
|
227
|
+
scale:
|
|
228
|
+
base: "1.125rem"
|
|
229
|
+
ratio: 1.25
|
|
230
|
+
sizes:
|
|
231
|
+
xs: "0.875rem"
|
|
232
|
+
sm: "1rem"
|
|
233
|
+
base: "1.125rem"
|
|
234
|
+
lg: "1.25rem"
|
|
235
|
+
xl: "1.5rem"
|
|
236
|
+
"2xl": "1.875rem"
|
|
237
|
+
"3xl": "2.25rem"
|
|
238
|
+
"4xl": "3rem"
|
|
239
|
+
"5xl": "3.75rem"
|
|
240
|
+
usage: "Designed for maximum legibility. Ideal for healthcare, government, education, and any context where accessibility is paramount."
|
|
241
|
+
|
|
242
|
+
- name: "System Native"
|
|
243
|
+
tags: ["system", "performance", "native", "zero-download"]
|
|
244
|
+
display:
|
|
245
|
+
family: "system-ui"
|
|
246
|
+
fallback: "-apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
|
|
247
|
+
weights: [500, 600, 700]
|
|
248
|
+
variable: false
|
|
249
|
+
source: "System"
|
|
250
|
+
body:
|
|
251
|
+
family: "system-ui"
|
|
252
|
+
fallback: "-apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
|
|
253
|
+
weights: [400, 500, 600]
|
|
254
|
+
variable: false
|
|
255
|
+
source: "System"
|
|
256
|
+
mono:
|
|
257
|
+
family: "ui-monospace"
|
|
258
|
+
fallback: "'SF Mono', 'Cascadia Code', 'Fira Code', 'JetBrains Mono', 'Courier New', monospace"
|
|
259
|
+
weights: [400, 500]
|
|
260
|
+
source: "System"
|
|
261
|
+
scale:
|
|
262
|
+
base: "1rem"
|
|
263
|
+
ratio: 1.25
|
|
264
|
+
sizes:
|
|
265
|
+
xs: "0.75rem"
|
|
266
|
+
sm: "0.875rem"
|
|
267
|
+
base: "1rem"
|
|
268
|
+
lg: "1.125rem"
|
|
269
|
+
xl: "1.25rem"
|
|
270
|
+
"2xl": "1.5rem"
|
|
271
|
+
"3xl": "1.875rem"
|
|
272
|
+
"4xl": "2.25rem"
|
|
273
|
+
"5xl": "3rem"
|
|
274
|
+
usage: "Zero font downloads, instant rendering. Best for performance-critical apps, internal tools, and native-feeling web applications."
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
description: "Rules at the intersection of i18n and accessibility — ensuring localized content remains accessible across languages, scripts, and text directions"
|
|
2
|
+
|
|
3
|
+
rules:
|
|
4
|
+
- name: "lang attribute on html element"
|
|
5
|
+
category: "lang-tags"
|
|
6
|
+
wcag_criteria: ["3.1.1"]
|
|
7
|
+
description: "The <html> element must have a valid lang attribute matching the page's primary language"
|
|
8
|
+
detect:
|
|
9
|
+
method: "Check for lang attribute on <html> element; verify it matches a valid BCP 47 tag and corresponds to the page content language"
|
|
10
|
+
reason: "Screen readers use the lang attribute to select the correct pronunciation engine. Without it, an English screen reader will mispronounce French content."
|
|
11
|
+
fix: "Set <html lang='fr'> for French content, <html lang='ar' dir='rtl'> for Arabic, etc. Update dynamically when locale changes."
|
|
12
|
+
severity: error
|
|
13
|
+
strictness:
|
|
14
|
+
permissive: warn
|
|
15
|
+
standard: error
|
|
16
|
+
strict: error
|
|
17
|
+
|
|
18
|
+
- name: "lang attribute on inline language switches"
|
|
19
|
+
category: "lang-tags"
|
|
20
|
+
wcag_criteria: ["3.1.2"]
|
|
21
|
+
description: "Inline content in a different language must be wrapped with a lang attribute"
|
|
22
|
+
detect:
|
|
23
|
+
method: "Check for foreign-language words or phrases without a lang attribute on their container"
|
|
24
|
+
reason: "Screen readers will pronounce foreign words using the page's primary language rules, making them unintelligible."
|
|
25
|
+
fix: "Wrap language switches: <span lang='fr'>bonjour</span> within English content, <span lang='en'>API</span> within Japanese content."
|
|
26
|
+
severity: warning
|
|
27
|
+
strictness:
|
|
28
|
+
permissive: info
|
|
29
|
+
standard: warn
|
|
30
|
+
strict: error
|
|
31
|
+
|
|
32
|
+
- name: "dir attribute for RTL content"
|
|
33
|
+
category: "bidi-a11y"
|
|
34
|
+
wcag_criteria: ["1.3.2"]
|
|
35
|
+
description: "RTL content must have dir='rtl' set on the appropriate container element"
|
|
36
|
+
detect:
|
|
37
|
+
method: "Check for Arabic, Hebrew, or other RTL script content without a dir attribute on its container"
|
|
38
|
+
reason: "Without dir='rtl', screen readers may read RTL text in the wrong order, and visual rendering will be incorrect."
|
|
39
|
+
fix: "Set dir='rtl' on containers with RTL content. For the full page: <html lang='ar' dir='rtl'>. For inline: <span dir='rtl'>."
|
|
40
|
+
severity: error
|
|
41
|
+
strictness:
|
|
42
|
+
permissive: warn
|
|
43
|
+
standard: error
|
|
44
|
+
strict: error
|
|
45
|
+
|
|
46
|
+
- name: "dir=auto on user-generated content"
|
|
47
|
+
category: "bidi-a11y"
|
|
48
|
+
wcag_criteria: ["1.3.2"]
|
|
49
|
+
description: "User-generated content containers should use dir='auto' to detect text direction automatically"
|
|
50
|
+
detect:
|
|
51
|
+
method: "Check for user-generated content areas (comments, messages, reviews) without dir='auto'"
|
|
52
|
+
reason: "User content may be in any language. Without dir='auto', an Arabic comment in an English page will render incorrectly."
|
|
53
|
+
fix: "Set dir='auto' on elements that display user-generated content: <p dir='auto'>{userComment}</p>"
|
|
54
|
+
severity: warning
|
|
55
|
+
strictness:
|
|
56
|
+
permissive: info
|
|
57
|
+
standard: warn
|
|
58
|
+
strict: warn
|
|
59
|
+
|
|
60
|
+
- name: "Font size scaling for complex scripts"
|
|
61
|
+
category: "script-sizing"
|
|
62
|
+
wcag_criteria: ["1.4.4"]
|
|
63
|
+
description: "Complex scripts (Devanagari, Thai, Arabic, CJK) require larger minimum font sizes for legibility"
|
|
64
|
+
detect:
|
|
65
|
+
method: "Check minimum font sizes when content language uses complex scripts; flag sizes below recommended minimums"
|
|
66
|
+
reason: "Complex scripts have more visual detail per character. Arabic letters reshape by position. Thai stacks diacritics vertically. Below 12-14px, these become illegible."
|
|
67
|
+
fix: "Set minimum font sizes: 12px for CJK, 13px for Arabic, 14px for Devanagari and Thai. Increase line-height to 1.6-1.8 for scripts with stacking marks."
|
|
68
|
+
severity: warning
|
|
69
|
+
strictness:
|
|
70
|
+
permissive: info
|
|
71
|
+
standard: warn
|
|
72
|
+
strict: error
|
|
73
|
+
|
|
74
|
+
- name: "Screen reader pronunciation of numbers and dates"
|
|
75
|
+
category: "screen-readers"
|
|
76
|
+
wcag_criteria: ["1.3.1"]
|
|
77
|
+
description: "Numbers and dates must use semantic markup so screen readers pronounce them correctly per locale"
|
|
78
|
+
detect:
|
|
79
|
+
method: "Check for visually formatted numbers/dates that lack semantic markup (time element, appropriate ARIA)"
|
|
80
|
+
reason: "A screen reader seeing '03/04/2025' cannot determine if it is March 4 or April 3 without semantic context. '1.234' could be one-point-two-three-four or one-thousand-two-hundred-thirty-four."
|
|
81
|
+
fix: "Use <time datetime='2025-03-04'>March 4, 2025</time> for dates. Use aria-label for ambiguous number formats."
|
|
82
|
+
severity: warning
|
|
83
|
+
strictness:
|
|
84
|
+
permissive: info
|
|
85
|
+
standard: warn
|
|
86
|
+
strict: warn
|
|
87
|
+
|
|
88
|
+
- name: "ARIA labels must be translated"
|
|
89
|
+
category: "screen-readers"
|
|
90
|
+
wcag_criteria: ["4.1.2"]
|
|
91
|
+
description: "All ARIA labels, descriptions, and live region content must go through the translation pipeline"
|
|
92
|
+
detect:
|
|
93
|
+
method: "Check for hardcoded English strings in aria-label, aria-description, aria-roledescription attributes"
|
|
94
|
+
reason: "Untranslated ARIA labels make the interface inaccessible to screen reader users in non-English locales."
|
|
95
|
+
fix: "Wrap ARIA attributes in translation functions: aria-label={t('nav.menu')} instead of aria-label='Menu'"
|
|
96
|
+
severity: error
|
|
97
|
+
strictness:
|
|
98
|
+
permissive: warn
|
|
99
|
+
standard: error
|
|
100
|
+
strict: error
|
|
101
|
+
|
|
102
|
+
- name: "hreflang attribute on alternate-language links"
|
|
103
|
+
category: "lang-tags"
|
|
104
|
+
wcag_criteria: ["3.1.1"]
|
|
105
|
+
description: "Links to alternate-language versions of a page must have hreflang attributes"
|
|
106
|
+
detect:
|
|
107
|
+
method: "Check for <link rel='alternate'> elements without hreflang, or language switcher links without hreflang"
|
|
108
|
+
reason: "hreflang helps search engines serve the correct language version and assists screen readers in announcing the target language."
|
|
109
|
+
fix: "Add hreflang to all alternate links: <link rel='alternate' hreflang='es' href='/es/page'>. Include x-default for the default version."
|
|
110
|
+
severity: warning
|
|
111
|
+
strictness:
|
|
112
|
+
permissive: info
|
|
113
|
+
standard: warn
|
|
114
|
+
strict: warn
|
|
115
|
+
|
|
116
|
+
- name: "Translated alt text for images"
|
|
117
|
+
category: "screen-readers"
|
|
118
|
+
wcag_criteria: ["1.1.1"]
|
|
119
|
+
description: "Image alt text must be translated along with all other user-facing content"
|
|
120
|
+
detect:
|
|
121
|
+
method: "Check for img alt attributes containing English text when the page language is non-English"
|
|
122
|
+
reason: "Untranslated alt text is meaningless to screen reader users who do not speak the source language."
|
|
123
|
+
fix: "Include all alt attributes in the translation pipeline: <img alt={t('hero.alt')} /> instead of hardcoded text"
|
|
124
|
+
severity: error
|
|
125
|
+
strictness:
|
|
126
|
+
permissive: warn
|
|
127
|
+
standard: error
|
|
128
|
+
strict: error
|
|
129
|
+
|
|
130
|
+
- name: "Keyboard navigation in RTL layouts"
|
|
131
|
+
category: "bidi-a11y"
|
|
132
|
+
wcag_criteria: ["2.4.3"]
|
|
133
|
+
description: "Tab order must follow visual order in RTL layouts — right-to-left, top-to-bottom"
|
|
134
|
+
detect:
|
|
135
|
+
method: "Check tab order in RTL layouts; verify it matches the visual reading order (right to left)"
|
|
136
|
+
reason: "If tab order remains LTR in an RTL layout, keyboard users navigate against the visual flow, causing confusion."
|
|
137
|
+
fix: "Use CSS logical properties for layout; avoid manual tabindex that assumes LTR order; test tab navigation with RTL locale"
|
|
138
|
+
severity: error
|
|
139
|
+
strictness:
|
|
140
|
+
permissive: info
|
|
141
|
+
standard: warn
|
|
142
|
+
strict: error
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
description: "Encoding anti-patterns — common mistakes in character encoding, Unicode handling, and text measurement that break with non-ASCII content"
|
|
2
|
+
|
|
3
|
+
patterns:
|
|
4
|
+
- name: "Assuming 1 character equals 1 byte"
|
|
5
|
+
severity: error
|
|
6
|
+
scope: all
|
|
7
|
+
detect:
|
|
8
|
+
method: "Check for buffer allocation or data storage sized by string.length for strings that may contain non-ASCII"
|
|
9
|
+
context: "Buffer.alloc(str.length) or database VARCHAR columns sized by character count for UTF-8 data"
|
|
10
|
+
reason: "UTF-8 encodes characters in 1-4 bytes. 'hello' is 5 bytes but 'こんにちは' is 15 bytes. Buffer overflow or truncation results."
|
|
11
|
+
instead: "Use Buffer.byteLength(str, 'utf8') for byte calculations; size database columns for byte length not character count"
|
|
12
|
+
strictness:
|
|
13
|
+
permissive: info
|
|
14
|
+
standard: warn
|
|
15
|
+
strict: error
|
|
16
|
+
|
|
17
|
+
- name: "String length not equal to visual width"
|
|
18
|
+
severity: warning
|
|
19
|
+
scope: all
|
|
20
|
+
detect:
|
|
21
|
+
method: "Check for string.length used to estimate visual display width"
|
|
22
|
+
context: "Layout calculations or column alignment using .length instead of visual width measurement"
|
|
23
|
+
reason: "CJK characters are double-width visually but .length counts them as 1. Emoji may be multiple code points but one visual glyph."
|
|
24
|
+
instead: "Use Intl.Segmenter for grapheme counting; use canvas.measureText() or terminal wcwidth for visual width"
|
|
25
|
+
strictness:
|
|
26
|
+
permissive: info
|
|
27
|
+
standard: warn
|
|
28
|
+
strict: warn
|
|
29
|
+
|
|
30
|
+
- name: "Missing UTF-8 BOM handling"
|
|
31
|
+
severity: warning
|
|
32
|
+
scope: all
|
|
33
|
+
detect:
|
|
34
|
+
method: "Check for file reading that does not strip BOM (U+FEFF) from the beginning of text files"
|
|
35
|
+
context: "Reading CSV, JSON, or translation files that may have been edited in Windows tools that add BOM"
|
|
36
|
+
reason: "BOM at the start of a file can break JSON parsing, CSV parsing, and string comparison. Windows Notepad adds BOM by default."
|
|
37
|
+
instead: "Strip BOM when reading files: content.replace(/^\\uFEFF/, '') or use a BOM-aware file reader"
|
|
38
|
+
strictness:
|
|
39
|
+
permissive: info
|
|
40
|
+
standard: warn
|
|
41
|
+
strict: warn
|
|
42
|
+
|
|
43
|
+
- name: "Emoji and ZWJ sequence handling"
|
|
44
|
+
severity: warning
|
|
45
|
+
scope: all
|
|
46
|
+
detect:
|
|
47
|
+
method: "Check for string operations that split or truncate without grapheme cluster awareness"
|
|
48
|
+
context: "Array.from(str) or str.split('') used to process strings containing emoji"
|
|
49
|
+
reason: "Family emoji (👨👩👦) is 5 code points joined by ZWJ. Splitting by code point produces broken fragments."
|
|
50
|
+
instead: "Use Intl.Segmenter(locale, { granularity: 'grapheme' }) to iterate over visual characters safely"
|
|
51
|
+
strictness:
|
|
52
|
+
permissive: info
|
|
53
|
+
standard: warn
|
|
54
|
+
strict: warn
|
|
55
|
+
|
|
56
|
+
- name: "Filename and URL encoding not handling non-ASCII"
|
|
57
|
+
severity: error
|
|
58
|
+
scope: all
|
|
59
|
+
detect:
|
|
60
|
+
method: "Check for file path or URL construction that does not encode non-ASCII characters"
|
|
61
|
+
context: "Path concatenation with user input or locale-specific filenames without encodeURIComponent"
|
|
62
|
+
reason: "Non-ASCII filenames and URL segments must be percent-encoded. Unencoded characters cause 404 errors and security issues."
|
|
63
|
+
instead: "Use encodeURIComponent() for URL segments; use encodeURI() for full URLs; normalize filenames to ASCII-safe slugs"
|
|
64
|
+
strictness:
|
|
65
|
+
permissive: warn
|
|
66
|
+
standard: error
|
|
67
|
+
strict: error
|