@polariens/kitsune-lint 1.0.0-rc.10

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/README.md ADDED
@@ -0,0 +1,268 @@
1
+ # @polariens/kitsune-lint 🦊
2
+
3
+ Opinionated ESLint & Prettier configs for high-quality Vue, TypeScript & Vitest projects.
4
+
5
+ > **Kitsune** (狐) é a raposa mística do folclore japonês — astuta, adaptável e capaz de se transformar conforme o contexto. Assim como a kitsune, este pacote se molda ao seu projeto: você escolhe os módulos e as opções, e ele compõe as regras certas para cada cenário. Código limpo com a precisão de uma raposa.
6
+
7
+ ## O que é
8
+
9
+ Um pacote instalável que padroniza regras de linting e formatação entre múltiplos projetos. As configurações são **modulares** — cada conjunto de regras (TypeScript, Vue, Pinia, segurança, etc.) é independente e configurável via opções.
10
+
11
+ ## Como usar
12
+
13
+ ### Instalação
14
+
15
+ Primeiro, instale o pacote principal em seu projeto como dependência de desenvolvimento:
16
+
17
+ ```bash
18
+ npm install --save-dev @polariens/kitsune-lint
19
+ ```
20
+
21
+ As _peer dependencies_ correspondentes devem ser instaladas no projeto consumidor. Veja abaixo as opções de instalação dependendo do seu cenário.
22
+
23
+ #### Instalação Completa (Todos os módulos)
24
+
25
+ Se você planeja utilizar a configuração máxima com todos os módulos ativados no seu ecossistema (`security`, `cleanCode`, `pinia`, `vitest`, `typescript` e `vue`), execute este comando para instalar todas as ferramentas de uma vez:
26
+
27
+ ```bash
28
+ npm install --save-dev eslint @eslint/js typescript-eslint globals eslint-plugin-security eslint-plugin-vue vue-eslint-parser eslint-plugin-pinia @vitest/eslint-plugin
29
+ ```
30
+
31
+ #### Instalação Específica (Por módulo)
32
+
33
+ Se preferir incluir apenas as peças que for usar, você deve sempre iniciar instalando as **Dependências Base**, que são essenciais para os módulos principais (que já vêm ativos por padrão, como `base`, `cleanCode` e `typescript`):
34
+
35
+ ```bash
36
+ npm install --save-dev eslint @eslint/js typescript-eslint globals
37
+ ```
38
+
39
+ Em seguida, instale os complementos exclusivos para cada módulo extra que for habilitar em seu `createKitsuneConfig()`:
40
+
41
+ **Módulo `security` (Habilitado por padrão)**
42
+ Necessário para a suíte de regras focadas em prevenir vulnerabilidades de segurança e injeções de código:
43
+ ```bash
44
+ npm install --save-dev eslint-plugin-security
45
+ ```
46
+
47
+ **Módulo `vue`**
48
+ Pacotes necessários para realizar o lint na sintaxe `<template>`, `script setup` e validar as regras do Vue 3:
49
+ ```bash
50
+ npm install --save-dev eslint-plugin-vue vue-eslint-parser
51
+ ```
52
+ > *(Exemplo prático de setup em um projeto para uso apenas dos essenciais e módulo Vue:)*
53
+ > ```bash
54
+ > npm install --save-dev eslint @eslint/js typescript-eslint globals eslint-plugin-vue vue-eslint-parser
55
+ > ```
56
+
57
+ **Módulo `pinia`**
58
+ O verificador de store e regras recomendadas para o gerenciamento de estado via Pinia:
59
+ ```bash
60
+ npm install --save-dev eslint-plugin-pinia
61
+ ```
62
+
63
+ **Módulo `vitest`**
64
+ Para linting focado em arquivos de teste especificados nativamente pelas boas práticas do Vitest:
65
+ ```bash
66
+ npm install --save-dev @vitest/eslint-plugin
67
+ ```
68
+
69
+ ### ESLint — Factory function (recomendado)
70
+
71
+ A forma mais simples. O `createKitsuneConfig` compõe os módulos selecionados:
72
+
73
+ ```javascript
74
+ // eslint.config.js
75
+ import { createKitsuneConfig } from '@polariens/kitsune-lint/eslint';
76
+
77
+ export default await createKitsuneConfig({
78
+ vue: true,
79
+ pinia: true,
80
+ tests: true,
81
+ vitest: true,
82
+ });
83
+ ```
84
+
85
+ Por padrão, `base`, `typescript`, `security` e `cleanCode` já vêm habilitados. Passe `false` para desativar:
86
+
87
+ ```javascript
88
+ export default await createKitsuneConfig({
89
+ security: false,
90
+ vue: true,
91
+ });
92
+ ```
93
+
94
+ ### ESLint — Customizando módulos
95
+
96
+ Cada módulo aceita um objeto de opções no lugar de `true`:
97
+
98
+ ```javascript
99
+ export default await createKitsuneConfig({
100
+ base: { environment: 'node' },
101
+ cleanCode: { maxDepth: 3, maxParams: 3, complexity: 10, maxLines: 300 },
102
+ vue: { apiStyle: 'composition' },
103
+ pinia: true,
104
+ vitest: {
105
+ titlePattern: '^should .+',
106
+ titleMessage: 'Test title must start with "should"',
107
+ fn: 'it',
108
+ maxNestedDescribe: 2,
109
+ },
110
+ });
111
+ ```
112
+
113
+ ### ESLint — Imports granulares
114
+
115
+ Para controle total, importe cada módulo diretamente:
116
+
117
+ ```javascript
118
+ // eslint.config.js
119
+ import { base } from '@polariens/kitsune-lint/eslint/base';
120
+ import { typescript } from '@polariens/kitsune-lint/eslint/typescript';
121
+ import { vue } from '@polariens/kitsune-lint/eslint/vue';
122
+ import { pinia } from '@polariens/kitsune-lint/eslint/pinia';
123
+
124
+ export default [
125
+ ...base(),
126
+ ...typescript(),
127
+ ...vue(),
128
+ ...(await pinia()),
129
+ ];
130
+ ```
131
+
132
+ ### ESLint — Estendendo com configs extras
133
+
134
+ Use `extend` para adicionar configs de plugins externos (ex: `eslint-config-prettier`):
135
+
136
+ ```javascript
137
+ import { createKitsuneConfig } from '@polariens/kitsune-lint/eslint';
138
+ import eslintConfigPrettier from 'eslint-config-prettier';
139
+ import pluginVue from 'eslint-plugin-vue';
140
+
141
+ export default await createKitsuneConfig({
142
+ vue: true,
143
+ pinia: true,
144
+ tests: true,
145
+ vitest: true,
146
+ extend: [
147
+ ...pluginVue.configs['flat/recommended'],
148
+ eslintConfigPrettier,
149
+ ],
150
+ });
151
+ ```
152
+
153
+ ### Prettier
154
+
155
+ Uso direto da config padrão:
156
+
157
+ ```javascript
158
+ // prettier.config.mjs
159
+ import { prettierConfig } from '@polariens/kitsune-lint/prettier';
160
+ export default prettierConfig;
161
+ ```
162
+
163
+ Com overrides:
164
+
165
+ ```javascript
166
+ import { createPrettierConfig } from '@polariens/kitsune-lint/prettier';
167
+ export default createPrettierConfig({ printWidth: 120 });
168
+ ```
169
+
170
+ ## Módulos
171
+
172
+ | Módulo | Default | Descrição |
173
+ | ------------ | ------- | ------------------------------------------------------------ |
174
+ | `base` | ✅ on | Globals do ambiente (browser/node) |
175
+ | `typescript` | ✅ on | Regras TS recomendadas + naming conventions |
176
+ | `security` | ✅ on | Prevenção de eval, XSS, injection + eslint-plugin-security |
177
+ | `cleanCode` | ✅ on | SRP, legibilidade, imutabilidade, organização |
178
+ | `vue` | ❌ off | Vue 3 + script setup + type-based props/emits |
179
+ | `pinia` | ❌ off | Stores Pinia — naming, organização, boas práticas |
180
+ | `tests` | ❌ off | Relaxamentos para arquivos de teste (desliga regras rígidas) |
181
+ | `vitest` | ❌ off | Regras do plugin Vitest (naming, hooks, describe) |
182
+
183
+ ## Opções dos módulos
184
+
185
+ ### base
186
+
187
+ | Opção | Padrão | Descrição |
188
+ | ------------- | ----------- | ------------------------------------------------ |
189
+ | `environment` | `'browser'` | Globals: `browser`, `node`, `shared-node-browser`|
190
+
191
+ ### typescript
192
+
193
+ | Opção | Padrão | Descrição |
194
+ | -------- | -------------- | ------------------ |
195
+ | `ignores`| configs + dist | Patterns a ignorar |
196
+ | `rules` | `{}` | Regras extras |
197
+
198
+ ### security
199
+
200
+ | Opção | Padrão | Descrição |
201
+ | --------------- | ------ | ----------------------------- |
202
+ | `pluginEnabled` | `true` | Usar `eslint-plugin-security` |
203
+ | `rules` | `{}` | Regras extras |
204
+
205
+ ### cleanCode
206
+
207
+ | Opção | Padrão | Descrição |
208
+ | --------------------- | ------ | ---------------------------------- |
209
+ | `maxDepth` | `4` | Profundidade máxima de aninhamento |
210
+ | `maxParams` | `4` | Parâmetros máximos por função |
211
+ | `complexity` | `14` | Complexidade ciclomática máxima |
212
+ | `maxLines` | `400` | Linhas máximas por arquivo |
213
+ | `maxLinesPerFunction` | `80` | Linhas máximas por função |
214
+ | `rules` | `{}` | Regras extras |
215
+
216
+ ### vue
217
+
218
+ | Opção | Padrão | Descrição |
219
+ | ---------- | ---------------- | ------------------- |
220
+ | `apiStyle` | `'script-setup'` | Estilo de API Vue |
221
+ | `rules` | `{}` | Regras extras |
222
+
223
+ ### pinia
224
+
225
+ | Opção | Padrão | Descrição |
226
+ | ------- | ------------------------- | ------------------------------- |
227
+ | `files` | `['src/state/**/*.ts']` | Override dos file patterns |
228
+ | `rules` | `{}` | Regras extras |
229
+
230
+ ### tests
231
+
232
+ Relaxamentos para arquivos de teste — desliga regras rígidas de produção como `complexity`, `max-lines`, `max-lines-per-function`, `no-explicit-any`, `naming-convention`, etc.
233
+
234
+ | Opção | Padrão | Descrição |
235
+ | ------- | ------------------------------- | -------------------------- |
236
+ | `files` | `['tests/**/*.{js,mjs,cjs,ts}']`| Override dos file patterns |
237
+ | `rules` | `{}` | Regras extras |
238
+
239
+ ### vitest
240
+
241
+ | Opção | Padrão | Descrição |
242
+ | ------------------ | -------------- | -------------------------------- |
243
+ | `fn` | `'test'` | `test()` ou `it()` |
244
+ | `titlePattern` | Gherkin PT-BR | Regex do título dos testes |
245
+ | `titleMessage` | mensagem PT-BR | Mensagem de erro |
246
+ | `maxNestedDescribe`| `3` | Máximo de describe aninhados |
247
+ | `rules` | `{}` | Regras extras |
248
+
249
+ ## Estrutura
250
+
251
+ ```
252
+ @polariens/kitsune-lint/
253
+ ├── package.json
254
+ ├── eslint/
255
+ │ ├── index.mjs # Factory createKitsuneConfig + re-exports
256
+ │ ├── utils.mjs # Patterns de arquivos compartilhados
257
+ │ └── configs/
258
+ │ ├── base.mjs # Globals do ambiente (browser/node)
259
+ │ ├── typescript.mjs # Regras TypeScript + naming conventions
260
+ │ ├── security.mjs # Prevenção de eval, XSS, injection
261
+ │ ├── clean-code.mjs # SRP, legibilidade, imutabilidade
262
+ │ ├── vue.mjs # Vue 3 + script setup
263
+ │ ├── pinia.mjs # Stores Pinia
264
+ │ ├── tests.mjs # Relaxamentos para testes
265
+ │ └── vitest.mjs # Regras plugin Vitest
266
+ └── prettier/
267
+ └── index.mjs # Config Prettier exportável
268
+ ```
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { cpSync, existsSync, readFileSync } from 'node:fs';
4
+ import { dirname, join, resolve } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
8
+ const source = resolve(__dirname, '..', 'prettier', '.prettierignore');
9
+ const dest = resolve(process.cwd(), '.prettierignore');
10
+
11
+ const force = process.argv.includes('--force');
12
+
13
+ if (existsSync(dest) && !force) {
14
+ const existing = readFileSync(dest, 'utf-8');
15
+ const template = readFileSync(source, 'utf-8');
16
+
17
+ if (existing === template) {
18
+ console.info('[lint-config] .prettierignore já está atualizado.');
19
+ process.exit(0);
20
+ }
21
+
22
+ console.error(
23
+ '[lint-config] .prettierignore já existe e difere do template.\n' +
24
+ ' Use --force para sobrescrever.'
25
+ );
26
+ process.exit(1);
27
+ }
28
+
29
+ cpSync(source, dest);
30
+ console.info(`[lint-config] .prettierignore copiado para ${dest}`);
@@ -0,0 +1,10 @@
1
+ import type { Linter } from 'eslint';
2
+
3
+ export interface BaseOptions {
4
+ /** File patterns override */
5
+ files?: string[];
6
+ /** Ambiente de globals a aplicar @default 'browser' */
7
+ environment?: 'browser' | 'node' | 'shared-node-browser' | 'worker' | 'serviceworker';
8
+ }
9
+
10
+ export declare function base(options?: BaseOptions): Linter.Config[];
@@ -0,0 +1,28 @@
1
+ import globals from 'globals';
2
+
3
+ import { resolveFiles } from '../utils.mjs';
4
+
5
+ /**
6
+ * @typedef {Object} BaseOptions
7
+ * @property {string[]} [files] - File patterns override
8
+ * @property {'browser' | 'node' | 'shared-node-browser'} [environment='browser'] - Ambiente global
9
+ */
10
+
11
+ /**
12
+ * Configuração base com globals do ambiente.
13
+ * @param {BaseOptions} [options={}]
14
+ * @returns {import('eslint').Linter.Config[]}
15
+ */
16
+ export function base(options = {}) {
17
+ const { files, environment = 'browser' } = options;
18
+
19
+ return [
20
+ {
21
+ files: resolveFiles('all', files),
22
+ name: '@kitsune/base/globals',
23
+ languageOptions: {
24
+ globals: globals[environment],
25
+ },
26
+ },
27
+ ];
28
+ }
@@ -0,0 +1,20 @@
1
+ import type { Linter } from 'eslint';
2
+
3
+ export interface CleanCodeOptions {
4
+ /** File patterns override */
5
+ files?: string[];
6
+ /** Profundidade máxima de aninhamento @default 4 */
7
+ maxDepth?: number;
8
+ /** Número máximo de parâmetros por função @default 4 */
9
+ maxParams?: number;
10
+ /** Complexidade ciclomática máxima @default 14 */
11
+ complexity?: number;
12
+ /** Linhas máximas por arquivo @default 400 */
13
+ maxLines?: number;
14
+ /** Linhas máximas por função @default 80 */
15
+ maxLinesPerFunction?: number;
16
+ /** Regras adicionais ou overrides */
17
+ rules?: Partial<Linter.RulesRecord>;
18
+ }
19
+
20
+ export declare function cleanCode(options?: CleanCodeOptions): Linter.Config[];
@@ -0,0 +1,102 @@
1
+ import { resolveFiles } from '../utils.mjs';
2
+
3
+ /**
4
+ * @typedef {Object} CleanCodeOptions
5
+ * @property {string[]} [files] - File patterns override
6
+ * @property {number} [maxDepth=4] - Profundidade máxima de aninhamento
7
+ * @property {number} [maxParams=4] - Número máximo de parâmetros
8
+ * @property {number} [complexity=14] - Complexidade ciclomática máxima
9
+ * @property {number} [maxLines=400] - Linhas máximas por arquivo
10
+ * @property {number} [maxLinesPerFunction=80] - Linhas máximas por função
11
+ * @property {Record<string, unknown>} [rules] - Regras adicionais ou overrides
12
+ */
13
+
14
+ /**
15
+ * Regras de clean code para legibilidade e manutenibilidade.
16
+ * @param {CleanCodeOptions} [options={}]
17
+ * @returns {import('eslint').Linter.Config[]}
18
+ */
19
+ export function cleanCode(options = {}) {
20
+ const {
21
+ files,
22
+ maxDepth = 4,
23
+ maxParams = 4,
24
+ complexity: maxComplexity = 14,
25
+ maxLines = 400,
26
+ maxLinesPerFunction = 80,
27
+ rules: extraRules = {},
28
+ } = options;
29
+
30
+ const resolvedFiles = resolveFiles('all', files);
31
+
32
+ return [
33
+ {
34
+ files: resolvedFiles,
35
+ name: '@kitsune/clean-code/rules',
36
+ rules: {
37
+ // --- Single Responsibility (SRP) ---
38
+ complexity: ['warn', maxComplexity],
39
+ 'max-lines': ['warn', { max: maxLines, skipBlankLines: true, skipComments: true }],
40
+ 'max-lines-per-function': ['warn', { max: maxLinesPerFunction, skipBlankLines: true, skipComments: true }],
41
+ 'max-depth': ['error', maxDepth],
42
+ 'max-params': ['error', maxParams],
43
+
44
+ // --- Readability & Expressiveness ---
45
+ 'no-negated-condition': 'error',
46
+ 'no-nested-ternary': 'error',
47
+ 'no-unneeded-ternary': 'error',
48
+ 'no-else-return': 'error',
49
+ 'no-lonely-if': 'error',
50
+ 'prefer-template': 'error',
51
+ 'object-shorthand': 'error',
52
+ curly: ['error', 'all'],
53
+ 'arrow-body-style': ['error', 'as-needed'],
54
+ 'no-multi-assign': 'error',
55
+ 'no-unreachable-loop': 'error',
56
+ 'no-unused-labels': 'error',
57
+
58
+ // --- Immutability & Safety ---
59
+ 'no-param-reassign': ['error', { props: false }],
60
+ 'no-return-assign': ['error', 'always'],
61
+ 'no-sequences': 'error',
62
+ 'no-constructor-return': 'error',
63
+ 'no-promise-executor-return': 'error',
64
+ // Evita modificação de built-ins
65
+ 'no-extend-native': 'error',
66
+
67
+ // --- Code Organization ---
68
+ 'default-case-last': 'error',
69
+ 'grouped-accessor-pairs': ['error', 'getBeforeSet'],
70
+ 'max-statements': ['error', 20],
71
+
72
+ // --- Bug Prevention ---
73
+ 'no-template-curly-in-string': 'warn',
74
+ 'no-useless-return': 'error',
75
+
76
+ ...extraRules,
77
+ },
78
+ },
79
+ {
80
+ /**
81
+ * Regra personalizada para composables e stores pinia que por padrão podem ter mais linhas
82
+ * devido aos exports e variáveis de estado ref/computed.
83
+ * Padrão de arquivos: iniciando com `use`
84
+ */
85
+ files: resolvedFiles.map((pattern) => {
86
+ const parts = pattern.split('/');
87
+ const lastPart = parts[parts.length - 1];
88
+ if (lastPart.includes('*')) {
89
+ parts[parts.length - 1] = lastPart.replace('*', 'use*');
90
+ }
91
+ return parts.join('/');
92
+ }),
93
+ name: '@kitsune/clean-code/use-rules',
94
+ rules: {
95
+ 'max-lines-per-function': [
96
+ 'warn',
97
+ { max: Math.max(200, maxLinesPerFunction), skipBlankLines: true, skipComments: true },
98
+ ],
99
+ },
100
+ },
101
+ ];
102
+ }
@@ -0,0 +1,10 @@
1
+ import type { Linter } from 'eslint';
2
+
3
+ export interface PiniaOptions {
4
+ /** File patterns override @default ['src/state/**\/*.ts'] */
5
+ files?: string[];
6
+ /** Regras adicionais ou overrides */
7
+ rules?: Partial<Linter.RulesRecord>;
8
+ }
9
+
10
+ export declare function pinia(options?: PiniaOptions): Promise<Linter.Config[]>;
@@ -0,0 +1,36 @@
1
+ import { resolveFiles } from '../utils.mjs';
2
+
3
+ /**
4
+ * @typedef {Object} PiniaOptions
5
+ * @property {string[]} [files] - File patterns override (default: src/state/**\/*.ts)
6
+ * @property {Record<string, unknown>} [rules] - Regras adicionais ou overrides
7
+ */
8
+
9
+ /**
10
+ * Regras para stores Pinia — organização, naming e boas práticas.
11
+ * @param {PiniaOptions} [options={}]
12
+ * @returns {Promise<import('eslint').Linter.Config[]>}
13
+ */
14
+ export async function pinia(options = {}) {
15
+ const { files, rules: extraRules = {} } = options;
16
+
17
+ const pluginPinia = await import('eslint-plugin-pinia').then((m) => m.default ?? m);
18
+
19
+ return [
20
+ {
21
+ files: resolveFiles('pinia', files),
22
+ name: '@kitsune/pinia/rules',
23
+ plugins: { pinia: pluginPinia },
24
+ rules: {
25
+ 'pinia/never-export-initialized-store': 'error',
26
+ 'pinia/no-duplicate-store-ids': 'error',
27
+ 'pinia/no-return-global-properties': 'error',
28
+ 'pinia/no-store-to-refs-in-store': 'error',
29
+ 'pinia/prefer-single-store-per-file': 'warn',
30
+ 'pinia/prefer-use-store-naming-convention': 'warn',
31
+ 'pinia/require-setup-store-properties-export': 'warn',
32
+ ...extraRules,
33
+ },
34
+ },
35
+ ];
36
+ }
@@ -0,0 +1,12 @@
1
+ import type { Linter } from 'eslint';
2
+
3
+ export interface SecurityOptions {
4
+ /** File patterns override */
5
+ files?: string[];
6
+ /** Habilitar eslint-plugin-security @default true */
7
+ pluginEnabled?: boolean;
8
+ /** Regras adicionais ou overrides */
9
+ rules?: Partial<Linter.RulesRecord>;
10
+ }
11
+
12
+ export declare function security(options?: SecurityOptions): Linter.Config[];
@@ -0,0 +1,46 @@
1
+ import pluginSecurity from 'eslint-plugin-security';
2
+
3
+ import { resolveFiles } from '../utils.mjs';
4
+
5
+ /**
6
+ * @typedef {Object} SecurityOptions
7
+ * @property {string[]} [files] - File patterns override
8
+ * @property {boolean} [pluginEnabled=true] - Habilitar eslint-plugin-security
9
+ * @property {Record<string, unknown>} [rules] - Regras adicionais ou overrides
10
+ */
11
+
12
+ /**
13
+ * Regras de segurança para prevenir vulnerabilidades comuns.
14
+ * @param {SecurityOptions} [options={}]
15
+ * @returns {import('eslint').Linter.Config[]}
16
+ */
17
+ export function security(options = {}) {
18
+ const { files, pluginEnabled = true, rules: extraRules = {} } = options;
19
+ const resolvedFiles = resolveFiles('all', files);
20
+
21
+ const configs = []
22
+
23
+ if (pluginEnabled) {
24
+ configs.push({
25
+ ...pluginSecurity.configs.recommended,
26
+ files: resolvedFiles,
27
+ name: '@kitsune/security/plugin',
28
+ });
29
+ }
30
+
31
+ configs.push({
32
+ files: resolvedFiles,
33
+ name: '@kitsune/security/rules',
34
+ rules: {
35
+ 'no-alert': 'error',
36
+ 'no-eval': 'error',
37
+ 'no-debugger': 'error',
38
+ 'no-new-func': 'error',
39
+ 'no-script-url': 'error',
40
+ 'no-implied-eval': 'error',
41
+ ...extraRules,
42
+ },
43
+ })
44
+
45
+ return configs;
46
+ }
@@ -0,0 +1,10 @@
1
+ import type { Linter } from 'eslint';
2
+
3
+ export interface TestsOptions {
4
+ /** File patterns override */
5
+ files?: string[];
6
+ /** Regras adicionais ou overrides */
7
+ rules?: Partial<Linter.RulesRecord>;
8
+ }
9
+
10
+ export declare function tests(options?: TestsOptions): Linter.Config[];
@@ -0,0 +1,40 @@
1
+ import { resolveFiles } from '../utils.mjs';
2
+
3
+ /**
4
+ * @typedef {Object} TestsOptions
5
+ * @property {string[]} [files] - File patterns override
6
+ * @property {Record<string, unknown>} [rules] - Regras adicionais ou overrides
7
+ */
8
+
9
+ /**
10
+ * Relaxamentos para arquivos de teste — desliga regras rígidas de produção
11
+ * que atrapalham a escrita de testes (complexity, max-lines, naming, etc).
12
+ * @param {TestsOptions} [options={}]
13
+ * @returns {import('eslint').Linter.Config[]}
14
+ */
15
+ export function tests(options = {}) {
16
+ const { files, rules: extraRules = {} } = options;
17
+
18
+ return [
19
+ {
20
+ files: resolveFiles('tests', files),
21
+ name: '@kitsune/tests/relaxations',
22
+ rules: {
23
+ 'max-lines-per-function': 'off',
24
+ 'max-lines': 'off',
25
+ complexity: 'off',
26
+ '@typescript-eslint/no-shadow': 'off',
27
+ '@typescript-eslint/no-non-null-assertion': 'off',
28
+ '@typescript-eslint/no-explicit-any': 'off',
29
+ '@typescript-eslint/naming-convention': 'off',
30
+ 'no-promise-executor-return': 'off',
31
+ 'no-param-reassign': 'off',
32
+ 'no-constructor-return': 'off',
33
+ 'no-script-url': 'off',
34
+ 'security/detect-object-injection': 'off',
35
+ 'security/detect-unsafe-regex': 'off',
36
+ ...extraRules,
37
+ },
38
+ },
39
+ ];
40
+ }
@@ -0,0 +1,14 @@
1
+ import type { Linter } from 'eslint';
2
+
3
+ export interface TypescriptOptions {
4
+ /** File patterns override */
5
+ files?: string[];
6
+ /** Patterns a ignorar */
7
+ ignores?: string[];
8
+ /** Patterns a ignorar substituindo qualquer padrão do pacote */
9
+ replaceIgnores?: string[];
10
+ /** Regras adicionais ou overrides */
11
+ rules?: Partial<Linter.RulesRecord>;
12
+ }
13
+
14
+ export declare function typescript(options?: TypescriptOptions): Linter.Config[];