Add lint, typecheck, and html-validate guardrails
Tooling:
- ESLint 9 flat config (eslint.config.mjs) with three scopes:
- browser vanilla JS for js/ (no modules, window globals)
- Node ESM for scripts/
- typescript-eslint for tests/ and *.ts
- Stylelint with a deliberately minimal "bug-only" ruleset
(block-no-empty, color-no-invalid-hex, function-no-unknown,
property-no-unknown, …) — no nags about compact handwritten CSS
- html-validate against index.html (DOCTYPE, accessible names,
non-redundant ARIA roles, valid landmark usage)
- TypeScript --noEmit strict on playwright.config.ts + tests/*.ts
npm scripts:
- lint — parallel run of lint:js, lint:css, lint:html (~3s)
- lint:js{,:fix}, lint:css{,:fix}, lint:html
- typecheck — tsc --noEmit
- check — lint + typecheck + test in parallel (CI entry point)
Fixes uncovered by the new checks:
- js/app.js: drop unused `activeTimers`, drop unused `t` lookup in
refreshTreeRow, switch `activeTags` let→const, replace empty
`catch(_)` blocks with parameter-less catch + intent comment
- js/data.js: drop unused index arg in renderExperience
- index.html: uppercase DOCTYPE, drop redundant role="banner" /
role="contentinfo" on <header>/<footer>, add aria-labels on icon-only
Stop / Reset buttons, add role="group" to the tag bar so its
aria-label is valid, add explicit type="button" everywhere
- tests/portfolio.spec.ts: landmark test now uses getByRole() rather
than the explicit [role="banner"] attribute selector
Housekeeping:
- .gitignore picks up .eslintcache / .stylelintcache / *.tsbuildinfo
- README documents the lint + check toolchain
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
// Flat config — ESLint 9. Three lint targets:
|
||||
// 1. Browser vanilla JS in `js/` (no build, no modules)
|
||||
// 2. Node ES modules in `scripts/` (utility tasks)
|
||||
// 3. TypeScript test + config files (@playwright/test)
|
||||
import js from "@eslint/js";
|
||||
import globals from "globals";
|
||||
import tseslint from "typescript-eslint";
|
||||
|
||||
export default [
|
||||
{
|
||||
ignores: [
|
||||
"node_modules/",
|
||||
"playwright-report/",
|
||||
"test-results/",
|
||||
"assets/",
|
||||
"dist/",
|
||||
".cache/",
|
||||
],
|
||||
},
|
||||
|
||||
// ----- Browser vanilla JS (js/app.js, js/data.js) -----
|
||||
{
|
||||
files: ["js/**/*.js"],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2022,
|
||||
sourceType: "script",
|
||||
globals: {
|
||||
...globals.browser,
|
||||
// `data.js` exposes window.PORTFOLIO and a set of `renderXxx`
|
||||
// top-level functions referenced from inline `render:` properties.
|
||||
// They are looked up by reference inside data.js, not by name from
|
||||
// other files, so we don't need to pre-declare each renderer.
|
||||
PORTFOLIO: "readonly",
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
...js.configs.recommended.rules,
|
||||
eqeqeq: ["error", "always"],
|
||||
"no-var": "error",
|
||||
"prefer-const": "warn",
|
||||
"no-console": ["warn", { allow: ["warn", "error"] }],
|
||||
// _ / _esc are intentional helper / placeholder names.
|
||||
"no-unused-vars": [
|
||||
"warn",
|
||||
{
|
||||
argsIgnorePattern: "^_",
|
||||
varsIgnorePattern: "^_",
|
||||
caughtErrorsIgnorePattern: "^_",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
// ----- Node ES modules (scripts/*.mjs) -----
|
||||
{
|
||||
files: ["scripts/**/*.{js,mjs}"],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2022,
|
||||
sourceType: "module",
|
||||
globals: { ...globals.node },
|
||||
},
|
||||
rules: {
|
||||
...js.configs.recommended.rules,
|
||||
eqeqeq: ["error", "always"],
|
||||
"no-var": "error",
|
||||
"prefer-const": "warn",
|
||||
"no-console": "off",
|
||||
},
|
||||
},
|
||||
|
||||
// ----- TypeScript (tests/, playwright.config.ts) -----
|
||||
...tseslint.configs.recommended.map((cfg) => ({
|
||||
...cfg,
|
||||
files: ["tests/**/*.ts", "*.ts"],
|
||||
})),
|
||||
{
|
||||
files: ["tests/**/*.ts", "*.ts"],
|
||||
languageOptions: {
|
||||
globals: { ...globals.node },
|
||||
},
|
||||
rules: {
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"warn",
|
||||
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
|
||||
],
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
},
|
||||
},
|
||||
];
|
||||
Reference in New Issue
Block a user