Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 38 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"tsx": "^4.21.0",
"typescript": "^5.9.3",
"vite": "^6.0.0",
"vite-plugin-dts": "^4.5.0"
"vite-plugin-dts": "^4.5.0",
"vite-tsconfig-paths": "^6.0.5"
}
}
31 changes: 14 additions & 17 deletions scripts/generate-rules-md.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { readFileSync, writeFileSync, mkdirSync, rmSync } from 'node:fs'
import { readFile, writeFile, mkdir, rm } from 'node:fs/promises'
import { resolve, dirname } from 'node:path'
import { fileURLToPath } from 'node:url'

Expand All @@ -11,10 +11,8 @@ interface RuleEntry {
options?: unknown[]
}

const rules = JSON.parse(
// eslint-disable-next-line n/no-sync
readFileSync(resolve(rootDir, 'rules.json'), 'utf-8'),
) as Record<string, RuleEntry>
const rulesPath = resolve(rootDir, 'rules.json')
const rules = JSON.parse(await readFile(rulesPath, 'utf-8')) as Record<string, RuleEntry>

function getDocUrl(rule: string): string | null {
const urlMap: Record<string, (name: string) => string> = {
Expand Down Expand Up @@ -73,19 +71,18 @@ for (const [rule, entry] of Object.entries(rules)) {
groupKey = prefix
}

if (!groups.has(groupKey)) {
groups.set(groupKey, [])
const existing = groups.get(groupKey)
if (existing) {
existing.push([rule, entry])
} else {
groups.set(groupKey, [[rule, entry]])
}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
groups.get(groupKey)!.push([rule, entry])
}

// Generate markdown files per plugin in docs/
const docsDir = resolve(rootDir, 'docs')
// eslint-disable-next-line n/no-sync
rmSync(docsDir, { recursive: true, force: true })
// eslint-disable-next-line n/no-sync
mkdirSync(docsDir, { recursive: true })
await rm(docsDir, { recursive: true, force: true })
await mkdir(docsDir, { recursive: true })

const indexLines: string[] = [
'# Rules',
Expand Down Expand Up @@ -114,8 +111,8 @@ for (const [group, entries] of groups) {

lines.push('')

// eslint-disable-next-line security/detect-non-literal-fs-filename, n/no-sync
writeFileSync(resolve(docsDir, fileName), lines.join('\n'))
// eslint-disable-next-line security/detect-non-literal-fs-filename -- path is derived from rules.json keys, not user input
await writeFile(resolve(docsDir, fileName), lines.join('\n'))
const active = entries.filter(([, e]) => e.enabled).length
indexLines.push(
`- [${group}](docs/${fileName}) (${active.toString()}/${entries.length.toString()})`,
Expand All @@ -124,7 +121,7 @@ for (const [group, entries] of groups) {

indexLines.push('')

// eslint-disable-next-line n/no-sync
writeFileSync(resolve(rootDir, 'RULES.md'), indexLines.join('\n'))
const rulesMarkdownPath = resolve(rootDir, 'RULES.md')
await writeFile(rulesMarkdownPath, indexLines.join('\n'))
// eslint-disable-next-line no-console
console.log('RULES.md and docs/ generated')
7 changes: 3 additions & 4 deletions scripts/inspect-rules.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// eslint-disable-next-line import-x/no-deprecated
// eslint-disable-next-line import-x/no-deprecated -- no stable alternative for flat config
import { builtinRules } from 'eslint/use-at-your-own-risk'

// eslint-disable-next-line import-x/no-relative-parent-imports
import config, { vue2, vue3, jest, vitest, graphql, react } from '../src/index'
import config, { vue2, vue3, jest, vitest, graphql, react } from '#src/index'

import type { Linter } from 'eslint'

Expand All @@ -26,7 +25,7 @@ interface RuleEntry {
// Collect all available rules from built-in and plugins
const availableRules = new Set<string>()

// eslint-disable-next-line import-x/no-deprecated
// eslint-disable-next-line import-x/no-deprecated -- no stable alternative for flat config
for (const [name] of builtinRules) {
availableRules.add(name)
}
Expand Down
7 changes: 4 additions & 3 deletions src/modules/comments.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import pluginComments from '@eslint-community/eslint-plugin-eslint-comments'
import pluginComments, {
configs as commentsConfigs,
} from '@eslint-community/eslint-plugin-eslint-comments'

import type { Linter } from 'eslint'

const config: Linter.Config[] = [
{
plugins: { '@eslint-community/eslint-comments': pluginComments },
// eslint-disable-next-line import-x/no-named-as-default-member
rules: (pluginComments.configs.recommended as { rules: Linter.RulesRecord }).rules,
rules: (commentsConfigs.recommended as { rules: Linter.RulesRecord }).rules,
},
{
rules: {
Expand Down
6 changes: 2 additions & 4 deletions src/modules/import-x.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import pluginImportX from 'eslint-plugin-import-x'
import { flatConfigs as importXFlatConfigs } from 'eslint-plugin-import-x'
import neostandard from 'neostandard'

import type { Linter } from 'eslint'

const { plugins: _, ...importXTypescript } =
// eslint-disable-next-line import-x/no-named-as-default-member
pluginImportX.flatConfigs.typescript
const { plugins: _, ...importXTypescript } = importXFlatConfigs.typescript

const config: Linter.Config[] = [
...neostandard({ noStyle: true }),
Expand Down
2 changes: 1 addition & 1 deletion src/modules/security.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import pluginSecurity from 'eslint-plugin-security'

import type { Linter } from 'eslint'

// eslint-disable-next-line import-x/no-named-as-default-member
// eslint-disable-next-line import-x/no-named-as-default-member -- no named export available
const config: Linter.Config[] = [pluginSecurity.configs.recommended]

export default config
5 changes: 2 additions & 3 deletions src/modules/typescript.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import pluginNoCatchAll from 'eslint-plugin-no-catch-all'
import tseslint from 'typescript-eslint'
import { configs as tseslintConfigs } from 'typescript-eslint'

import type { Linter } from 'eslint'

Expand All @@ -16,8 +16,7 @@ const config: Linter.Config[] = [
},
},
},
// eslint-disable-next-line import-x/no-named-as-default-member
...(tseslint.configs.strictTypeChecked as Linter.Config[]).map((cfg) => ({
...(tseslintConfigs.strictTypeChecked as Linter.Config[]).map((cfg) => ({
...cfg,
files: ['**/*.ts', '**/*.tsx', '**/*.mts', '**/*.cts'],
})),
Expand Down
5 changes: 2 additions & 3 deletions src/modules/yaml.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import pluginYml from 'eslint-plugin-yml'
import { configs as ymlConfigs } from 'eslint-plugin-yml'

import type { Linter } from 'eslint'

// eslint-disable-next-line import-x/no-named-as-default-member
const config: Linter.Config[] = pluginYml.configs['flat/recommended']
const config: Linter.Config[] = ymlConfigs['flat/recommended']

export default config
3 changes: 1 addition & 2 deletions src/prettier.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// eslint-disable-next-line import-x/no-relative-parent-imports
import prettier from '../prettier.config'
import prettier from '#root/prettier.config'

export default prettier
7 changes: 6 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@
"outDir": "dist",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
"skipLibCheck": true,
"baseUrl": ".",
"paths": {
"#root/*": ["./*"],
"#src/*": ["./src/*"]
}
},
"include": ["src", "scripts", "*.config.ts"]
}
89 changes: 47 additions & 42 deletions vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,52 +1,57 @@
import { readdirSync } from 'node:fs'
import { readdir } from 'node:fs/promises'
import { resolve } from 'node:path'

import { defineConfig } from 'vite'
import dts from 'vite-plugin-dts'
import tsconfigPaths from 'vite-tsconfig-paths'

const modulesDir = resolve(__dirname, 'src/modules')
// eslint-disable-next-line n/no-sync
const moduleEntries = readdirSync(modulesDir)
.filter((f) => f.endsWith('.ts'))
.reduce<Record<string, string>>((acc, f) => {
const name = f.replace('.ts', '')
acc[`modules/${name}`] = resolve(modulesDir, f)
return acc
}, {})

export default defineConfig({
build: {
lib: {
entry: {
index: resolve(__dirname, 'src/index.ts'),
prettier: resolve(__dirname, 'src/prettier.ts'),
...moduleEntries,
export default defineConfig(async () => {
const files = await readdir(modulesDir)
const moduleEntries = files
.filter((f) => f.endsWith('.ts'))
.reduce<Record<string, string>>((acc, f) => {
const name = f.replace('.ts', '')
acc[`modules/${name}`] = resolve(modulesDir, f)
return acc
}, {})

return {
build: {
lib: {
entry: {
index: resolve(__dirname, 'src/index.ts'),
prettier: resolve(__dirname, 'src/prettier.ts'),
...moduleEntries,
},
formats: ['es'],
fileName: (_: string, entryName: string) => `${entryName}.js`,
},
rollupOptions: {
external: [
/^@eslint/,
/^@eslint-community/,
/^@graphql-eslint/,
/^@vue/,
/^@typescript-eslint/,
/^eslint/,
/^neostandard/,
/^typescript-eslint/,
/^prettier$/,
],
},
formats: ['es'],
fileName: (_, entryName) => `${entryName}.js`,
},
rollupOptions: {
external: [
/^@eslint/,
/^@eslint-community/,
/^@graphql-eslint/,
/^@vue/,
/^@typescript-eslint/,
/^eslint/,
/^neostandard/,
/^typescript-eslint/,
/^prettier$/,
],
},
outDir: 'dist',
emptyOutDir: true,
},
plugins: [
dts({
include: ['src/**/*.ts'],
outDir: 'dist',
entryRoot: 'src',
tsconfigPath: './tsconfig.json',
}),
],
emptyOutDir: true,
},
plugins: [
tsconfigPaths(),
dts({
include: ['src/**/*.ts'],
outDir: 'dist',
entryRoot: 'src',
tsconfigPath: './tsconfig.json',
}),
],
}
})