@gaia-harness/lint 0.0.0-stage → 3.0.3
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/LICENSE +21 -0
- package/README.md +514 -2
- package/dist/configs/base.d.ts +3 -0
- package/dist/configs/base.d.ts.map +1 -0
- package/dist/configs/better-tailwind.d.ts +17 -0
- package/dist/configs/better-tailwind.d.ts.map +1 -0
- package/dist/configs/guardrails.d.ts +3 -0
- package/dist/configs/guardrails.d.ts.map +1 -0
- package/dist/configs/i18n.d.ts +17 -0
- package/dist/configs/i18n.d.ts.map +1 -0
- package/dist/configs/ignores.d.ts +25 -0
- package/dist/configs/ignores.d.ts.map +1 -0
- package/dist/configs/playwright.d.ts +10 -0
- package/dist/configs/playwright.d.ts.map +1 -0
- package/dist/configs/prettier.d.ts +11 -0
- package/dist/configs/prettier.d.ts.map +1 -0
- package/dist/configs/react-router.d.ts +37 -0
- package/dist/configs/react-router.d.ts.map +1 -0
- package/dist/configs/react.d.ts +23 -0
- package/dist/configs/react.d.ts.map +1 -0
- package/dist/configs/restricted-imports.d.ts +29 -0
- package/dist/configs/restricted-imports.d.ts.map +1 -0
- package/dist/configs/shadcn.d.ts +59 -0
- package/dist/configs/shadcn.d.ts.map +1 -0
- package/dist/configs/storybook.d.ts +9 -0
- package/dist/configs/storybook.d.ts.map +1 -0
- package/dist/configs/style-hygiene.d.ts +3 -0
- package/dist/configs/style-hygiene.d.ts.map +1 -0
- package/dist/configs/testing.d.ts +10 -0
- package/dist/configs/testing.d.ts.map +1 -0
- package/dist/configs/zod.d.ts +16 -0
- package/dist/configs/zod.d.ts.map +1 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1938 -0
- package/dist/index.js.map +1 -0
- package/dist/plugins/cn-conditional.d.ts +4 -0
- package/dist/plugins/cn-conditional.d.ts.map +1 -0
- package/dist/plugins/no-enum.d.ts +4 -0
- package/dist/plugins/no-enum.d.ts.map +1 -0
- package/dist/plugins/no-imperative-query-fetch.d.ts +4 -0
- package/dist/plugins/no-imperative-query-fetch.d.ts.map +1 -0
- package/dist/plugins/no-jsx-iife.d.ts +4 -0
- package/dist/plugins/no-jsx-iife.d.ts.map +1 -0
- package/dist/plugins/no-null-render.d.ts +4 -0
- package/dist/plugins/no-null-render.d.ts.map +1 -0
- package/dist/plugins/no-switch.d.ts +4 -0
- package/dist/plugins/no-switch.d.ts.map +1 -0
- package/dist/plugins/no-zod-enum.d.ts +4 -0
- package/dist/plugins/no-zod-enum.d.ts.map +1 -0
- package/dist/prettier.d.ts +4 -0
- package/dist/prettier.d.ts.map +1 -0
- package/dist/prettier.js +15 -0
- package/dist/prettier.js.map +1 -0
- package/dist/stylelint.d.ts +4 -0
- package/dist/stylelint.d.ts.map +1 -0
- package/dist/stylelint.js +36 -0
- package/dist/stylelint.js.map +1 -0
- package/package.json +119 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Steven Sacks
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,515 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @gaia-harness/lint
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
GAIA's lint configuration.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
pnpm add -D @gaia-harness/lint eslint prettier typescript
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick start
|
|
12
|
+
|
|
13
|
+
The block below is the actual `eslint.config.mjs` shipped by GAIA. Copy it
|
|
14
|
+
verbatim and adjust the override block at the bottom for your project.
|
|
15
|
+
|
|
16
|
+
```js
|
|
17
|
+
import gaiaLint from '@gaia-harness/lint';
|
|
18
|
+
import {defineConfig} from 'eslint/config';
|
|
19
|
+
|
|
20
|
+
const lint = gaiaLint();
|
|
21
|
+
|
|
22
|
+
export default defineConfig([
|
|
23
|
+
...lint.ignores,
|
|
24
|
+
...lint.base,
|
|
25
|
+
...lint.react,
|
|
26
|
+
...lint.reactRouter,
|
|
27
|
+
...lint.testing,
|
|
28
|
+
...lint.storybook,
|
|
29
|
+
...lint.playwright,
|
|
30
|
+
...lint.styleHygiene,
|
|
31
|
+
...lint.guardrails,
|
|
32
|
+
...lint.i18n, // opt-in; drop if the UI is not translated
|
|
33
|
+
...lint.zod, // opt-in; Zod 4 projects
|
|
34
|
+
...lint.betterTailwind({entryPoint: './app/styles/tailwind.css'}),
|
|
35
|
+
...lint.prettier,
|
|
36
|
+
...lint.shadcn({ui: '~/components/ui'}), // opt-in; must be last
|
|
37
|
+
]);
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Drop the `reactRouter` line if you are not on React Router framework mode.
|
|
41
|
+
See [Router-specific rules](#router-specific-rules). Drop the `shadcn` line if
|
|
42
|
+
you do not use shadcn/ui; see [shadcn factory](#shadcn-factory). Drop the
|
|
43
|
+
`i18n` or `zod` line if the project does not translate its UI or does not use
|
|
44
|
+
Zod; see [i18n and Zod](#i18n-and-zod).
|
|
45
|
+
|
|
46
|
+
## Factory options
|
|
47
|
+
|
|
48
|
+
`gaiaLint(opts?)` returns a bundle of config blocks. Call it once at the
|
|
49
|
+
top of `eslint.config.mjs` and spread the returned configs into
|
|
50
|
+
`defineConfig`.
|
|
51
|
+
|
|
52
|
+
| Option | Type | Default | Description |
|
|
53
|
+
| ----------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
54
|
+
| `sourceDir` | `string` | `'app'` | Project source directory (relative to repo root). Used to scope filename conventions, hook-folder rules, and the `no-relative-import-paths` root path. |
|
|
55
|
+
|
|
56
|
+
Non-GAIA projects that store source under `src/` (or any other path):
|
|
57
|
+
|
|
58
|
+
```js
|
|
59
|
+
const lint = gaiaLint({sourceDir: 'src'});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
That single call rebinds `base`, `reactRouter`, `styleHygiene`, and `guardrails` to the
|
|
63
|
+
new source root: no per-config override blocks needed.
|
|
64
|
+
|
|
65
|
+
## Bundle shape
|
|
66
|
+
|
|
67
|
+
| Property | Shape | Includes | Required? |
|
|
68
|
+
| ---------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | --------- |
|
|
69
|
+
| `base` | `Linter.Config[]` | JS recommended, TypeScript (typescript-eslint), `import-x`, unused-disable-directive reporting at error, `eslint-comments` (every disable states a reason), `prefer-arrow-functions`, lodash/underscore guard, `no-restricted-imports` (bans bare `@conform-to/zod`) | required |
|
|
70
|
+
| `react` | `Linter.Config[]` | `eslint-plugin-react`, `react-hooks`, `jsx-a11y`, `react-refresh` (Fast Refresh-safe exports), `react-you-might-not-need-an-effect` (Effect misuse), nine `@eslint-react` rules (Effect cleanup, React 19 forms), GAIA-specific React rules | required for React apps |
|
|
71
|
+
| `reactRouter` | `Linter.Config[]` | Relaxations for React Router framework mode, route-module exports allowed by `react-refresh`, plus `no-imperative-query-fetch` (custom). Spread **after** `react`. See [Router-specific rules](#router-specific-rules) | React Router only |
|
|
72
|
+
| `styleHygiene` | `Linter.Config[]` | `canonical`, `perfectionist`, `unicorn`, `unused-imports`, `check-file` | required |
|
|
73
|
+
| `guardrails` | `Linter.Config[]` | `regexp` (recommended, ReDoS included), `no-enum` (custom), `no-switch` (custom), `no-jsx-iife` (custom), `no-null-render` (custom), `no-zod-enum` (custom), `cn-conditional` (custom), `no-relative-import-paths`, `sonarjs`, `import-x`, `prefer-arrow-functions` | required |
|
|
74
|
+
| `i18n` | `Linter.Config[]` | `i18next/no-literal-string` on raw JSX text under the source dir. See [i18n and Zod](#i18n-and-zod) | optional |
|
|
75
|
+
| `zod` | `Linter.Config[]` | `eslint-plugin-zod` recommended, minus `consistent-import`. See [i18n and Zod](#i18n-and-zod) | optional |
|
|
76
|
+
| `testing` | `Linter.Config[]` | Vitest + jest-dom config scoped to `*.test.*`, `*.stories.*` and `test/` | optional |
|
|
77
|
+
| `storybook` | `Linter.Config[]` | `eslint-plugin-storybook` scoped to `*.stories.*` and `.storybook/main.*` | optional |
|
|
78
|
+
| `playwright` | `Linter.Config[]` | `eslint-plugin-playwright` scoped to `.playwright/` | optional |
|
|
79
|
+
| `prettier` | `Linter.Config[]` | `eslint-config-prettier`, must be **last** to disable formatting rules | required if using Prettier |
|
|
80
|
+
| `shadcn` | `(opts?) => Linter.Config[]` | `@shadcn/lint` token rules plus the vendored-ui exemption; see [shadcn factory](#shadcn-factory). Spread **last**, after `prettier`, with the full GAIA composition before it | optional |
|
|
81
|
+
| `betterTailwind` | `(opts) => Linter.Config[]` | `eslint-plugin-better-tailwindcss` factory; takes `entryPoint` (path to Tailwind entry CSS) and optional `ignore` (class names to skip) | optional |
|
|
82
|
+
| `ignores` | `Iterable<Linter.Config> & ((opts?) => Linter.Config[])` | `includeIgnoreFile` helper plus GAIA defaults. Spread directly for defaults (`...lint.ignores`) or call with options to override (`...lint.ignores({extra: ['.gaia/**']})`). | recommended |
|
|
83
|
+
|
|
84
|
+
## Override patterns
|
|
85
|
+
|
|
86
|
+
Flat config is last-write-wins. Append override blocks **after** the
|
|
87
|
+
gaia-lint spreads to disable, change, or scope rules.
|
|
88
|
+
|
|
89
|
+
### Disable a rule globally
|
|
90
|
+
|
|
91
|
+
```js
|
|
92
|
+
export default defineConfig([
|
|
93
|
+
...lint.base,
|
|
94
|
+
...lint.react,
|
|
95
|
+
{rules: {'sonarjs/cognitive-complexity': 'off'}},
|
|
96
|
+
]);
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Override on specific globs
|
|
100
|
+
|
|
101
|
+
```js
|
|
102
|
+
export default defineConfig([
|
|
103
|
+
...lint.base,
|
|
104
|
+
...lint.react,
|
|
105
|
+
{
|
|
106
|
+
files: ['app/legacy/**'],
|
|
107
|
+
rules: {'sonarjs/cognitive-complexity': 'off'},
|
|
108
|
+
},
|
|
109
|
+
]);
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Swap parser options
|
|
113
|
+
|
|
114
|
+
```js
|
|
115
|
+
export default defineConfig([
|
|
116
|
+
...lint.base,
|
|
117
|
+
{
|
|
118
|
+
languageOptions: {
|
|
119
|
+
parserOptions: {project: './tsconfig.eslint.json'},
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
]);
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Add an extra plugin
|
|
126
|
+
|
|
127
|
+
```js
|
|
128
|
+
import myPlugin from 'eslint-plugin-my-plugin';
|
|
129
|
+
|
|
130
|
+
export default defineConfig([
|
|
131
|
+
...lint.base,
|
|
132
|
+
...lint.react,
|
|
133
|
+
{
|
|
134
|
+
plugins: {'my-plugin': myPlugin},
|
|
135
|
+
rules: {'my-plugin/some-rule': 'error'},
|
|
136
|
+
},
|
|
137
|
+
]);
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Peer dependencies
|
|
141
|
+
|
|
142
|
+
`eslint`, `prettier`, and `typescript` are declared as **peer
|
|
143
|
+
dependencies** so consumers control their own versions and a single resolved
|
|
144
|
+
copy of each is installed in `node_modules`. Every other plugin
|
|
145
|
+
(`eslint-plugin-react`, `typescript-eslint`, `eslint-plugin-import-x`, etc.)
|
|
146
|
+
ships as a direct `dependency` of `@gaia-harness/lint` so consumers don't
|
|
147
|
+
have to install or upgrade them individually.
|
|
148
|
+
|
|
149
|
+
Supported versions:
|
|
150
|
+
|
|
151
|
+
- `eslint ^9.30.0` (`@shadcn/lint` needs 9.30 or later)
|
|
152
|
+
- `prettier ^3.0.0`
|
|
153
|
+
- `typescript ^5.0.0 || ^6.0.0`
|
|
154
|
+
|
|
155
|
+
## Custom rules included
|
|
156
|
+
|
|
157
|
+
These rules are implemented inside this package and ship as part of
|
|
158
|
+
`guardrails`.
|
|
159
|
+
|
|
160
|
+
### `no-enum`
|
|
161
|
+
|
|
162
|
+
Forbids TypeScript `enum` declarations. Enums emit runtime code, are not
|
|
163
|
+
tree-shakeable, conflate value and type space, and have well-known footguns
|
|
164
|
+
around numeric vs string enums and reverse mappings. Use a `const` object
|
|
165
|
+
plus a derived union type instead.
|
|
166
|
+
|
|
167
|
+
Opt out for a file or block:
|
|
168
|
+
|
|
169
|
+
```js
|
|
170
|
+
{files: ['src/legacy/**'], rules: {'no-enum/no-enum': 'off'}}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### `no-switch`
|
|
174
|
+
|
|
175
|
+
Forbids `switch` statements. They are an early-return / lookup-map / `if`
|
|
176
|
+
chain in disguise and are easy to misuse (fallthrough, missing `default`,
|
|
177
|
+
shadowed locals across cases). Replace with a lookup object, an early
|
|
178
|
+
`return` chain, or a discriminated-union exhaustiveness check.
|
|
179
|
+
|
|
180
|
+
Opt out for a file or block:
|
|
181
|
+
|
|
182
|
+
```js
|
|
183
|
+
{files: ['src/parser/**'], rules: {'no-switch/no-switch': 'off'}}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### `no-jsx-iife`
|
|
187
|
+
|
|
188
|
+
Forbids IIFEs (`{(() => { ... })()}`) inside JSX expression containers in `.tsx` and `.jsx` files. IIFEs obscure intent and allocate a new function on every render. Compute the value in a variable before the return statement, or use an inline `&&` expression instead.
|
|
189
|
+
|
|
190
|
+
Opt out for a file or block:
|
|
191
|
+
|
|
192
|
+
```js
|
|
193
|
+
{files: ['src/legacy/**'], rules: {'no-jsx-iife/no-jsx-iife': 'off'}}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### `no-null-render`
|
|
197
|
+
|
|
198
|
+
Standardizes the empty render on `undefined` instead of `null` in `.tsx` and
|
|
199
|
+
`.jsx` files. A `return null` inside a function that provably renders JSX (it
|
|
200
|
+
returns a JSX element elsewhere in the same scope) is rewritten to
|
|
201
|
+
`return undefined`. `null` and `undefined` are identical to React's reconciler
|
|
202
|
+
(both, with `false`/`true`, are the same empty slot); this is a consistency
|
|
203
|
+
convention that picks one of two equivalent forms, not a correctness or
|
|
204
|
+
performance fix.
|
|
205
|
+
|
|
206
|
+
Autofixable: `--fix` rewrites `return null` → `return undefined`. The fix is
|
|
207
|
+
deliberately conservative and only touches a `return null` whose enclosing
|
|
208
|
+
function is provably a render function, so a `return null` in a loader, action,
|
|
209
|
+
or plain utility is never altered. `: null` ternary arms are out of scope (the
|
|
210
|
+
report-only `no-restricted-syntax` selectors cover those).
|
|
211
|
+
|
|
212
|
+
Opt out for a file or block:
|
|
213
|
+
|
|
214
|
+
```js
|
|
215
|
+
{files: ['src/legacy/**'], rules: {'no-null-render/no-null-render': 'off'}}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### `cn-conditional`
|
|
219
|
+
|
|
220
|
+
Holds one form for a conditional class passed to `cn` from the
|
|
221
|
+
[`cn`](https://www.npmjs.com/package/cn) package: `cond && 'class'` (or
|
|
222
|
+
`!cond && 'class'`). It reports an object argument (`cn('a', {b: c})`) and a
|
|
223
|
+
ternary with an empty branch (`undefined`, `null`, `false`, `''`, or an empty
|
|
224
|
+
template), at any depth inside array arguments, ternary branches, and `&&`,
|
|
225
|
+
`||`, or `??` operands. Each offending node is reported once.
|
|
226
|
+
|
|
227
|
+
Allowed: `cn('a', c && 'b')`, `cn('a', !c && 'b')`, a two-class ternary
|
|
228
|
+
(`cn('a', c ? 'b' : 'd')`), `||` and `??` of values, strings, identifiers,
|
|
229
|
+
lookups (`VARIANTS[v]`), arrays of those, spreads, and template literals. The
|
|
230
|
+
condition side of `&&` and a ternary's test are never inspected.
|
|
231
|
+
|
|
232
|
+
It only fires on a call to the named import `cn` from `'cn'` (an aliased import
|
|
233
|
+
counts). A locally declared `cn`, or a `cn` imported from any other module, is
|
|
234
|
+
never reported. It is not autofixable, and it is active in test, story, and
|
|
235
|
+
Playwright files as well as source.
|
|
236
|
+
|
|
237
|
+
Opt out for a file or block:
|
|
238
|
+
|
|
239
|
+
```js
|
|
240
|
+
{files: ['src/legacy/**'], rules: {'cn-conditional/cn-conditional': 'off'}}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Router-specific rules
|
|
244
|
+
|
|
245
|
+
`reactRouter` is opt-in because it is **subtractive**. `storybook` and
|
|
246
|
+
`playwright` only add rules, so spreading them can never weaken anything.
|
|
247
|
+
`reactRouter` turns `no-empty-pattern` **off**, and its glob
|
|
248
|
+
(`**/routes/**/*.tsx`) is not unique to React Router, since TanStack Router
|
|
249
|
+
uses a `routes/` directory too. Shipping it inside `react` silently relaxed
|
|
250
|
+
the rule for every file-based router that isn't React Router.
|
|
251
|
+
|
|
252
|
+
```js
|
|
253
|
+
...lint.react,
|
|
254
|
+
...lint.reactRouter, // React Router framework mode only
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
**On React Router?** Spread it. A route module destructures nothing from its
|
|
258
|
+
typed props (`({}: Route.ComponentProps)`), which `no-empty-pattern` reads as
|
|
259
|
+
an empty pattern.
|
|
260
|
+
|
|
261
|
+
**On TanStack Router, or any other router?** Omit it, and keep the rule.
|
|
262
|
+
`createFileRoute(...)({component: Named})` never produces the empty-pattern
|
|
263
|
+
shape. You will most likely also want to ignore your generated route tree:
|
|
264
|
+
|
|
265
|
+
```js
|
|
266
|
+
...lint.ignores({extra: ['**/routeTree.gen.ts']}),
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
`reactRouter` also adds one rule, `no-imperative-query-fetch/no-imperative-query-fetch`,
|
|
270
|
+
on every TypeScript file under the source dir. It bans `ensureQueryData`,
|
|
271
|
+
`fetchQuery`, `prefetchQuery` and their infinite variants on any member call,
|
|
272
|
+
so a route has one fetch idiom: `await queryClient.query(options)` in a
|
|
273
|
+
clientLoader, read with `useSuspenseQuery(options)` in the component. It
|
|
274
|
+
matches by method name, so it fires whether or not TanStack Query is
|
|
275
|
+
installed.
|
|
276
|
+
|
|
277
|
+
`react` turns on `react-refresh/only-export-components`, because a module that
|
|
278
|
+
exports anything besides components cannot be hot-swapped and Fast Refresh
|
|
279
|
+
falls back to a full reload. `reactRouter` lets route modules (`**/routes/**`
|
|
280
|
+
and `root.tsx`) export React Router's route-module names beside their
|
|
281
|
+
component: `loader`, `clientLoader`, `action`, `clientAction`, `middleware`,
|
|
282
|
+
`clientMiddleware`, `meta`, `links`, `headers`, `handle`, `shouldRevalidate`,
|
|
283
|
+
`ErrorBoundary`, `HydrateFallback` and `Layout`. Any other export from a route
|
|
284
|
+
module is still reported; move it to its own module.
|
|
285
|
+
|
|
286
|
+
The `/.react-router/**` glob stays in the `ignores` defaults. It names a
|
|
287
|
+
directory that only exists in a React Router project, so it costs other
|
|
288
|
+
projects nothing.
|
|
289
|
+
|
|
290
|
+
## i18n and Zod
|
|
291
|
+
|
|
292
|
+
Both are opt-in arrays: spread them only when the project uses the library.
|
|
293
|
+
|
|
294
|
+
`lint.i18n` turns on `i18next/no-literal-string` in `jsx-text-only` mode for
|
|
295
|
+
`.tsx`/`.jsx` under the source dir. It reports raw text between JSX tags
|
|
296
|
+
(`<p>Hello</p>`), which should come from `t()`. Attributes are not checked,
|
|
297
|
+
since `data-slot`, `htmlFor` and `value` strings are not UI copy. Stories,
|
|
298
|
+
tests, `tests/` helpers and the vendored `components/ui/*.tsx` files are
|
|
299
|
+
exempt. Text that must stay untranslated, such as an error boundary that has to
|
|
300
|
+
render without i18n, takes an inline disable with a reason. A project that
|
|
301
|
+
drops i18n removes the line, and adds it back if it adds a language later.
|
|
302
|
+
|
|
303
|
+
`lint.zod` turns on `eslint-plugin-zod`'s recommended set for Zod 4:
|
|
304
|
+
conflicting or duplicate checks, `.optional()` with `.default()`, a `throw`
|
|
305
|
+
inside `.refine()`, a refine without an error message, `z.nativeEnum`,
|
|
306
|
+
`z.any()`, and the Zod 3 forms Zod 4 deprecates. `consistent-import` is off
|
|
307
|
+
because it wants `import * as z from 'zod'`, and GAIA writes
|
|
308
|
+
`import {z} from 'zod'`.
|
|
309
|
+
|
|
310
|
+
## Tailwind / better-tailwindcss factory
|
|
311
|
+
|
|
312
|
+
`betterTailwind` is a factory because the underlying plugin needs to know
|
|
313
|
+
where your Tailwind entry CSS file lives.
|
|
314
|
+
|
|
315
|
+
```js
|
|
316
|
+
...lint.betterTailwind({
|
|
317
|
+
entryPoint: './app/styles/tailwind.css',
|
|
318
|
+
ignore: ['plain-link', 'plain-table'],
|
|
319
|
+
}),
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
| Option | Type | Required | Description |
|
|
323
|
+
| ------------ | ---------- | -------- | -------------------------------------------------------------------------------------------- |
|
|
324
|
+
| `entryPoint` | `string` | yes | Path to your Tailwind entry CSS, used by the plugin to resolve the active class set. |
|
|
325
|
+
| `ignore` | `string[]` | no | Class names the plugin should ignore in `better-tailwindcss/no-unknown-classes` (e.g. design-system tokens, `plain-*` utility shims). |
|
|
326
|
+
|
|
327
|
+
## shadcn factory
|
|
328
|
+
|
|
329
|
+
`shadcn()` bundles [`@shadcn/lint`](https://github.com/shadcn-ui/lint) (an
|
|
330
|
+
exact-pinned dependency) so role tokens are the only color vocabulary, and
|
|
331
|
+
exempts the vendored shadcn ui files from house style. It is opt-in: omit it
|
|
332
|
+
and nothing shadcn-related loads.
|
|
333
|
+
|
|
334
|
+
```js
|
|
335
|
+
...lint.shadcn({ui: '~/components/ui'}), // the LAST entry, after ...lint.prettier
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
| Option | Type | Default | Description |
|
|
339
|
+
| ----------------- | ---------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
|
340
|
+
| `ui` | `string` | `'~/components/ui'` | Import alias of the vendored ui folder, written to the root-level `settings.shadcn.ui` (never a rule option). |
|
|
341
|
+
| `uiFiles` | `string[]` | `[`${sourceDir}/components/ui/*.tsx`]` plus the registry helpers | Globs of the vendored files: the ui folder plus the helpers `shadcn add` writes outside it (`hooks/use-mobile.ts`, `hooks/use-highlighted-code.ts`, `utils/highlighter.tsx`). Never matches `ui/tests/**`. |
|
|
342
|
+
| `restyleOffFiles` | `string[]` | `[]` | Fallback: globs outside ui where `shadcn/no-restyle` is off. Its block always ignores `${sourceDir}/components/ui/**`, so `ui/tests/**` stays covered. |
|
|
343
|
+
|
|
344
|
+
Blocks it returns:
|
|
345
|
+
|
|
346
|
+
- `shadcn/settings`: no `files`; registers the plugin and sets `settings.shadcn.ui`.
|
|
347
|
+
- `shadcn/rules`: source files. `shadcn/no-raw-colors`, `shadcn/require-static-classes`
|
|
348
|
+
and `shadcn/no-inline-styles` are `error`; `shadcn/no-restyle` is
|
|
349
|
+
`['error', {allow: ['layout']}]`. `shadcn/no-arbitrary-values` is `off`: an
|
|
350
|
+
arbitrary value is allowed where no scale step or token fits (`grid-cols-[auto_1fr]`),
|
|
351
|
+
and `better-tailwindcss/enforce-canonical-classes` (with `rootFontSize: 16`)
|
|
352
|
+
rewrites one that has a scale equivalent (`w-[16px]` to `w-4`). An arbitrary
|
|
353
|
+
color (hex, a CSS color function, a `color:` hint) is an error through
|
|
354
|
+
`better-tailwindcss/no-restricted-classes`, since colors are role tokens.
|
|
355
|
+
`shadcn/no-unknown-classes` is `off` because `better-tailwindcss/no-unknown-classes` (from `betterTailwind`)
|
|
356
|
+
stays the only unknown-class rule. A marker class a library applies, such as
|
|
357
|
+
sonner's `toaster`, is cleared through `betterTailwind({ignore: ['toaster']})`.
|
|
358
|
+
- `shadcn/vendored-ui`: the `uiFiles` only. See below.
|
|
359
|
+
- `shadcn/restyle-fallback`: only when `restyleOffFiles` is non-empty.
|
|
360
|
+
|
|
361
|
+
**Ordering.** The vendored-ui block turns off rules owned by plugins the other
|
|
362
|
+
GAIA blocks register (prettier, prefer-arrow-functions, perfectionist, unicorn,
|
|
363
|
+
better-tailwindcss, and more), so `shadcn()` assumes the full GAIA composition
|
|
364
|
+
is spread before it. Spread it last, after `...lint.prettier`, so its
|
|
365
|
+
`prettier/prettier: off` wins on vendored files.
|
|
366
|
+
|
|
367
|
+
### Vendored ui policy
|
|
368
|
+
|
|
369
|
+
Files in `components/ui/*.tsx`, and the helpers the registry writes outside
|
|
370
|
+
that folder, are registry output kept byte-identical to `shadcn add`. The list
|
|
371
|
+
of rules off for them covers the full shadcn registry: every rule that fires on
|
|
372
|
+
unedited `shadcn add --all` output. Prettier and the house-style rules are off,
|
|
373
|
+
so lint never rewrites a vendored file, and so are the correctness-class rules
|
|
374
|
+
the shadcn source itself trips, each commented in `src/configs/shadcn.ts` with
|
|
375
|
+
the stock file it covers. `jsx-a11y/anchor-has-content` is one of them:
|
|
376
|
+
`PaginationLink` passes its anchor content through spread `children`, which the
|
|
377
|
+
rule cannot see.
|
|
378
|
+
|
|
379
|
+
Everything else stays on in vendored ui: `shadcn/no-raw-colors`,
|
|
380
|
+
`react-hooks/rules-of-hooks`, `react-hooks/exhaustive-deps`, and every other
|
|
381
|
+
correctness rule. `components/ui/tests/**` is GAIA-authored and stays fully
|
|
382
|
+
linted, and so does any hook or util beside the registry helpers. If a later
|
|
383
|
+
registry item trips a rule not in the list, extend the block rather than
|
|
384
|
+
editing the vendored file.
|
|
385
|
+
|
|
386
|
+
## `FC` and `FunctionComponent` are banned
|
|
387
|
+
|
|
388
|
+
Importing `FC` or `FunctionComponent` from `'react'` is an error everywhere,
|
|
389
|
+
including test and story files (a core `no-restricted-imports` entry in the
|
|
390
|
+
shared path list). Type props inline instead:
|
|
391
|
+
|
|
392
|
+
```tsx
|
|
393
|
+
type ButtonProps = {label: string};
|
|
394
|
+
|
|
395
|
+
const Button = ({label}: ButtonProps) => <button>{label}</button>;
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
## Ignores factory
|
|
399
|
+
|
|
400
|
+
`ignores` produces a leading flat-config block that merges your
|
|
401
|
+
`.gitignore` plus GAIA defaults. `.gitignore` is picked up automatically
|
|
402
|
+
if it exists at the project root; no need to declare it.
|
|
403
|
+
|
|
404
|
+
`lint.ignores` is dual-shape: spread it directly for the default case
|
|
405
|
+
(no call), or call it with options to override.
|
|
406
|
+
|
|
407
|
+
```js
|
|
408
|
+
...lint.ignores, // default: auto .gitignore + GAIA defaults
|
|
409
|
+
...lint.ignores({extra: ['coverage/**']}), // + extra globs
|
|
410
|
+
...lint.ignores({gitignore: 'config/.gitignore'}), // override the path
|
|
411
|
+
...lint.ignores({gitignore: false}), // opt out of the merge
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
| Option | Type | Required | Description |
|
|
415
|
+
| ---------- | ----------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
416
|
+
| `gitignore`| `string \| false` | no | Path to a `.gitignore` file (relative to `cwd` or absolute). Defaults to `'.gitignore'`. Silently skipped if the resolved path does not exist. Pass `false` to opt out entirely. |
|
|
417
|
+
| `extra` | `string[]` | no | Extra ignore globs merged with GAIA defaults. |
|
|
418
|
+
|
|
419
|
+
## GAIA folder conventions baked into `check-file`
|
|
420
|
+
|
|
421
|
+
The `check-file` rules in `styleHygiene` encode GAIA's folder layout (with
|
|
422
|
+
`sourceDir` substituted for the literal `app/` prefix). Every folder and file
|
|
423
|
+
name is kebab-case:
|
|
424
|
+
|
|
425
|
+
```
|
|
426
|
+
<sourceDir>/
|
|
427
|
+
components/
|
|
428
|
+
ui/ flat kebab-case files (button.tsx); tests/ is the only subfolder
|
|
429
|
+
<name>/index.tsx one folder per component, default export in PascalCase
|
|
430
|
+
tests/ index.stories.tsx, index.test.tsx
|
|
431
|
+
hooks/ use-<name>.ts
|
|
432
|
+
<sub-name>/index.tsx nested component
|
|
433
|
+
pages/
|
|
434
|
+
<route path>/page.tsx route page, default export <Name>Page
|
|
435
|
+
tests/ page.stories.tsx, page.test.tsx
|
|
436
|
+
<name>/index.tsx component used only by this page
|
|
437
|
+
hooks/
|
|
438
|
+
use-<name>.ts camelCase export (useTheme)
|
|
439
|
+
tests/use-<name>.test.ts
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
- `<sourceDir>/components/**`: kebab-case folders; component files are named
|
|
443
|
+
`index.tsx`, except the flat `components/ui/` files; no component file sits
|
|
444
|
+
directly in `components/`
|
|
445
|
+
- `<sourceDir>/pages/**`: kebab-case folders; a `.tsx` file is `page.tsx` or
|
|
446
|
+
`index.tsx`
|
|
447
|
+
- `**/hooks/*`: hook files are kebab-case with a `use-` prefix (`use-*.ts`)
|
|
448
|
+
- `assets/`, `hooks/`, `state/`, `tests/`, and `utils/` are the reserved
|
|
449
|
+
subfolders of a component or page folder; files in them are kebab-case
|
|
450
|
+
- `test/**`: test harness naming
|
|
451
|
+
|
|
452
|
+
`canonical/filename-match-exported` compares a component or page file's
|
|
453
|
+
default export against its kebab-case folder (`theme-switch/index.tsx` exports
|
|
454
|
+
`ThemeSwitch`). Outside `components/` and `pages/` it keeps exact matching, so
|
|
455
|
+
`i18n.ts` exports `i18n`. It is off for `pages/**/page.tsx`, stories, tests,
|
|
456
|
+
routes, and hook files.
|
|
457
|
+
|
|
458
|
+
For most non-GAIA layouts, passing `sourceDir` to the factory is enough:
|
|
459
|
+
|
|
460
|
+
```js
|
|
461
|
+
const lint = gaiaLint({sourceDir: 'src'});
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
If your project uses a different layout (for example, a non-GAIA project
|
|
465
|
+
that names component files in PascalCase, `Button.tsx`, instead of GAIA's
|
|
466
|
+
kebab-case folders with `index.tsx`), override the relevant `check-file/*` rules **after** the
|
|
467
|
+
`styleHygiene` spread:
|
|
468
|
+
|
|
469
|
+
```js
|
|
470
|
+
const lint = gaiaLint({sourceDir: 'src'});
|
|
471
|
+
|
|
472
|
+
export default defineConfig([
|
|
473
|
+
...lint.base,
|
|
474
|
+
...lint.styleHygiene,
|
|
475
|
+
{
|
|
476
|
+
files: ['src/components/**'],
|
|
477
|
+
rules: {
|
|
478
|
+
'check-file/filename-naming-convention': [
|
|
479
|
+
'error',
|
|
480
|
+
{'src/components/**/*.{ts,tsx}': 'PASCAL_CASE'},
|
|
481
|
+
],
|
|
482
|
+
},
|
|
483
|
+
},
|
|
484
|
+
]);
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
Or disable the GAIA `check-file` block entirely and reapply your own:
|
|
488
|
+
|
|
489
|
+
```js
|
|
490
|
+
{rules: {'check-file/folder-naming-convention': 'off'}}
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
## Versioning policy
|
|
494
|
+
|
|
495
|
+
This package follows SemVer.
|
|
496
|
+
|
|
497
|
+
- **Patch.** Plugin version bumps that do not change rule defaults, internal
|
|
498
|
+
refactors, README fixes.
|
|
499
|
+
- **Minor.** New rules added, new options exposed on factories, new named
|
|
500
|
+
exports, opt-in changes that do not break existing consumer configs.
|
|
501
|
+
- **Major.** Engine swaps (ESLint → Biome), `eslint` major version bumps,
|
|
502
|
+
removal/rename of named exports, default-rule changes that introduce new
|
|
503
|
+
errors in previously-clean code.
|
|
504
|
+
|
|
505
|
+
## Prereleases
|
|
506
|
+
|
|
507
|
+
3.0.0 ships first as `3.0.0-rc.N` on the `rc` dist-tag, for GAIA 2.0. Install
|
|
508
|
+
it with `pnpm add -D @gaia-harness/lint@rc`. The `latest` dist-tag stays on 2.x
|
|
509
|
+
until GAIA 2.0.0 ships. The Release workflow publishes from `main` only, so a
|
|
510
|
+
2.x hotfix is cut and published manually by the maintainer from the
|
|
511
|
+
`release/2.x` branch.
|
|
512
|
+
|
|
513
|
+
## License
|
|
514
|
+
|
|
515
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/configs/base.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAS,MAAM,EAAC,MAAM,QAAQ,CAAC;AA+Y3C,eAAO,MAAM,SAAS,GAAI,WAAW,MAAM,KAAG,MAAM,CAAC,MAAM,EAY1D,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Linter } from 'eslint';
|
|
2
|
+
export type GaiaLintBetterTailwindOptions = {
|
|
3
|
+
/** Path to the Tailwind entry CSS file (e.g. './app/styles/tailwind.css'). */
|
|
4
|
+
entryPoint: string;
|
|
5
|
+
/** Class names to ignore in `better-tailwindcss/no-unknown-classes`. */
|
|
6
|
+
ignore?: string[];
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Better-Tailwind flat-config factory.
|
|
10
|
+
*
|
|
11
|
+
* Ports `betterTailwindConfig` from GAIA's `eslint.config.mjs`. The
|
|
12
|
+
* `entryPoint` (consumer's Tailwind CSS entry) and `ignore` list are
|
|
13
|
+
* project-specific, so this is shipped as a factory rather than a static
|
|
14
|
+
* array.
|
|
15
|
+
*/
|
|
16
|
+
export declare const betterTailwind: (opts: GaiaLintBetterTailwindOptions) => Linter.Config[];
|
|
17
|
+
//# sourceMappingURL=better-tailwind.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"better-tailwind.d.ts","sourceRoot":"","sources":["../../src/configs/better-tailwind.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,QAAQ,CAAC;AAEnC,MAAM,MAAM,6BAA6B,GAAG;IAC1C,8EAA8E;IAC9E,UAAU,EAAE,MAAM,CAAC;IACnB,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GACzB,MAAM,6BAA6B,KAClC,MAAM,CAAC,MAAM,EA8Bf,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guardrails.d.ts","sourceRoot":"","sources":["../../src/configs/guardrails.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,QAAQ,CAAC;AAsRnC,eAAO,MAAM,eAAe,GAAI,WAAW,MAAM,KAAG,MAAM,CAAC,MAAM,EAWhE,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Linter } from 'eslint';
|
|
2
|
+
/**
|
|
3
|
+
* i18n flat-config block (opt-in), for projects that translate their UI.
|
|
4
|
+
*
|
|
5
|
+
* `i18next/no-literal-string` in `jsx-text-only` mode reports raw text between
|
|
6
|
+
* JSX tags (`<p>Hello</p>`), which should come from `t()`. Attributes and
|
|
7
|
+
* plain string literals are not checked: `jsx-only` mode flags `data-slot`,
|
|
8
|
+
* `htmlFor`, `value` and the like, which are not UI copy.
|
|
9
|
+
*
|
|
10
|
+
* Stories, tests, `tests/` helpers and the vendored shadcn ui files are
|
|
11
|
+
* exempt. Text that must stay untranslated (an error boundary that renders
|
|
12
|
+
* without i18n) takes an inline disable with a reason.
|
|
13
|
+
*
|
|
14
|
+
* A project that drops i18n removes `...lint.i18n` from its config.
|
|
15
|
+
*/
|
|
16
|
+
export declare const buildI18n: (sourceDir: string) => Linter.Config[];
|
|
17
|
+
//# sourceMappingURL=i18n.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../src/configs/i18n.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,QAAQ,CAAC;AAEnC;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,SAAS,GAAI,WAAW,MAAM,KAAG,MAAM,CAAC,MAAM,EAe1D,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Linter } from 'eslint';
|
|
2
|
+
export type GaiaLintIgnoresOptions = {
|
|
3
|
+
/**
|
|
4
|
+
* Path to a `.gitignore` file to merge in. Resolved from `process.cwd()`
|
|
5
|
+
* if relative. Pass `false` to skip the gitignore merge entirely.
|
|
6
|
+
*
|
|
7
|
+
* If the resolved path does not exist, the merge is silently skipped —
|
|
8
|
+
* projects without a `.gitignore` don't need to opt out explicitly.
|
|
9
|
+
*
|
|
10
|
+
* @default '.gitignore'
|
|
11
|
+
*/
|
|
12
|
+
gitignore?: string | false;
|
|
13
|
+
/** Extra ignore globs to merge with GAIA defaults. */
|
|
14
|
+
extra?: string[];
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Ignores flat-config factory.
|
|
18
|
+
*
|
|
19
|
+
* Ports the `includeIgnoreFile(gitignorePath)` + static `ignored-files`
|
|
20
|
+
* block from GAIA's `eslint.config.mjs`. The `gitignore` path must be
|
|
21
|
+
* resolved at the consumer's cwd (config-load time), not at gaia-lint's
|
|
22
|
+
* install location, so this is shipped as a factory.
|
|
23
|
+
*/
|
|
24
|
+
export declare const ignores: (opts?: GaiaLintIgnoresOptions) => Linter.Config[];
|
|
25
|
+
//# sourceMappingURL=ignores.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ignores.d.ts","sourceRoot":"","sources":["../../src/configs/ignores.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,QAAQ,CAAC;AAInC,MAAM,MAAM,sBAAsB,GAAG;IACnC;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC3B,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAyBF;;;;;;;GAOG;AACH,eAAO,MAAM,OAAO,GAAI,OAAO,sBAAsB,KAAG,MAAM,CAAC,MAAM,EAmBpE,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Linter } from 'eslint';
|
|
2
|
+
/**
|
|
3
|
+
* Playwright flat-config block.
|
|
4
|
+
*
|
|
5
|
+
* Ports `playwrightConfig` from GAIA's `eslint.config.mjs` — scopes
|
|
6
|
+
* `eslint-plugin-playwright`'s `flat/recommended` config to `.playwright/`
|
|
7
|
+
* test files (GAIA's e2e directory convention).
|
|
8
|
+
*/
|
|
9
|
+
export declare const playwright: Linter.Config[];
|
|
10
|
+
//# sourceMappingURL=playwright.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playwright.d.ts","sourceRoot":"","sources":["../../src/configs/playwright.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,QAAQ,CAAC;AAEnC;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAsBrC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Linter } from 'eslint';
|
|
2
|
+
/**
|
|
3
|
+
* Prettier flat-config block.
|
|
4
|
+
*
|
|
5
|
+
* Ports `prettierConfig` from GAIA's `eslint.config.mjs`. Layers
|
|
6
|
+
* `eslint-config-prettier`'s rule disablers, then re-enables a few
|
|
7
|
+
* `@stylistic/*` rules GAIA wants to keep (padding lines, single quotes),
|
|
8
|
+
* and finally turns on the `prettier/prettier` rule itself.
|
|
9
|
+
*/
|
|
10
|
+
export declare const prettier: Linter.Config[];
|
|
11
|
+
//# sourceMappingURL=prettier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prettier.d.ts","sourceRoot":"","sources":["../../src/configs/prettier.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,QAAQ,CAAC;AAEnC;;;;;;;GAOG;AACH,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EA6BnC,CAAC"}
|