{"_id":"@gaia-react/lint","_rev":"3-3b590e33368e709f80a05486155a95a1","name":"@gaia-react/lint","dist-tags":{"latest":"1.1.1"},"versions":{"1.0.0":{"name":"@gaia-react/lint","version":"1.0.0","keywords":["gaia","gaia-react","eslint","eslint-config","flat-config","react","typescript","lint"],"author":{"name":"Steven Sacks","email":"stevensacks@gmail.com"},"license":"MIT","_id":"@gaia-react/lint@1.0.0","maintainers":[{"name":"stevensacks","email":"stevensacks@gmail.com"}],"homepage":"https://github.com/gaia-react/lint#readme","bugs":{"url":"https://github.com/gaia-react/lint/issues"},"dist":{"shasum":"2d7d6df48488c6f0f412d59ec408da4e25fbf569","tarball":"https://registry.npmjs.org/@gaia-react/lint/-/lint-1.0.0.tgz","fileCount":31,"integrity":"sha512-R//2FxfFjAXcx6WStrM2aszOPMOT0JBbiknWzjVgQ6/OGF0QhRISJv3V/7SkhEe8x2uhx/nk+7EzxE8d5lEB6w==","signatures":[{"sig":"MEQCIAO9NFOH4cx0hOC2ntGX96xG0pXNhYjMBwC96LFFN9SjAiAWecrmHJFA9N/SVsr3XBlnZAZkzEtD4DuiBHlEWcDpmw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":89249},"main":"./dist/index.js","type":"module","_from":"file:gaia-react-lint-1.0.0.tgz","types":"./dist/index.d.ts","engines":{"node":">=22.19.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"dev":"tsup --watch","lint":"eslint --max-warnings=0 src","build":"tsup && tsc --emitDeclarationOnly","typecheck":"tsc --noEmit"},"_npmUser":{"name":"stevensacks","email":"stevensacks@gmail.com"},"_resolved":"/private/var/folders/pn/m58c653j1js2r48m5n358ync0000gn/T/a65c4e023ddf02722d6b80295d0ed08b/gaia-react-lint-1.0.0.tgz","_integrity":"sha512-R//2FxfFjAXcx6WStrM2aszOPMOT0JBbiknWzjVgQ6/OGF0QhRISJv3V/7SkhEe8x2uhx/nk+7EzxE8d5lEB6w==","repository":{"url":"git+https://github.com/gaia-react/lint.git","type":"git"},"_npmVersion":"11.12.1","description":"GAIA's opinionated lint configuration.","directories":{},"_nodeVersion":"24.14.1","dependencies":{"@eslint/js":"9.39.4","@eslint/compat":"2.0.5","@vitest/eslint-plugin":"1.6.16","eslint-plugin-sonarjs":"4.0.3","eslint-plugin-unicorn":"64.0.0","eslint-config-prettier":"10.1.8","eslint-plugin-jest-dom":"5.5.0","eslint-plugin-prettier":"5.5.5","eslint-plugin-canonical":"5.1.3","eslint-plugin-storybook":"10.3.5","eslint-plugin-check-file":"3.3.1","eslint-plugin-playwright":"2.10.2","eslint-plugin-perfectionist":"5.9.0","eslint-plugin-unused-imports":"4.4.1","eslint-config-airbnb-extended":"3.1.0","eslint-plugin-testing-library":"7.16.2","eslint-plugin-better-tailwindcss":"4.4.1","eslint-plugin-prefer-arrow-functions":"3.9.1","eslint-plugin-no-relative-import-paths":"1.6.1","eslint-plugin-you-dont-need-lodash-underscore":"6.14.0","@eslint-community/eslint-plugin-eslint-comments":"4.7.1"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","eslint":"^9.39.0","typescript":"^6.0.0","@types/node":"^22.0.0","typescript-eslint":"^8.59.0"},"peerDependencies":{"eslint":"^9.0.0","prettier":"^3.0.0","typescript":"^5.0.0 || ^6.0.0"},"peerDependenciesMeta":{"prettier":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/lint_1.0.0_1777295065989_0.05868313818333171","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@gaia-react/lint","version":"1.1.0","keywords":["gaia","gaia-react","eslint","eslint-config","flat-config","react","typescript","lint"],"author":{"name":"Steven Sacks","email":"stevensacks@gmail.com"},"license":"MIT","_id":"@gaia-react/lint@1.1.0","maintainers":[{"name":"stevensacks","email":"stevensacks@gmail.com"}],"homepage":"https://github.com/gaia-react/lint#readme","bugs":{"url":"https://github.com/gaia-react/lint/issues"},"dist":{"shasum":"122b9559313565d424a7b9d6f28d9e61f1431ac1","tarball":"https://registry.npmjs.org/@gaia-react/lint/-/lint-1.1.0.tgz","fileCount":39,"integrity":"sha512-/uV5sQV1H9tSDfdfcZnobsyl9SqgctF5g8jQHBeCD78kzUuxdpjQYrGmA/0BBepenSG2DcZPuRweAOvqKAQhJA==","signatures":[{"sig":"MEUCIQCnyL6x2/NS+UTwvdPRywMGE6UzqE3iZZmP3AK46txgpQIgaMwCX7CtGc5hn5N+VZPKYc5dBwCupta5pSmpZt8QcU8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gaia-react%2flint@1.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":93471},"main":"./dist/index.js","type":"module","_from":"file:gaia-react-lint-1.1.0.tgz","types":"./dist/index.d.ts","engines":{"node":">=22.19.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./prettier":{"types":"./dist/prettier.d.ts","import":"./dist/prettier.js"},"./stylelint":{"types":"./dist/stylelint.d.ts","import":"./dist/stylelint.js"}},"scripts":{"dev":"tsup --watch","lint":"eslint --max-warnings=0 src","build":"tsup && tsc --emitDeclarationOnly","release":"pnpm build && changeset publish","changeset":"changeset","typecheck":"tsc --noEmit","version-packages":"changeset version"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:9aea3cba-8c1b-483c-81db-94a5b33fdbd7"}},"_resolved":"/tmp/6788d9c30acad890e4cdd63dfba06a00/gaia-react-lint-1.1.0.tgz","_integrity":"sha512-/uV5sQV1H9tSDfdfcZnobsyl9SqgctF5g8jQHBeCD78kzUuxdpjQYrGmA/0BBepenSG2DcZPuRweAOvqKAQhJA==","repository":{"url":"git+https://github.com/gaia-react/lint.git","type":"git"},"_npmVersion":"11.11.0","description":"GAIA's opinionated lint configuration.","directories":{},"_nodeVersion":"24.14.1","dependencies":{"@eslint/js":"9.39.4","@eslint/compat":"2.0.5","stylelint-order":"8.1.1","@vitest/eslint-plugin":"1.6.16","eslint-plugin-sonarjs":"4.0.3","eslint-plugin-unicorn":"64.0.0","eslint-config-prettier":"10.1.8","eslint-plugin-jest-dom":"5.5.0","eslint-plugin-prettier":"5.5.5","eslint-plugin-canonical":"5.1.3","eslint-plugin-storybook":"10.3.5","eslint-plugin-check-file":"3.3.1","eslint-plugin-playwright":"2.10.2","stylelint-config-standard":"40.0.0","eslint-plugin-perfectionist":"5.9.0","prettier-plugin-tailwindcss":"0.7.3","eslint-plugin-unused-imports":"4.4.1","stylelint-config-clean-order":"8.0.1","stylelint-config-tailwindcss":"1.0.1","eslint-config-airbnb-extended":"3.1.0","eslint-plugin-testing-library":"7.16.2","eslint-plugin-better-tailwindcss":"4.4.1","eslint-plugin-prefer-arrow-functions":"3.9.1","eslint-plugin-no-relative-import-paths":"1.6.1","eslint-plugin-you-dont-need-lodash-underscore":"6.14.0","@eslint-community/eslint-plugin-eslint-comments":"4.7.1"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","eslint":"^9.39.0","typescript":"^6.0.0","@types/node":"^22.0.0","@changesets/cli":"^2.31.0","typescript-eslint":"^8.59.0","@changesets/changelog-github":"^0.6.0"},"peerDependencies":{"eslint":"^9.0.0","prettier":"^3.0.0","stylelint":"^17.0.0","typescript":"^5.0.0 || ^6.0.0"},"peerDependenciesMeta":{"prettier":{"optional":true},"stylelint":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/lint_1.1.0_1777299273985_0.26135661441926783","host":"s3://npm-registry-packages-npm-production"}},"1.1.1":{"name":"@gaia-react/lint","version":"1.1.1","description":"GAIA's opinionated lint configuration.","type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"import":"./dist/index.js","types":"./dist/index.d.ts"},"./prettier":{"import":"./dist/prettier.js","types":"./dist/prettier.d.ts"},"./stylelint":{"import":"./dist/stylelint.js","types":"./dist/stylelint.d.ts"}},"engines":{"node":">=22.19.0"},"peerDependencies":{"eslint":"^9.0.0","prettier":"^3.0.0","stylelint":"^17.0.0","typescript":"^5.0.0 || ^6.0.0"},"peerDependenciesMeta":{"prettier":{"optional":true},"stylelint":{"optional":true}},"dependencies":{"@eslint-community/eslint-plugin-eslint-comments":"4.7.1","@eslint/compat":"2.0.5","@eslint/js":"9.39.4","@vitest/eslint-plugin":"1.6.16","eslint-config-airbnb-extended":"3.1.0","eslint-config-prettier":"10.1.8","eslint-plugin-better-tailwindcss":"4.4.1","eslint-plugin-canonical":"5.1.3","eslint-plugin-check-file":"3.3.1","eslint-plugin-jest-dom":"5.5.0","eslint-plugin-no-relative-import-paths":"1.6.1","eslint-plugin-perfectionist":"5.9.0","eslint-plugin-playwright":"2.10.2","eslint-plugin-prefer-arrow-functions":"3.9.1","eslint-plugin-prettier":"5.5.5","eslint-plugin-sonarjs":"4.0.3","eslint-plugin-storybook":"10.3.5","eslint-plugin-testing-library":"7.16.2","eslint-plugin-unicorn":"64.0.0","eslint-plugin-unused-imports":"4.4.1","eslint-plugin-you-dont-need-lodash-underscore":"6.14.0","prettier-plugin-tailwindcss":"0.7.3","stylelint-config-clean-order":"8.0.1","stylelint-config-standard":"40.0.0","stylelint-config-tailwindcss":"1.0.1","stylelint-order":"8.1.1"},"devDependencies":{"@changesets/changelog-github":"^0.6.0","@changesets/cli":"^2.31.0","@types/node":"^22.0.0","eslint":"^9.39.0","tsup":"^8.0.0","typescript":"^6.0.0","typescript-eslint":"^8.59.0"},"author":{"name":"Steven Sacks","email":"stevensacks@gmail.com"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/gaia-react/lint.git"},"homepage":"https://github.com/gaia-react/lint#readme","bugs":{"url":"https://github.com/gaia-react/lint/issues"},"keywords":["gaia","gaia-react","eslint","eslint-config","flat-config","react","typescript","lint"],"scripts":{"build":"tsup && tsc --emitDeclarationOnly","dev":"tsup --watch","typecheck":"tsc --noEmit","lint":"eslint --max-warnings=0 src","changeset":"changeset","version-packages":"changeset version","release":"pnpm build && changeset publish"},"_id":"@gaia-react/lint@1.1.1","_integrity":"sha512-qaFONQbWs+SLD6PqTddtFE9e2etvSkGyKMq+CZngL6Wx7SBJWbw1xJXBWKSbN6vuTOobCzoJ7Q3Br3TfyHsY2Q==","_resolved":"/tmp/bc5e125a7cc1dc464b1296afed0be976/gaia-react-lint-1.1.1.tgz","_from":"file:gaia-react-lint-1.1.1.tgz","_nodeVersion":"24.14.1","_npmVersion":"11.11.0","dist":{"integrity":"sha512-qaFONQbWs+SLD6PqTddtFE9e2etvSkGyKMq+CZngL6Wx7SBJWbw1xJXBWKSbN6vuTOobCzoJ7Q3Br3TfyHsY2Q==","shasum":"ca50dacd5c4866ae69a444b2c2ca1ab01c4757bf","tarball":"https://registry.npmjs.org/@gaia-react/lint/-/lint-1.1.1.tgz","fileCount":39,"unpackedSize":95443,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gaia-react%2flint@1.1.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDu4I7mzg02eOnZHRnq9tW1BhY/vMg9cB/896l0Z7vYGQIhAIYerheVy/K+Br35uymZzmN1/BKzPWhEuBtC/cSZ5ox6"}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:9aea3cba-8c1b-483c-81db-94a5b33fdbd7"}},"directories":{},"maintainers":[{"name":"stevensacks","email":"stevensacks@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/lint_1.1.1_1777491651652_0.6366865375224096"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-27T13:04:25.874Z","modified":"2026-04-29T19:40:52.067Z","1.0.0":"2026-04-27T13:04:26.139Z","1.1.0":"2026-04-27T14:14:34.116Z","1.1.1":"2026-04-29T19:40:51.778Z"},"bugs":{"url":"https://github.com/gaia-react/lint/issues"},"author":{"name":"Steven Sacks","email":"stevensacks@gmail.com"},"license":"MIT","homepage":"https://github.com/gaia-react/lint#readme","keywords":["gaia","gaia-react","eslint","eslint-config","flat-config","react","typescript","lint"],"repository":{"type":"git","url":"git+https://github.com/gaia-react/lint.git"},"description":"GAIA's opinionated lint configuration.","maintainers":[{"name":"stevensacks","email":"stevensacks@gmail.com"}],"readme":"# @gaia-react/lint\n\nGAIA's lint configuration.\n\n## Install\n\n```sh\npnpm add -D @gaia-react/lint eslint prettier typescript\n```\n\n## Quick start\n\nThe block below is the actual `eslint.config.mjs` shipped by GAIA. Copy it\nverbatim and adjust the override block at the bottom for your project.\n\n```js\nimport gaiaLint from '@gaia-react/lint';\nimport {defineConfig} from 'eslint/config';\n\nexport default defineConfig([\n  ...gaiaLint.ignores({gitignore: '.gitignore'}),\n  ...gaiaLint.base,\n  ...gaiaLint.react,\n  ...gaiaLint.testing,\n  ...gaiaLint.storybook,\n  ...gaiaLint.playwright,\n  ...gaiaLint.styleHygiene,\n  ...gaiaLint.guardrails,\n  ...gaiaLint.betterTailwind({\n    entryPoint: './app/styles/tailwind.css',\n    ignore: ['plain-link', 'plain-table'],\n  }),\n  ...gaiaLint.prettier,\n]);\n```\n\n## Exports\n\n| Export           | Shape                            | Includes                                                                                                                                          | Required? |\n| ---------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | --------- |\n| `base`           | `Linter.Config[]`                | JS recommended, TypeScript (typescript-eslint), `import-x`, `eslint-comments`, `prefer-arrow-functions`, lodash/underscore guard                  | required  |\n| `react`          | `Linter.Config[]`                | `eslint-plugin-react`, `react-hooks`, `jsx-a11y`, GAIA-specific React rules                                                                       | required for React apps |\n| `styleHygiene`   | `Linter.Config[]`                | `canonical`, `perfectionist`, `unicorn`, `unused-imports`, `check-file`                                                                           | required  |\n| `guardrails`     | `Linter.Config[]`                | `no-enum` (custom), `no-switch` (custom), `no-relative-import-paths`, `sonarjs`, `eslint-comments`, `import-x`, `prefer-arrow-functions`          | required  |\n| `testing`        | `Linter.Config[]`                | Vitest + Testing Library config scoped to `*.test.*` and `test/`                                                                                  | optional  |\n| `storybook`      | `Linter.Config[]`                | `eslint-plugin-storybook` scoped to `*.stories.*`                                                                                                 | optional  |\n| `playwright`     | `Linter.Config[]`                | `eslint-plugin-playwright` scoped to `e2e/`                                                                                                       | optional  |\n| `prettier`       | `Linter.Config[]`                | `eslint-config-prettier` — must be **last** to disable formatting rules                                                                           | required if using Prettier |\n| `betterTailwind` | `(opts) => Linter.Config[]`      | `eslint-plugin-better-tailwindcss` factory; takes `entryPoint` (path to Tailwind entry CSS) and optional `ignore` (class names to skip)           | optional  |\n| `ignores`        | `(opts?) => Linter.Config[]`     | `includeIgnoreFile` helper plus GAIA defaults; takes optional `gitignore` (path) and `extra` (string[])                                           | recommended |\n\nThe default export bundles every named export:\n\n```js\nimport gaiaLint from '@gaia-react/lint';\n// gaiaLint.base, gaiaLint.react, gaiaLint.betterTailwind({...}), ...\n```\n\n## Override patterns\n\nFlat config is last-write-wins. Append override blocks **after** the\ngaia-lint spreads to disable, change, or scope rules.\n\n### Disable a rule globally\n\n```js\nexport default defineConfig([\n  ...gaiaLint.base,\n  ...gaiaLint.react,\n  {rules: {'sonarjs/cognitive-complexity': 'off'}},\n]);\n```\n\n### Override on specific globs\n\n```js\nexport default defineConfig([\n  ...gaiaLint.base,\n  ...gaiaLint.react,\n  {\n    files: ['app/legacy/**'],\n    rules: {'sonarjs/cognitive-complexity': 'off'},\n  },\n]);\n```\n\n### Swap parser options\n\n```js\nexport default defineConfig([\n  ...gaiaLint.base,\n  {\n    languageOptions: {\n      parserOptions: {project: './tsconfig.eslint.json'},\n    },\n  },\n]);\n```\n\n### Add an extra plugin\n\n```js\nimport myPlugin from 'eslint-plugin-my-plugin';\n\nexport default defineConfig([\n  ...gaiaLint.base,\n  ...gaiaLint.react,\n  {\n    plugins: {'my-plugin': myPlugin},\n    rules: {'my-plugin/some-rule': 'error'},\n  },\n]);\n```\n\n## Peer dependencies\n\n`eslint`, `prettier`, and `typescript` are declared as **peer\ndependencies** so consumers control their own versions and a single resolved\ncopy of each is installed in `node_modules`. Every other plugin\n(`eslint-plugin-react`, `typescript-eslint`, `eslint-plugin-import-x`, etc.)\nships as a direct `dependency` of `@gaia-react/lint` so consumers don't\nhave to install or upgrade them individually.\n\nSupported versions:\n\n- `eslint ^9.0.0`\n- `prettier ^3.0.0`\n- `typescript ^5.0.0 || ^6.0.0`\n\n## Custom rules included\n\nTwo rules are implemented inside this package and ship as part of\n`guardrails`.\n\n### `no-enum`\n\nForbids TypeScript `enum` declarations. Enums emit runtime code, are not\ntree-shakeable, conflate value and type space, and have well-known footguns\naround numeric vs string enums and reverse mappings. Use a `const` object\nplus a derived union type instead.\n\n```ts\n// flagged\nenum Status {\n  Active,\n  Inactive,\n}\n\n// preferred\nconst Status = {\n  Active: 'active',\n  Inactive: 'inactive',\n} as const;\ntype Status = (typeof Status)[keyof typeof Status];\n```\n\nOpt out for a file or block:\n\n```js\n{files: ['src/legacy/**'], rules: {'no-enum/no-enum': 'off'}}\n```\n\n### `no-switch`\n\nForbids `switch` statements. They are an early-return / lookup-map / `if`\nchain in disguise and are easy to misuse (fallthrough, missing `default`,\nshadowed locals across cases). Replace with a lookup object, an early\n`return` chain, or a discriminated-union exhaustiveness check.\n\nOpt out for a file or block:\n\n```js\n{files: ['src/parser/**'], rules: {'no-switch/no-switch': 'off'}}\n```\n\n## Tailwind / better-tailwindcss factory\n\n`betterTailwind` is a factory because the underlying plugin needs to know\nwhere your Tailwind entry CSS file lives.\n\n```js\n...gaiaLint.betterTailwind({\n  entryPoint: './app/styles/tailwind.css',\n  ignore: ['plain-link', 'plain-table'],\n}),\n```\n\n| Option       | Type       | Required | Description                                                                                  |\n| ------------ | ---------- | -------- | -------------------------------------------------------------------------------------------- |\n| `entryPoint` | `string`   | yes      | Path to your Tailwind entry CSS, used by the plugin to resolve the active class set.         |\n| `ignore`     | `string[]` | no       | Class names the plugin should ignore in `no-unregistered-classes` (e.g. design-system tokens, `plain-*` utility shims). |\n\n## Ignores factory\n\n`ignores` produces a leading flat-config block that merges your\n`.gitignore` plus GAIA defaults.\n\n```js\n...gaiaLint.ignores({\n  gitignore: '.gitignore',\n  extra: ['coverage/**', '**/*.generated.ts'],\n}),\n```\n\n| Option     | Type       | Required | Description                                                                                          |\n| ---------- | ---------- | -------- | ---------------------------------------------------------------------------------------------------- |\n| `gitignore`| `string`   | no       | Path to a `.gitignore` file (relative to `cwd` or absolute). Patterns are merged via `includeIgnoreFile`. |\n| `extra`    | `string[]` | no       | Extra ignore globs merged with GAIA defaults.                                                        |\n\n## GAIA folder conventions baked into `check-file`\n\nThe `check-file` rules in `styleHygiene` encode GAIA's folder layout:\n\n- `app/components/**` — component file naming\n- `app/pages/**` — route/page file naming\n- `app/hooks/**` — hook file naming (`use-*.ts`)\n- `test/**` — test harness naming\n\nIf your project uses a different layout, override the relevant\n`check-file/*` rules **after** the `styleHygiene` spread:\n\n```js\nexport default defineConfig([\n  ...gaiaLint.base,\n  ...gaiaLint.styleHygiene,\n  // Project uses src/ instead of app/\n  {\n    files: ['src/components/**'],\n    rules: {\n      'check-file/filename-naming-convention': [\n        'error',\n        {'src/components/**/*.{ts,tsx}': 'PASCAL_CASE'},\n      ],\n    },\n  },\n]);\n```\n\nOr disable the GAIA `check-file` block entirely and reapply your own:\n\n```js\n{rules: {'check-file/folder-naming-convention': 'off'}}\n```\n\n## Versioning policy\n\nThis package follows SemVer.\n\n- **Patch.** Plugin version bumps that do not change rule defaults, internal\n  refactors, README fixes.\n- **Minor.** New rules added, new options exposed on factories, new named\n  exports, opt-in changes that do not break existing consumer configs.\n- **Major.** Engine swaps (ESLint → Biome), `eslint` major version bumps,\n  removal/rename of named exports, default-rule changes that introduce new\n  errors in previously-clean code.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}