@hooshid/ox-config 1.0.0 → 1.0.2
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/lint.d.mts.map +1 -1
- package/dist/lint.mjs +49 -7
- package/dist/lint.mjs.map +1 -1
- package/package.json +1 -1
package/dist/lint.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lint.d.mts","names":[],"sources":["../src/utils.ts","../src/lint.ts"],"mappings":";;;qBAgDa;;qBAGA;;qBAGA;;qBAGA;;qBAGA;;qBAMA;;qBAGA;;;;;;;
|
|
1
|
+
{"version":3,"file":"lint.d.mts","names":[],"sources":["../src/utils.ts","../src/lint.ts"],"mappings":";;;qBAgDa;;qBAGA;;qBAGA;;qBAGA;;qBAGA;;qBAMA;;qBAGA;;;;;;;wBCuCG,KAAK,YAAY,QAAQ,gBAAgB;;;;;wBA6HzC,UAAU,YAAY,QAAQ,gBAAgB;;wBAa9C,QAAQ,YAAY,QAAQ,gBAAgB;;wBA2C5C,OAAO,YAAY,QAAQ,gBAAgB;;wBAwB3C,KAAK,YAAY,QAAQ,gBAAgB;;wBAazC,QAAQ,YAAY,QAAQ,gBAAgB;;wBAuE5C,MAAM,YAAY,QAAQ,gBAAgB;;wBAW1C,UAAU,YAAY,QAAQ,gBAAgB;;wBAe9C,OAAO,YAAY,QAAQ,gBAAgB;;;;;;;;;;;wBAc3C,eAAe,YAAY,QAAQ,gBAAgB;;;;;;;;;wBAsEnD,cAAc,YAAY,QAAQ,gBAAgB;;wBAkGlD,KAAK,YAAY,QAAQ,gBAAgB;;wBAKzC,MAAM,YAAY,QAAQ,gBAAgB;UAQhD,sBAAsB,QAAQ;;EAEtC;;;wBAIc,OAAO,UAAU,gBAAgB;UAkDvC,wBAAwB,QAAQ;EACxC;EACA;;EAEA;;;wBAIc,SAAS,UAAS,kBAAuB;;;;;wBA6BzC,OAAO,YAAY,QAAQ,gBAAgB;;wBA+B3C,QAAQ,YAAY,QAAQ,gBAAgB"}
|
package/dist/lint.mjs
CHANGED
|
@@ -74,6 +74,7 @@ const DEFAULT_IGNORES = [
|
|
|
74
74
|
"**/.hg/**",
|
|
75
75
|
"**/.pnp.*",
|
|
76
76
|
"**/public/**",
|
|
77
|
+
"**/routeTree.gen.ts",
|
|
77
78
|
"**/*.d.ts"
|
|
78
79
|
];
|
|
79
80
|
function loadGitignorePatterns() {
|
|
@@ -150,6 +151,8 @@ function base(overrides) {
|
|
|
150
151
|
"typescript/consistent-type-definitions": "off",
|
|
151
152
|
"typescript/consistent-type-imports": "error",
|
|
152
153
|
"no-unused-vars": "off",
|
|
154
|
+
"no-useless-rename": "error",
|
|
155
|
+
"uninvoked-array-callback": "error",
|
|
153
156
|
"typescript/array-type": "error",
|
|
154
157
|
"typescript/consistent-generic-constructors": "error",
|
|
155
158
|
"typescript/consistent-indexed-object-style": "error",
|
|
@@ -157,6 +160,10 @@ function base(overrides) {
|
|
|
157
160
|
"typescript/ban-tslint-comment": "error",
|
|
158
161
|
"typescript/no-empty-interface": "error",
|
|
159
162
|
"typescript/no-inferrable-types": "error",
|
|
163
|
+
"typescript/no-misused-new": "error",
|
|
164
|
+
"typescript/no-unnecessary-parameter-property-assignment": "error",
|
|
165
|
+
"typescript/no-useless-empty-export": "error",
|
|
166
|
+
"typescript/no-deprecated": "warn",
|
|
160
167
|
"typescript/prefer-for-of": "error",
|
|
161
168
|
"typescript/prefer-function-type": "error",
|
|
162
169
|
"typescript/unified-signatures": "error"
|
|
@@ -223,7 +230,6 @@ function unicorn(overrides) {
|
|
|
223
230
|
"unicorn/catch-error-name": "error",
|
|
224
231
|
"unicorn/error-message": "error",
|
|
225
232
|
"unicorn/prefer-optional-catch-binding": "error",
|
|
226
|
-
"unicorn/no-zero-fractions": "error",
|
|
227
233
|
"unicorn/number-literal-case": "error",
|
|
228
234
|
"unicorn/numeric-separators-style": "error",
|
|
229
235
|
"unicorn/prefer-includes": "error",
|
|
@@ -232,9 +238,22 @@ function unicorn(overrides) {
|
|
|
232
238
|
"unicorn/prefer-string-trim-start-end": "error",
|
|
233
239
|
"unicorn/prefer-structured-clone": "error",
|
|
234
240
|
"unicorn/prefer-default-parameters": "error",
|
|
235
|
-
"unicorn/
|
|
241
|
+
"unicorn/prefer-string-starts-ends-with": "error",
|
|
242
|
+
"unicorn/prefer-set-size": "error",
|
|
236
243
|
"unicorn/throw-new-error": "error",
|
|
237
|
-
"unicorn/require-array-join-separator": "error"
|
|
244
|
+
"unicorn/require-array-join-separator": "error",
|
|
245
|
+
"unicorn/no-zero-fractions": "error",
|
|
246
|
+
"unicorn/no-console-spaces": "error",
|
|
247
|
+
"unicorn/no-useless-spread": "error",
|
|
248
|
+
"unicorn/no-useless-fallback-in-spread": "error",
|
|
249
|
+
"unicorn/no-unnecessary-await": "error",
|
|
250
|
+
"unicorn/no-useless-length-check": "error",
|
|
251
|
+
"unicorn/no-single-promise-in-promise-methods": "error",
|
|
252
|
+
"unicorn/no-await-in-promise-methods": "error",
|
|
253
|
+
"unicorn/no-invalid-remove-event-listener": "error",
|
|
254
|
+
"unicorn/no-invalid-fetch-options": "error",
|
|
255
|
+
"unicorn/no-new-array": "error",
|
|
256
|
+
"unicorn/no-empty-file": "warn"
|
|
238
257
|
}
|
|
239
258
|
}, overrides);
|
|
240
259
|
}
|
|
@@ -255,7 +274,10 @@ function depend(overrides) {
|
|
|
255
274
|
}
|
|
256
275
|
/** Node.js lint preset — native node plugin. */
|
|
257
276
|
function node(overrides) {
|
|
258
|
-
return preset({
|
|
277
|
+
return preset({
|
|
278
|
+
plugins: ["node"],
|
|
279
|
+
rules: { "unicorn/prefer-node-protocol": "error" }
|
|
280
|
+
}, overrides);
|
|
259
281
|
}
|
|
260
282
|
/** Promise lint preset — native promise plugin. */
|
|
261
283
|
function promise(overrides) {
|
|
@@ -267,10 +289,11 @@ const reactRules = {
|
|
|
267
289
|
"react/jsx-key": "error",
|
|
268
290
|
"react/jsx-no-duplicate-props": "error",
|
|
269
291
|
"react/jsx-no-undef": "error",
|
|
270
|
-
"react/jsx-uses-vars": "error",
|
|
271
292
|
"react/jsx-no-target-blank": ["error", { allowReferrer: false }],
|
|
272
293
|
"react/jsx-no-comment-textnodes": "error",
|
|
273
294
|
"react/jsx-no-script-url": "error",
|
|
295
|
+
"react/jsx-props-no-spread-multi": "error",
|
|
296
|
+
"react/jsx-no-useless-fragment": "warn",
|
|
274
297
|
"react/jsx-boolean-value": ["error", "never"],
|
|
275
298
|
"react/jsx-curly-brace-presence": ["error", {
|
|
276
299
|
props: "never",
|
|
@@ -288,7 +311,6 @@ const reactRules = {
|
|
|
288
311
|
"react/hook-use-state": "error",
|
|
289
312
|
"react/no-children-prop": "error",
|
|
290
313
|
"react/no-danger-with-children": "error",
|
|
291
|
-
"react/no-deprecated": "error",
|
|
292
314
|
"react/no-direct-mutation-state": "error",
|
|
293
315
|
"react/no-find-dom-node": "error",
|
|
294
316
|
"react/no-is-mounted": "error",
|
|
@@ -298,8 +320,20 @@ const reactRules = {
|
|
|
298
320
|
"react/no-unsafe": "error",
|
|
299
321
|
"react/require-render-return": "error",
|
|
300
322
|
"react/void-dom-elements-no-children": "error",
|
|
323
|
+
"react/no-set-state": "error",
|
|
324
|
+
"react/no-did-mount-set-state": "error",
|
|
325
|
+
"react/no-did-update-set-state": "error",
|
|
326
|
+
"react/no-will-update-set-state": "error",
|
|
327
|
+
"react/no-this-in-sfc": "error",
|
|
328
|
+
"react/forward-ref-uses-ref": "error",
|
|
329
|
+
"react/no-unstable-nested-components": "warn",
|
|
330
|
+
"react/iframe-missing-sandbox": "error",
|
|
331
|
+
"react/set-state-in-render": "error",
|
|
332
|
+
"react/error-boundaries": "error",
|
|
333
|
+
"react/jsx-no-constructed-context-values": "warn",
|
|
334
|
+
"react/no-array-index-key": "warn",
|
|
335
|
+
"react/style-prop-object": "error",
|
|
301
336
|
"react/react-in-jsx-scope": "off",
|
|
302
|
-
"react/jsx-uses-react": "off",
|
|
303
337
|
"react/no-unescaped-entities": "off"
|
|
304
338
|
};
|
|
305
339
|
/** React lint preset — core React + Hooks rules. */
|
|
@@ -489,6 +523,14 @@ function vitest(options) {
|
|
|
489
523
|
"vitest/no-disabled-tests": isInEditorEnv() ? "warn" : "error",
|
|
490
524
|
"vitest/no-focused-tests": isInEditorEnv() ? "warn" : "error",
|
|
491
525
|
"vitest/require-mock-type-parameters": "off",
|
|
526
|
+
"vitest/prefer-called-once": "error",
|
|
527
|
+
"vitest/prefer-called-times": "error",
|
|
528
|
+
"vitest/prefer-expect-type-of": "error",
|
|
529
|
+
"vitest/prefer-to-be-object": "error",
|
|
530
|
+
"vitest/hoisted-apis-on-top": "error",
|
|
531
|
+
"vitest/require-awaited-expect-poll": "error",
|
|
532
|
+
"vitest/no-conditional-tests": "error",
|
|
533
|
+
"vitest/consistent-vitest-vi": "error",
|
|
492
534
|
"no-console": "off",
|
|
493
535
|
"unicorn/no-null": "off",
|
|
494
536
|
"typescript/ban-ts-comment": "off"
|
package/dist/lint.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lint.mjs","names":["defineConfig"],"sources":["../src/utils.ts","../src/lint.ts"],"sourcesContent":["/**\n * Utility functions and constants\n */\n\n// ============================================================================\n// Environment detection\n// ============================================================================\n\nconst env = process.env\n\nfunction isCI(): boolean {\n return !!(\n env['CI'] ||\n env['CONTINUOUS_INTEGRATION'] ||\n env['BUILD_ID'] ||\n env['BUILD_NUMBER'] ||\n env['RUN_ID']\n )\n}\n\nfunction isInGitHooksOrLintStaged(): boolean {\n return (\n !!(env['GIT_PARAMS'] || env['VSCODE_GIT_COMMAND']) ||\n env['npm_lifecycle_script']?.startsWith('lint-staged') === true\n )\n}\n\n/**\n * Detects whether running in an editor environment.\n * Returns false in CI, Git Hooks, or lint-staged.\n */\nexport function isInEditorEnv(): boolean {\n if (isCI()) return false\n if (isInGitHooksOrLintStaged()) return false\n return !!(\n env['VSCODE_PID'] ||\n env['VSCODE_CWD'] ||\n env['JETBRAINS_IDE'] ||\n env['VIM'] ||\n env['NVIM']\n )\n}\n\n// ============================================================================\n// File matching patterns (Globs)\n// ============================================================================\n\n/** All JS/TS source files */\nexport const GLOB_SRC = '**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx}'\n\n/** JavaScript files only */\nexport const GLOB_JS = '**/*.{js,mjs,cjs,jsx}'\n\n/** TypeScript files only */\nexport const GLOB_TS = '**/*.{ts,mts,cts,tsx}'\n\n/** JSX/TSX files (React-related) */\nexport const GLOB_JSX = '**/*.{jsx,tsx}'\n\n/** Test files */\nexport const GLOB_TESTS: string[] = [\n '**/*.{test,spec}.{js,mjs,cjs,jsx,ts,mts,cts,tsx}',\n '**/__tests__/**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx}',\n]\n\n/** JSON files */\nexport const GLOB_JSON = '**/*.json'\n\n/** Markdown files */\nexport const GLOB_MARKDOWN = '**/*.md'\n","/**\n * Oxlint lint presets.\n *\n * Every preset is a function that accepts optional overrides, merged via `defu`.\n * User overrides take priority over preset defaults.\n *\n * @example\n * ```ts\n * // oxlint.config.ts\n * import { base, unicorn, react, tailwind, vitest } from '@hooshid/ox-config/lint'\n * import { defineConfig } from 'oxlint'\n *\n * export default defineConfig({\n * extends: [base(), unicorn(), react(), tailwind(), vitest()],\n * })\n * ```\n */\nimport { existsSync, readFileSync } from 'node:fs'\nimport { createRequire } from 'node:module'\nimport path from 'node:path'\n\nimport { defu } from 'defu'\nimport { defineConfig } from 'oxlint'\n\nimport { GLOB_JSX, GLOB_SRC, GLOB_TESTS, GLOB_TS, isInEditorEnv } from './utils'\n\nimport type { ExternalPluginEntry, OxlintConfig } from 'oxlint'\n\nconst require = createRequire(import.meta.url)\n\n// ============================================================================\n// Ignore patterns\n// ============================================================================\n\nconst DEFAULT_IGNORES: string[] = [\n '**/node_modules/**',\n '**/dist/**',\n '**/build/**',\n '**/out/**',\n '**/.next/**',\n '**/.cache/**',\n '**/.turbo/**',\n '**/.output/**',\n '**/.nitro/**',\n '**/.tanstack/**',\n '**/.vinxi/**',\n '**/.git/**',\n '**/.svn/**',\n '**/.hg/**',\n '**/.pnp.*',\n '**/public/**',\n '**/*.d.ts',\n]\n\nfunction loadGitignorePatterns(): string[] {\n const gitignoreFile = path.resolve(process.cwd(), '.gitignore')\n if (!existsSync(gitignoreFile)) return []\n\n return readFileSync(gitignoreFile, 'utf8')\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter((line) => line && !line.startsWith('#'))\n .map((pattern) => {\n let p = pattern.trimEnd()\n if (p.startsWith('/')) p = p.slice(1)\n if (!p.includes('/') && !p.includes('*')) p = `**/${p}`\n if (p.endsWith('/')) p = `${p}**`\n return p\n })\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction preset(defaults: OxlintConfig, overrides?: Partial<OxlintConfig>): OxlintConfig {\n return defineConfig(defu(overrides ?? {}, defaults))\n}\n\n/**\n * Resolve a jsPlugin package name to its absolute path.\n * This allows oxlint to load plugins directly without relying on\n * Node module resolution from the consumer's CWD — fixes pnpm strict mode.\n */\nfunction resolvePlugin(name: string): string {\n try {\n return require.resolve(name)\n } catch {\n return name\n }\n}\n\nfunction resolvePlugins(plugins: ExternalPluginEntry[]): ExternalPluginEntry[] {\n return plugins.map((p) => {\n if (typeof p === 'string') return resolvePlugin(p)\n return { ...p, specifier: resolvePlugin(p.specifier) }\n })\n}\n\n// ============================================================================\n// Core\n// ============================================================================\n\n/**\n * Base lint preset — TypeScript + Import plugins, categories, env, ignores.\n * Always include first.\n */\nexport function base(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset(\n {\n plugins: ['typescript', 'import'],\n categories: {\n correctness: 'error',\n suspicious: 'error',\n perf: 'error',\n pedantic: 'warn',\n },\n rules: {\n // Shape-only check; necessary in interactive CLI and sequential workflows.\n 'no-await-in-loop': 'off',\n // High-noise; readonly intent better expressed via `const generics` or call-site.\n 'typescript/prefer-readonly-parameter-types': 'off',\n // Turns `if (str)` into ceremony for marginal safety gain.\n 'typescript/strict-boolean-expressions': 'off',\n // File/function size is a reviewer call, not a lint rule.\n 'max-lines': 'off',\n 'max-lines-per-function': 'off',\n // Misfires on `/* @__PURE__ */` and similar bundler annotations.\n 'no-inline-comments': 'off',\n // TODO/FIXME triage belongs in the issue tracker.\n 'no-warning-comments': 'off',\n // Default cap of 10 is too tight for modern React/Next component files.\n 'import/max-dependencies': 'off',\n // Modern React renders apostrophes correctly; legacy noise.\n 'react/no-unescaped-entities': 'off',\n // Misfires on Next.js Server Actions and placeholder async functions.\n 'require-await': 'off',\n },\n env: {\n browser: true,\n node: true,\n es2026: true,\n builtin: true,\n },\n ignorePatterns: [...DEFAULT_IGNORES, ...loadGitignorePatterns()],\n overrides: [\n {\n files: [GLOB_TS],\n rules: {\n // Only list rules that DIFFER from categories defaults\n 'typescript/consistent-type-definitions': 'off',\n 'typescript/consistent-type-imports': 'error',\n 'no-unused-vars': 'off',\n 'typescript/array-type': 'error',\n 'typescript/consistent-generic-constructors': 'error',\n 'typescript/consistent-indexed-object-style': 'error',\n 'typescript/consistent-type-assertions': 'error',\n 'typescript/ban-tslint-comment': 'error',\n 'typescript/no-empty-interface': 'error',\n 'typescript/no-inferrable-types': 'error',\n 'typescript/prefer-for-of': 'error',\n 'typescript/prefer-function-type': 'error',\n 'typescript/unified-signatures': 'error',\n },\n },\n {\n files: [GLOB_SRC],\n rules: {\n // CSS/style side-effect imports are standard in all frontend frameworks\n 'import/no-unassigned-import': 'off',\n 'import/no-relative-parent-imports': 'error',\n 'import/first': 'error',\n 'import/no-duplicates': 'error',\n 'import/consistent-type-specifier-style': 'error',\n 'import/no-mutable-exports': 'error',\n 'import/no-named-default': 'error',\n },\n },\n {\n // Config files commonly import shared roots via `../../config.ts`\n // in monorepos — intended pattern, not a smell.\n files: ['**/*.config.{ts,mts,cts,js,mjs,cjs}'],\n rules: {\n 'import/no-relative-parent-imports': 'off',\n },\n },\n {\n // Test files use mock setup patterns (vi.mock/vi.hoisted before imports),\n // explicit mock signatures, and fixture data that\n // legitimately violate strict style/safety rules.\n files: GLOB_TESTS,\n rules: {\n // Mock setup pattern breaks standard import ordering\n 'import/first': 'off',\n 'import/no-duplicates': 'off',\n 'import/consistent-type-specifier-style': 'off',\n // Mock signatures need explicit values / async without await\n 'unicorn/no-useless-undefined': 'off',\n 'typescript/no-empty-function': 'off',\n // Modernization hints aren't useful in tests\n 'unicorn/prefer-string-replace-all': 'off',\n 'unicorn/no-array-callback-reference': 'off',\n 'unicorn/prefer-spread': 'off',\n // Tests deliberately use non-null assertions, magic numbers, any\n 'typescript/no-non-null-assertion': 'off',\n 'no-magic-numbers': 'off',\n 'typescript/no-explicit-any': 'off',\n 'typescript/no-unsafe-assignment': 'off',\n 'typescript/no-unsafe-call': 'off',\n 'typescript/no-unsafe-member-access': 'off',\n 'typescript/no-unsafe-return': 'off',\n 'typescript/no-unsafe-argument': 'off',\n // Index keys are fine when rendering fixture lists\n 'react/no-array-index-key': 'off',\n },\n },\n ],\n },\n overrides,\n )\n}\n\n/**\n * Type-aware lint preset — enables 59 type-aware rules via tsgolint + type checking.\n * Requires TypeScript 7.0+ and `oxlint-tsgolint` (bundled as dependency).\n */\nexport function typeAware(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset(\n {\n options: {\n typeAware: true,\n typeCheck: true,\n },\n },\n overrides,\n )\n}\n\n/** Unicorn lint preset — 100+ code quality rules. */\nexport function unicorn(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset(\n {\n plugins: ['unicorn'],\n rules: {\n 'unicorn/no-null': 'off',\n 'unicorn/filename-case': ['error', { case: 'kebabCase' }],\n 'unicorn/catch-error-name': 'error',\n 'unicorn/error-message': 'error',\n 'unicorn/prefer-optional-catch-binding': 'error',\n 'unicorn/no-zero-fractions': 'error',\n 'unicorn/number-literal-case': 'error',\n 'unicorn/numeric-separators-style': 'error',\n 'unicorn/prefer-includes': 'error',\n 'unicorn/prefer-spread': 'error',\n 'unicorn/prefer-ternary': 'error',\n 'unicorn/prefer-string-trim-start-end': 'error',\n 'unicorn/prefer-structured-clone': 'error',\n 'unicorn/prefer-default-parameters': 'error',\n 'unicorn/no-console-spaces': 'error',\n 'unicorn/throw-new-error': 'error',\n 'unicorn/require-array-join-separator': 'error',\n },\n },\n overrides,\n )\n}\n\n/** Dependency optimization — flags packages replaceable with native APIs. */\nexport function depend(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset(\n {\n jsPlugins: resolvePlugins(['eslint-plugin-depend']),\n rules: {\n 'depend/ban-dependencies': [\n 'error',\n {\n presets: ['native', 'microutilities', 'preferred'],\n modules: [],\n allowed: ['dotenv'],\n },\n ],\n },\n },\n overrides,\n )\n}\n\n// ============================================================================\n// Runtime environments\n// ============================================================================\n\n/** Node.js lint preset — native node plugin. */\nexport function node(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset({ plugins: ['node'] }, overrides)\n}\n\n/** Promise lint preset — native promise plugin. */\nexport function promise(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset({ plugins: ['promise'] }, overrides)\n}\n\n// ============================================================================\n// Frontend\n// ============================================================================\n\nconst reactRules = {\n // ─── Hooks (CRITICAL) ─────────────────────────────\n 'react/rules-of-hooks': 'error',\n 'react/exhaustive-deps': 'warn',\n\n // ─── JSX Correctness ──────────────────────────────\n 'react/jsx-key': 'error',\n 'react/jsx-no-duplicate-props': 'error',\n 'react/jsx-no-undef': 'error',\n 'react/jsx-uses-vars': 'error',\n 'react/jsx-no-target-blank': ['error', { allowReferrer: false }],\n 'react/jsx-no-comment-textnodes': 'error',\n 'react/jsx-no-script-url': 'error',\n\n // ─── JSX Style ────────────────────────────────────\n 'react/jsx-boolean-value': ['error', 'never'],\n 'react/jsx-curly-brace-presence': ['error', { props: 'never', children: 'never' }],\n 'react/jsx-fragments': ['error', 'syntax'],\n 'react/jsx-pascal-case': ['error', { allowAllCaps: false, allowNamespace: true }],\n 'react/self-closing-comp': ['error', { component: true, html: true }],\n 'react/hook-use-state': 'error',\n\n // ─── Runtime Safety ───────────────────────────────\n 'react/no-children-prop': 'error',\n 'react/no-danger-with-children': 'error',\n 'react/no-deprecated': 'error',\n 'react/no-direct-mutation-state': 'error',\n 'react/no-find-dom-node': 'error',\n 'react/no-is-mounted': 'error',\n 'react/no-render-return-value': 'error',\n 'react/no-string-refs': 'error',\n 'react/no-unknown-property': 'error',\n 'react/no-unsafe': 'error',\n 'react/require-render-return': 'error',\n 'react/void-dom-elements-no-children': 'error',\n\n // ─── Modern React (17+) ───────────────────────────\n 'react/react-in-jsx-scope': 'off',\n 'react/jsx-uses-react': 'off',\n\n // ─── Noise Reduction ──────────────────────────────\n 'react/no-unescaped-entities': 'off',\n} satisfies NonNullable<OxlintConfig['rules']>\n\n/** React lint preset — core React + Hooks rules. */\nexport function react(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset(\n {\n plugins: ['react'],\n rules: reactRules,\n },\n overrides,\n )\n}\n\n/** React + react-refresh preset (for Vite, TanStack Start, etc.). */\nexport function reactVite(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset(\n {\n plugins: ['react'],\n jsPlugins: resolvePlugins(['eslint-plugin-react-refresh']),\n rules: {\n ...reactRules,\n 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],\n },\n },\n overrides,\n )\n}\n\n/** Next.js lint preset — enables native nextjs plugin. */\nexport function nextjs(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset({ plugins: ['nextjs'] }, overrides)\n}\n\n/**\n * TanStack Router lint preset.\n *\n * Loads @tanstack/eslint-plugin-router and applies conventions specific\n * to file-based routing setups.\n *\n * Rules provided by the plugin:\n * - `route-param-names` — validates `$param` names match between route path and params\n * - `create-route-property-order` — enforces consistent property order in `createRoute()`\n */\nexport function tanstackRouter(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset(\n {\n jsPlugins: resolvePlugins([\n { name: 'tanstack-router', specifier: '@tanstack/eslint-plugin-router' },\n ]),\n rules: {\n // ─── Route Configuration ─────────────────────────\n 'tanstack-router/route-param-names': 'error',\n 'tanstack-router/create-route-property-order': 'error',\n\n // ─── Route File Conventions ──────────────────────\n // Route files should use named exports for route objects\n // (default export reserved for the component or route)\n 'import/no-default-export': 'off', // Router requires default exports\n },\n overrides: [\n {\n // Route files follow specific naming and structure\n files: ['**/routes/**/*.{ts,tsx}'],\n rules: {\n // Routes must not use window directly — use router hooks\n 'no-restricted-globals': [\n 'error',\n {\n name: 'window',\n message: 'Use useRouter() or useNavigate() instead of window in route files.',\n },\n ],\n },\n },\n {\n // ─── Filename Convention (kebab-case) ─────────\n // Applies only to files inside a `routes/` folder.\n files: ['**/routes/**/*.{ts,tsx}'],\n plugins: ['unicorn'],\n rules: {\n 'unicorn/filename-case': [\n 'error',\n {\n case: 'kebabCase',\n ignore: [\n '\\\\$', // dynamic params: $postId.tsx, posts.$postId.tsx\n '^_', // pathless/root: _auth.tsx, __root.tsx\n '\\\\.', // multi-segment: posts.index.tsx, route.lazy.tsx\n ],\n },\n ],\n },\n },\n {\n // Root route file convention\n files: ['**/routes/__root.tsx'],\n rules: {\n // __root.tsx can't use useNavigate (no router context yet)\n 'no-restricted-globals': 'off',\n },\n },\n ],\n },\n overrides,\n )\n}\n\n/**\n * TanStack Start lint preset.\n *\n * Adds rules for server functions, client/server boundaries, and Start\n * conventions. This preset assumes `reactVite()` and `tanstackRouter()`\n * are already in the `extends` array.\n *\n */\nexport function tanstackStart(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset(\n {\n rules: {\n // ─── Server Function Safety ──────────────────────\n // Prevent async promise executors (Start loaders must be sync wrapper)\n 'no-async-promise-executor': 'error',\n // Sequential awaits are fine in server functions\n 'no-await-in-loop': 'off',\n\n // ─── Client / Server Boundary ────────────────────\n // Node.js modules must not leak into client bundles\n 'import/no-nodejs-modules': 'error',\n\n // ─── Loader Conventions ──────────────────────────\n // Loaders must consistently return or throw\n 'consistent-return': 'error',\n\n // ─── Common Start Pitfalls ───────────────────────\n // Empty functions are common in placeholder server functions\n 'no-empty-function': 'warn',\n },\n\n overrides: [\n {\n // Server-only files — Node.js APIs allowed\n files: ['**/*.server.{ts,tsx}', '**/server/**/*.{ts,tsx}', '**/server-fns/**/*.{ts,tsx}'],\n rules: {\n 'import/no-nodejs-modules': 'off',\n 'no-console': 'off',\n },\n },\n {\n // Client-only files — Node.js APIs forbidden\n files: ['**/*.client.{ts,tsx}', '**/components/**/*.{ts,tsx}'],\n rules: {\n 'import/no-nodejs-modules': 'error',\n },\n },\n {\n // Route files — server-aware\n files: ['**/routes/**/*.{ts,tsx}'],\n rules: {\n // Routes use loaders, not direct fetch in component\n 'no-restricted-syntax': [\n 'warn',\n {\n selector: 'CallExpression[callee.name=\"fetch\"]',\n message: 'Prefer a loader or server function over direct fetch in route files.',\n },\n ],\n },\n },\n {\n files: ['**/*.server.{ts,tsx}', '**/*.client.{ts,tsx}'],\n plugins: ['unicorn'],\n rules: {\n 'unicorn/filename-case': [\n 'error',\n {\n case: 'kebabCase',\n ignore: [\n '\\\\.', // allow *.server.ts / *.client.ts (has dots)\n ],\n },\n ],\n },\n },\n {\n files: ['**/*.server.{ts,tsx}', '**/server/**/*.{ts,tsx}', '**/server-fns/**/*.{ts,tsx}'],\n rules: {\n 'import/no-nodejs-modules': 'off',\n 'no-console': 'off',\n // ← جدید: جلوگیری از crash توی SSR\n 'no-restricted-globals': [\n 'error',\n {\n name: 'window',\n message:\n 'Not available in server context. Use a server function or guard with typeof window.',\n },\n { name: 'document', message: 'Not available in server context.' },\n { name: 'localStorage', message: 'Not available in server context.' },\n { name: 'sessionStorage', message: 'Not available in server context.' },\n ],\n },\n },\n ],\n },\n overrides,\n )\n}\n\n// ============================================================================\n// Quality\n// ============================================================================\n\n/** Accessibility lint preset — enables native jsx-a11y plugin. */\nexport function a11y(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset({ plugins: ['jsx-a11y'] }, overrides)\n}\n\n/** JSDoc lint preset — enables native jsdoc plugin. */\nexport function jsdoc(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset({ plugins: ['jsdoc'] }, overrides)\n}\n\n// ============================================================================\n// Testing\n// ============================================================================\n\ninterface VitestOptions extends Partial<OxlintConfig> {\n /** Test file glob patterns. Replaces the default GLOB_TESTS. */\n files?: string[]\n}\n\n/** Vitest lint preset — native vitest plugin with test-file scoping. */\nexport function vitest(options?: VitestOptions): OxlintConfig {\n const { files, ...overrides } = options ?? {}\n\n return preset(\n {\n plugins: ['vitest'],\n settings: { vitest: { typecheck: true } },\n overrides: [\n {\n files: files ?? GLOB_TESTS,\n rules: {\n 'vitest/expect-expect': 'error',\n 'vitest/no-conditional-expect': 'error',\n 'vitest/no-identical-title': 'error',\n 'vitest/no-import-node-test': 'error',\n 'vitest/no-interpolation-in-snapshots': 'error',\n 'vitest/no-mocks-import': 'error',\n 'vitest/no-standalone-expect': 'error',\n 'vitest/valid-describe-callback': 'error',\n 'vitest/valid-expect': 'error',\n 'vitest/valid-title': 'error',\n 'vitest/consistent-test-it': ['error', { fn: 'it', withinDescribe: 'it' }],\n 'vitest/prefer-hooks-in-order': 'error',\n 'vitest/prefer-lowercase-title': 'error',\n 'vitest/no-disabled-tests': isInEditorEnv() ? 'warn' : 'error',\n 'vitest/no-focused-tests': isInEditorEnv() ? 'warn' : 'error',\n 'vitest/require-mock-type-parameters': 'off',\n 'no-console': 'off',\n 'unicorn/no-null': 'off',\n 'typescript/ban-ts-comment': 'off',\n },\n },\n ],\n },\n overrides,\n )\n}\n\n// ============================================================================\n// Tailwind\n// ============================================================================\n\ninterface TailwindOptions extends Partial<OxlintConfig> {\n entryPoint?: string\n rootFontSize?: number\n /** File glob patterns for tailwind rules. @default GLOB_JSX */\n files?: string[]\n}\n\n/** Tailwind CSS lint preset — eslint-plugin-better-tailwindcss. */\nexport function tailwind(options: TailwindOptions = {}): OxlintConfig {\n const { entryPoint = 'src/styles/globals.css', rootFontSize = 16, files, ...overrides } = options\n\n return preset(\n {\n jsPlugins: resolvePlugins(['eslint-plugin-better-tailwindcss']),\n settings: { 'better-tailwindcss': { entryPoint, rootFontSize } },\n overrides: [\n {\n files: files ?? [GLOB_JSX],\n rules: {\n 'better-tailwindcss/enforce-consistent-line-wrapping': ['error', { printWidth: 0 }],\n 'better-tailwindcss/enforce-canonical-classes': 'error',\n },\n },\n ],\n },\n overrides,\n )\n}\n\n// ============================================================================\n// Backend / ORM\n// ============================================================================\n\n/**\n * NestJS lint preset — loads @darraghor/eslint-plugin-nestjs-typed via jsPlugin.\n * Covers DI validation, Swagger consistency, decorator bug prevention (19 AST rules).\n */\nexport function nestjs(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset(\n {\n jsPlugins: resolvePlugins([\n { name: 'nestjs-typed', specifier: '@darraghor/eslint-plugin-nestjs-typed' },\n ]),\n rules: {\n // DI\n 'nestjs-typed/injectable-should-be-provided': 'error',\n 'nestjs-typed/provided-injected-should-match-factory-parameters': 'error',\n 'nestjs-typed/use-injectable-provided-token': 'error',\n // Swagger\n 'nestjs-typed/api-property-matches-property-optionality': 'error',\n 'nestjs-typed/controllers-should-supply-api-tags': 'error',\n 'nestjs-typed/api-method-should-specify-api-response': 'error',\n 'nestjs-typed/api-property-returning-array-should-set-array': 'error',\n 'nestjs-typed/api-property-should-have-api-extra-models': 'error',\n 'nestjs-typed/api-operation-summary-description-capitalized': 'error',\n // Bug prevention\n 'nestjs-typed/param-decorator-name-matches-route-param': 'error',\n 'nestjs-typed/validate-nested-of-array-should-set-each': 'error',\n 'nestjs-typed/all-properties-are-whitelisted': 'error',\n 'nestjs-typed/no-duplicate-decorators': 'error',\n 'nestjs-typed/validation-pipe-should-use-forbid-unknown': 'error',\n },\n },\n overrides,\n )\n}\n\n/** Drizzle ORM lint preset — eslint-plugin-drizzle. */\nexport function drizzle(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset(\n {\n jsPlugins: resolvePlugins(['eslint-plugin-drizzle']),\n rules: {\n 'drizzle/enforce-delete-with-where': 'error',\n 'drizzle/enforce-update-with-where': 'error',\n },\n },\n overrides,\n )\n}\n\n// ============================================================================\n// Re-exports\n// ============================================================================\n\nexport { defineConfig } from 'oxlint'\nexport { GLOB_SRC, GLOB_JS, GLOB_TS, GLOB_JSX, GLOB_TESTS, GLOB_JSON, GLOB_MARKDOWN } from './utils'\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"lint.mjs","names":["defineConfig"],"sources":["../src/utils.ts","../src/lint.ts"],"sourcesContent":["/**\n * Utility functions and constants\n */\n\n// ============================================================================\n// Environment detection\n// ============================================================================\n\nconst env = process.env\n\nfunction isCI(): boolean {\n return !!(\n env['CI'] ||\n env['CONTINUOUS_INTEGRATION'] ||\n env['BUILD_ID'] ||\n env['BUILD_NUMBER'] ||\n env['RUN_ID']\n )\n}\n\nfunction isInGitHooksOrLintStaged(): boolean {\n return (\n !!(env['GIT_PARAMS'] || env['VSCODE_GIT_COMMAND']) ||\n env['npm_lifecycle_script']?.startsWith('lint-staged') === true\n )\n}\n\n/**\n * Detects whether running in an editor environment.\n * Returns false in CI, Git Hooks, or lint-staged.\n */\nexport function isInEditorEnv(): boolean {\n if (isCI()) return false\n if (isInGitHooksOrLintStaged()) return false\n return !!(\n env['VSCODE_PID'] ||\n env['VSCODE_CWD'] ||\n env['JETBRAINS_IDE'] ||\n env['VIM'] ||\n env['NVIM']\n )\n}\n\n// ============================================================================\n// File matching patterns (Globs)\n// ============================================================================\n\n/** All JS/TS source files */\nexport const GLOB_SRC = '**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx}'\n\n/** JavaScript files only */\nexport const GLOB_JS = '**/*.{js,mjs,cjs,jsx}'\n\n/** TypeScript files only */\nexport const GLOB_TS = '**/*.{ts,mts,cts,tsx}'\n\n/** JSX/TSX files (React-related) */\nexport const GLOB_JSX = '**/*.{jsx,tsx}'\n\n/** Test files */\nexport const GLOB_TESTS: string[] = [\n '**/*.{test,spec}.{js,mjs,cjs,jsx,ts,mts,cts,tsx}',\n '**/__tests__/**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx}',\n]\n\n/** JSON files */\nexport const GLOB_JSON = '**/*.json'\n\n/** Markdown files */\nexport const GLOB_MARKDOWN = '**/*.md'\n","/**\n * Oxlint lint presets.\n *\n * Every preset is a function that accepts optional overrides, merged via `defu`.\n * User overrides take priority over preset defaults.\n *\n * @example\n * ```ts\n * // oxlint.config.ts\n * import { base, unicorn, react, tailwind, vitest } from '@hooshid/ox-config/lint'\n * import { defineConfig } from 'oxlint'\n *\n * export default defineConfig({\n * extends: [base(), unicorn(), react(), tailwind(), vitest()],\n * })\n * ```\n */\nimport { existsSync, readFileSync } from 'node:fs'\nimport { createRequire } from 'node:module'\nimport path from 'node:path'\n\nimport { defu } from 'defu'\nimport { defineConfig } from 'oxlint'\n\nimport { GLOB_JSX, GLOB_SRC, GLOB_TESTS, GLOB_TS, isInEditorEnv } from './utils'\n\nimport type { ExternalPluginEntry, OxlintConfig } from 'oxlint'\n\nconst require = createRequire(import.meta.url)\n\n// ============================================================================\n// Ignore patterns\n// ============================================================================\n\nconst DEFAULT_IGNORES: string[] = [\n '**/node_modules/**',\n '**/dist/**',\n '**/build/**',\n '**/out/**',\n '**/.next/**',\n '**/.cache/**',\n '**/.turbo/**',\n '**/.output/**',\n '**/.nitro/**',\n '**/.tanstack/**',\n '**/.vinxi/**',\n '**/.git/**',\n '**/.svn/**',\n '**/.hg/**',\n '**/.pnp.*',\n '**/public/**',\n '**/routeTree.gen.ts',\n '**/*.d.ts',\n]\n\nfunction loadGitignorePatterns(): string[] {\n const gitignoreFile = path.resolve(process.cwd(), '.gitignore')\n if (!existsSync(gitignoreFile)) return []\n\n return readFileSync(gitignoreFile, 'utf8')\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter((line) => line && !line.startsWith('#'))\n .map((pattern) => {\n let p = pattern.trimEnd()\n if (p.startsWith('/')) p = p.slice(1)\n if (!p.includes('/') && !p.includes('*')) p = `**/${p}`\n if (p.endsWith('/')) p = `${p}**`\n return p\n })\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction preset(defaults: OxlintConfig, overrides?: Partial<OxlintConfig>): OxlintConfig {\n return defineConfig(defu(overrides ?? {}, defaults))\n}\n\n/**\n * Resolve a jsPlugin package name to its absolute path.\n * This allows oxlint to load plugins directly without relying on\n * Node module resolution from the consumer's CWD — fixes pnpm strict mode.\n */\nfunction resolvePlugin(name: string): string {\n try {\n return require.resolve(name)\n } catch {\n return name\n }\n}\n\nfunction resolvePlugins(plugins: ExternalPluginEntry[]): ExternalPluginEntry[] {\n return plugins.map((p) => {\n if (typeof p === 'string') return resolvePlugin(p)\n return { ...p, specifier: resolvePlugin(p.specifier) }\n })\n}\n\n// ============================================================================\n// Core\n// ============================================================================\n\n/**\n * Base lint preset — TypeScript + Import plugins, categories, env, ignores.\n * Always include first.\n */\nexport function base(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset(\n {\n plugins: ['typescript', 'import'],\n categories: {\n correctness: 'error',\n suspicious: 'error',\n perf: 'error',\n pedantic: 'warn',\n },\n rules: {\n // Shape-only check; necessary in interactive CLI and sequential workflows.\n 'no-await-in-loop': 'off',\n // High-noise; readonly intent better expressed via `const generics` or call-site.\n 'typescript/prefer-readonly-parameter-types': 'off',\n // Turns `if (str)` into ceremony for marginal safety gain.\n 'typescript/strict-boolean-expressions': 'off',\n // File/function size is a reviewer call, not a lint rule.\n 'max-lines': 'off',\n 'max-lines-per-function': 'off',\n // Misfires on `/* @__PURE__ */` and similar bundler annotations.\n 'no-inline-comments': 'off',\n // TODO/FIXME triage belongs in the issue tracker.\n 'no-warning-comments': 'off',\n // Default cap of 10 is too tight for modern React/Next component files.\n 'import/max-dependencies': 'off',\n // Modern React renders apostrophes correctly; legacy noise.\n 'react/no-unescaped-entities': 'off',\n // Misfires on Next.js Server Actions and placeholder async functions.\n 'require-await': 'off',\n },\n env: {\n browser: true,\n node: true,\n es2026: true,\n builtin: true,\n },\n ignorePatterns: [...DEFAULT_IGNORES, ...loadGitignorePatterns()],\n overrides: [\n {\n files: [GLOB_TS],\n rules: {\n // Only list rules that DIFFER from categories defaults\n 'typescript/consistent-type-definitions': 'off',\n 'typescript/consistent-type-imports': 'error',\n 'no-unused-vars': 'off',\n 'no-useless-rename': 'error',\n 'uninvoked-array-callback': 'error',\n 'typescript/array-type': 'error',\n 'typescript/consistent-generic-constructors': 'error',\n 'typescript/consistent-indexed-object-style': 'error',\n 'typescript/consistent-type-assertions': 'error',\n 'typescript/ban-tslint-comment': 'error',\n 'typescript/no-empty-interface': 'error',\n 'typescript/no-inferrable-types': 'error',\n 'typescript/no-misused-new': 'error',\n 'typescript/no-unnecessary-parameter-property-assignment': 'error',\n 'typescript/no-useless-empty-export': 'error',\n 'typescript/no-deprecated': 'warn',\n 'typescript/prefer-for-of': 'error',\n 'typescript/prefer-function-type': 'error',\n 'typescript/unified-signatures': 'error',\n },\n },\n {\n files: [GLOB_SRC],\n rules: {\n // CSS/style side-effect imports are standard in all frontend frameworks\n 'import/no-unassigned-import': 'off',\n 'import/no-relative-parent-imports': 'error',\n 'import/first': 'error',\n 'import/no-duplicates': 'error',\n 'import/consistent-type-specifier-style': 'error',\n 'import/no-mutable-exports': 'error',\n 'import/no-named-default': 'error',\n },\n },\n {\n // Config files commonly import shared roots via `../../config.ts`\n // in monorepos — intended pattern, not a smell.\n files: ['**/*.config.{ts,mts,cts,js,mjs,cjs}'],\n rules: {\n 'import/no-relative-parent-imports': 'off',\n },\n },\n {\n // Test files use mock setup patterns (vi.mock/vi.hoisted before imports),\n // explicit mock signatures, and fixture data that\n // legitimately violate strict style/safety rules.\n files: GLOB_TESTS,\n rules: {\n // Mock setup pattern breaks standard import ordering\n 'import/first': 'off',\n 'import/no-duplicates': 'off',\n 'import/consistent-type-specifier-style': 'off',\n // Mock signatures need explicit values / async without await\n 'unicorn/no-useless-undefined': 'off',\n 'typescript/no-empty-function': 'off',\n // Modernization hints aren't useful in tests\n 'unicorn/prefer-string-replace-all': 'off',\n 'unicorn/no-array-callback-reference': 'off',\n 'unicorn/prefer-spread': 'off',\n // Tests deliberately use non-null assertions, magic numbers, any\n 'typescript/no-non-null-assertion': 'off',\n 'no-magic-numbers': 'off',\n 'typescript/no-explicit-any': 'off',\n 'typescript/no-unsafe-assignment': 'off',\n 'typescript/no-unsafe-call': 'off',\n 'typescript/no-unsafe-member-access': 'off',\n 'typescript/no-unsafe-return': 'off',\n 'typescript/no-unsafe-argument': 'off',\n // Index keys are fine when rendering fixture lists\n 'react/no-array-index-key': 'off',\n },\n },\n ],\n },\n overrides,\n )\n}\n\n/**\n * Type-aware lint preset — enables 59 type-aware rules via tsgolint + type checking.\n * Requires TypeScript 7.0+ and `oxlint-tsgolint` (bundled as dependency).\n */\nexport function typeAware(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset(\n {\n options: {\n typeAware: true,\n typeCheck: true,\n },\n },\n overrides,\n )\n}\n\n/** Unicorn lint preset — 100+ code quality rules. */\nexport function unicorn(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset(\n {\n plugins: ['unicorn'],\n rules: {\n 'unicorn/no-null': 'off',\n 'unicorn/filename-case': ['error', { case: 'kebabCase' }],\n 'unicorn/catch-error-name': 'error',\n 'unicorn/error-message': 'error',\n 'unicorn/prefer-optional-catch-binding': 'error',\n 'unicorn/number-literal-case': 'error',\n 'unicorn/numeric-separators-style': 'error',\n 'unicorn/prefer-includes': 'error',\n 'unicorn/prefer-spread': 'error',\n 'unicorn/prefer-ternary': 'error',\n 'unicorn/prefer-string-trim-start-end': 'error',\n 'unicorn/prefer-structured-clone': 'error',\n 'unicorn/prefer-default-parameters': 'error',\n 'unicorn/prefer-string-starts-ends-with': 'error',\n 'unicorn/prefer-set-size': 'error',\n 'unicorn/throw-new-error': 'error',\n 'unicorn/require-array-join-separator': 'error',\n\n // Correctness\n 'unicorn/no-zero-fractions': 'error',\n 'unicorn/no-console-spaces': 'error',\n 'unicorn/no-useless-spread': 'error',\n 'unicorn/no-useless-fallback-in-spread': 'error',\n 'unicorn/no-unnecessary-await': 'error',\n 'unicorn/no-useless-length-check': 'error',\n 'unicorn/no-single-promise-in-promise-methods': 'error',\n 'unicorn/no-await-in-promise-methods': 'error',\n 'unicorn/no-invalid-remove-event-listener': 'error',\n 'unicorn/no-invalid-fetch-options': 'error',\n 'unicorn/no-new-array': 'error',\n 'unicorn/no-empty-file': 'warn',\n },\n },\n overrides,\n )\n}\n\n/** Dependency optimization — flags packages replaceable with native APIs. */\nexport function depend(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset(\n {\n jsPlugins: resolvePlugins(['eslint-plugin-depend']),\n rules: {\n 'depend/ban-dependencies': [\n 'error',\n {\n presets: ['native', 'microutilities', 'preferred'],\n modules: [],\n allowed: ['dotenv'],\n },\n ],\n },\n },\n overrides,\n )\n}\n\n// ============================================================================\n// Runtime environments\n// ============================================================================\n\n/** Node.js lint preset — native node plugin. */\nexport function node(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset(\n {\n plugins: ['node'],\n rules: {\n 'unicorn/prefer-node-protocol': 'error',\n },\n },\n overrides,\n )\n}\n\n/** Promise lint preset — native promise plugin. */\nexport function promise(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset({ plugins: ['promise'] }, overrides)\n}\n\n// ============================================================================\n// Frontend\n// ============================================================================\n\nconst reactRules = {\n // Hooks (CRITICAL)\n 'react/rules-of-hooks': 'error',\n 'react/exhaustive-deps': 'warn',\n\n // JSX Correctness\n 'react/jsx-key': 'error',\n 'react/jsx-no-duplicate-props': 'error',\n 'react/jsx-no-undef': 'error',\n 'react/jsx-no-target-blank': ['error', { allowReferrer: false }],\n 'react/jsx-no-comment-textnodes': 'error',\n 'react/jsx-no-script-url': 'error',\n 'react/jsx-props-no-spread-multi': 'error',\n 'react/jsx-no-useless-fragment': 'warn',\n\n // JSX Style\n 'react/jsx-boolean-value': ['error', 'never'],\n 'react/jsx-curly-brace-presence': ['error', { props: 'never', children: 'never' }],\n 'react/jsx-fragments': ['error', 'syntax'],\n 'react/jsx-pascal-case': ['error', { allowAllCaps: false, allowNamespace: true }],\n 'react/self-closing-comp': ['error', { component: true, html: true }],\n 'react/hook-use-state': 'error',\n\n // Runtime Safety\n 'react/no-children-prop': 'error',\n 'react/no-danger-with-children': 'error',\n 'react/no-direct-mutation-state': 'error',\n 'react/no-find-dom-node': 'error',\n 'react/no-is-mounted': 'error',\n 'react/no-render-return-value': 'error',\n 'react/no-string-refs': 'error',\n 'react/no-unknown-property': 'error',\n 'react/no-unsafe': 'error',\n 'react/require-render-return': 'error',\n 'react/void-dom-elements-no-children': 'error',\n\n // Lifecycle Safety\n 'react/no-set-state': 'error',\n 'react/no-did-mount-set-state': 'error',\n 'react/no-did-update-set-state': 'error',\n 'react/no-will-update-set-state': 'error',\n 'react/no-this-in-sfc': 'error',\n\n // Refs & Boundaries\n 'react/forward-ref-uses-ref': 'error',\n 'react/no-unstable-nested-components': 'warn',\n 'react/iframe-missing-sandbox': 'error',\n 'react/set-state-in-render': 'error',\n 'react/error-boundaries': 'error',\n\n // Performance\n 'react/jsx-no-constructed-context-values': 'warn',\n 'react/no-array-index-key': 'warn',\n 'react/style-prop-object': 'error',\n\n // Modern React (17+)\n 'react/react-in-jsx-scope': 'off',\n\n // Noise Reduction\n 'react/no-unescaped-entities': 'off',\n} satisfies NonNullable<OxlintConfig['rules']>\n\n/** React lint preset — core React + Hooks rules. */\nexport function react(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset(\n {\n plugins: ['react'],\n rules: reactRules,\n },\n overrides,\n )\n}\n\n/** React + react-refresh preset (for Vite, TanStack Start, etc.). */\nexport function reactVite(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset(\n {\n plugins: ['react'],\n jsPlugins: resolvePlugins(['eslint-plugin-react-refresh']),\n rules: {\n ...reactRules,\n 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],\n },\n },\n overrides,\n )\n}\n\n/** Next.js lint preset — enables native nextjs plugin. */\nexport function nextjs(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset({ plugins: ['nextjs'] }, overrides)\n}\n\n/**\n * TanStack Router lint preset.\n *\n * Loads @tanstack/eslint-plugin-router and applies conventions specific\n * to file-based routing setups.\n *\n * Rules provided by the plugin:\n * - `route-param-names` — validates `$param` names match between route path and params\n * - `create-route-property-order` — enforces consistent property order in `createRoute()`\n */\nexport function tanstackRouter(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset(\n {\n jsPlugins: resolvePlugins([\n { name: 'tanstack-router', specifier: '@tanstack/eslint-plugin-router' },\n ]),\n rules: {\n // ─── Route Configuration ─────────────────────────\n 'tanstack-router/route-param-names': 'error',\n 'tanstack-router/create-route-property-order': 'error',\n\n // ─── Route File Conventions ──────────────────────\n // Route files should use named exports for route objects\n // (default export reserved for the component or route)\n 'import/no-default-export': 'off', // Router requires default exports\n },\n overrides: [\n {\n // Route files follow specific naming and structure\n files: ['**/routes/**/*.{ts,tsx}'],\n rules: {\n // Routes must not use window directly — use router hooks\n 'no-restricted-globals': [\n 'error',\n {\n name: 'window',\n message: 'Use useRouter() or useNavigate() instead of window in route files.',\n },\n ],\n },\n },\n {\n files: ['**/routes/**/*.{ts,tsx}'],\n plugins: ['unicorn'],\n rules: {\n 'unicorn/filename-case': [\n 'error',\n {\n case: 'kebabCase',\n ignore: [\n '\\\\$', // dynamic params: $postId.tsx, posts.$postId.tsx\n '^_', // pathless/root: _auth.tsx, __root.tsx\n '\\\\.', // multi-segment: posts.index.tsx, route.lazy.tsx\n ],\n },\n ],\n },\n },\n {\n // Root route file convention\n files: ['**/routes/__root.tsx'],\n rules: {\n // __root.tsx can't use useNavigate (no router context yet)\n 'no-restricted-globals': 'off',\n },\n },\n ],\n },\n overrides,\n )\n}\n\n/**\n * TanStack Start lint preset.\n *\n * Adds rules for server functions, client/server boundaries, and Start\n * conventions. This preset assumes `reactVite()` and `tanstackRouter()`\n * are already in the `extends` array.\n *\n */\nexport function tanstackStart(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset(\n {\n rules: {\n // ─── Server Function Safety ──────────────────────\n // Prevent async promise executors (Start loaders must be sync wrapper)\n 'no-async-promise-executor': 'error',\n // Sequential awaits are fine in server functions\n 'no-await-in-loop': 'off',\n\n // ─── Client / Server Boundary ────────────────────\n // Node.js modules must not leak into client bundles\n 'import/no-nodejs-modules': 'error',\n\n // ─── Loader Conventions ──────────────────────────\n // Loaders must consistently return or throw\n 'consistent-return': 'error',\n\n // ─── Common Start Pitfalls ───────────────────────\n // Empty functions are common in placeholder server functions\n 'no-empty-function': 'warn',\n },\n\n overrides: [\n {\n // Server-only files — Node.js APIs allowed\n files: ['**/*.server.{ts,tsx}', '**/server/**/*.{ts,tsx}', '**/server-fns/**/*.{ts,tsx}'],\n rules: {\n 'import/no-nodejs-modules': 'off',\n 'no-console': 'off',\n },\n },\n {\n // Client-only files — Node.js APIs forbidden\n files: ['**/*.client.{ts,tsx}', '**/components/**/*.{ts,tsx}'],\n rules: {\n 'import/no-nodejs-modules': 'error',\n },\n },\n {\n // Route files — server-aware\n files: ['**/routes/**/*.{ts,tsx}'],\n rules: {\n // Routes use loaders, not direct fetch in component\n 'no-restricted-syntax': [\n 'warn',\n {\n selector: 'CallExpression[callee.name=\"fetch\"]',\n message: 'Prefer a loader or server function over direct fetch in route files.',\n },\n ],\n },\n },\n {\n files: ['**/*.server.{ts,tsx}', '**/*.client.{ts,tsx}'],\n plugins: ['unicorn'],\n rules: {\n 'unicorn/filename-case': [\n 'error',\n {\n case: 'kebabCase',\n ignore: [\n '\\\\.', // allow *.server.ts / *.client.ts (has dots)\n ],\n },\n ],\n },\n },\n {\n files: ['**/*.server.{ts,tsx}', '**/server/**/*.{ts,tsx}', '**/server-fns/**/*.{ts,tsx}'],\n rules: {\n 'import/no-nodejs-modules': 'off',\n 'no-console': 'off',\n // ← جدید: جلوگیری از crash توی SSR\n 'no-restricted-globals': [\n 'error',\n {\n name: 'window',\n message:\n 'Not available in server context. Use a server function or guard with typeof window.',\n },\n { name: 'document', message: 'Not available in server context.' },\n { name: 'localStorage', message: 'Not available in server context.' },\n { name: 'sessionStorage', message: 'Not available in server context.' },\n ],\n },\n },\n ],\n },\n overrides,\n )\n}\n\n// ============================================================================\n// Quality\n// ============================================================================\n\n/** Accessibility lint preset — enables native jsx-a11y plugin. */\nexport function a11y(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset({ plugins: ['jsx-a11y'] }, overrides)\n}\n\n/** JSDoc lint preset — enables native jsdoc plugin. */\nexport function jsdoc(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset({ plugins: ['jsdoc'] }, overrides)\n}\n\n// ============================================================================\n// Testing\n// ============================================================================\n\ninterface VitestOptions extends Partial<OxlintConfig> {\n /** Test file glob patterns. Replaces the default GLOB_TESTS. */\n files?: string[]\n}\n\n/** Vitest lint preset — native vitest plugin with test-file scoping. */\nexport function vitest(options?: VitestOptions): OxlintConfig {\n const { files, ...overrides } = options ?? {}\n\n return preset(\n {\n plugins: ['vitest'],\n settings: { vitest: { typecheck: true } },\n overrides: [\n {\n files: files ?? GLOB_TESTS,\n rules: {\n 'vitest/expect-expect': 'error',\n 'vitest/no-conditional-expect': 'error',\n 'vitest/no-identical-title': 'error',\n 'vitest/no-import-node-test': 'error',\n 'vitest/no-interpolation-in-snapshots': 'error',\n 'vitest/no-mocks-import': 'error',\n 'vitest/no-standalone-expect': 'error',\n 'vitest/valid-describe-callback': 'error',\n 'vitest/valid-expect': 'error',\n 'vitest/valid-title': 'error',\n 'vitest/consistent-test-it': ['error', { fn: 'it', withinDescribe: 'it' }],\n 'vitest/prefer-hooks-in-order': 'error',\n 'vitest/prefer-lowercase-title': 'error',\n 'vitest/no-disabled-tests': isInEditorEnv() ? 'warn' : 'error',\n 'vitest/no-focused-tests': isInEditorEnv() ? 'warn' : 'error',\n 'vitest/require-mock-type-parameters': 'off',\n 'vitest/prefer-called-once': 'error',\n 'vitest/prefer-called-times': 'error',\n 'vitest/prefer-expect-type-of': 'error',\n 'vitest/prefer-to-be-object': 'error',\n 'vitest/hoisted-apis-on-top': 'error',\n 'vitest/require-awaited-expect-poll': 'error',\n 'vitest/no-conditional-tests': 'error',\n 'vitest/consistent-vitest-vi': 'error',\n 'no-console': 'off',\n 'unicorn/no-null': 'off',\n 'typescript/ban-ts-comment': 'off',\n },\n },\n ],\n },\n overrides,\n )\n}\n\n// ============================================================================\n// Tailwind\n// ============================================================================\n\ninterface TailwindOptions extends Partial<OxlintConfig> {\n entryPoint?: string\n rootFontSize?: number\n /** File glob patterns for tailwind rules. @default GLOB_JSX */\n files?: string[]\n}\n\n/** Tailwind CSS lint preset — eslint-plugin-better-tailwindcss. */\nexport function tailwind(options: TailwindOptions = {}): OxlintConfig {\n const { entryPoint = 'src/styles/globals.css', rootFontSize = 16, files, ...overrides } = options\n\n return preset(\n {\n jsPlugins: resolvePlugins(['eslint-plugin-better-tailwindcss']),\n settings: { 'better-tailwindcss': { entryPoint, rootFontSize } },\n overrides: [\n {\n files: files ?? [GLOB_JSX],\n rules: {\n 'better-tailwindcss/enforce-consistent-line-wrapping': ['error', { printWidth: 0 }],\n 'better-tailwindcss/enforce-canonical-classes': 'error',\n },\n },\n ],\n },\n overrides,\n )\n}\n\n// ============================================================================\n// Backend / ORM\n// ============================================================================\n\n/**\n * NestJS lint preset — loads @darraghor/eslint-plugin-nestjs-typed via jsPlugin.\n * Covers DI validation, Swagger consistency, decorator bug prevention (19 AST rules).\n */\nexport function nestjs(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset(\n {\n jsPlugins: resolvePlugins([\n { name: 'nestjs-typed', specifier: '@darraghor/eslint-plugin-nestjs-typed' },\n ]),\n rules: {\n // DI\n 'nestjs-typed/injectable-should-be-provided': 'error',\n 'nestjs-typed/provided-injected-should-match-factory-parameters': 'error',\n 'nestjs-typed/use-injectable-provided-token': 'error',\n // Swagger\n 'nestjs-typed/api-property-matches-property-optionality': 'error',\n 'nestjs-typed/controllers-should-supply-api-tags': 'error',\n 'nestjs-typed/api-method-should-specify-api-response': 'error',\n 'nestjs-typed/api-property-returning-array-should-set-array': 'error',\n 'nestjs-typed/api-property-should-have-api-extra-models': 'error',\n 'nestjs-typed/api-operation-summary-description-capitalized': 'error',\n // Bug prevention\n 'nestjs-typed/param-decorator-name-matches-route-param': 'error',\n 'nestjs-typed/validate-nested-of-array-should-set-each': 'error',\n 'nestjs-typed/all-properties-are-whitelisted': 'error',\n 'nestjs-typed/no-duplicate-decorators': 'error',\n 'nestjs-typed/validation-pipe-should-use-forbid-unknown': 'error',\n },\n },\n overrides,\n )\n}\n\n/** Drizzle ORM lint preset — eslint-plugin-drizzle. */\nexport function drizzle(overrides?: Partial<OxlintConfig>): OxlintConfig {\n return preset(\n {\n jsPlugins: resolvePlugins(['eslint-plugin-drizzle']),\n rules: {\n 'drizzle/enforce-delete-with-where': 'error',\n 'drizzle/enforce-update-with-where': 'error',\n },\n },\n overrides,\n )\n}\n\n// ============================================================================\n// Re-exports\n// ============================================================================\n\nexport { defineConfig } from 'oxlint'\nexport { GLOB_SRC, GLOB_JS, GLOB_TS, GLOB_JSX, GLOB_TESTS, GLOB_JSON, GLOB_MARKDOWN } from './utils'\n"],"mappings":"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"}
|