Skip to content

Commit 50631f4

Browse files
authored
fix: respect global ignores when scanning for vue files to lint (#239)
1 parent 286874c commit 50631f4

36 files changed

+1231
-254
lines changed

pnpm-lock.yaml

Lines changed: 362 additions & 204 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/configs.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export class TsEslintConfigForVue {
7777
toConfigArray(): FlatConfig.ConfigArray {
7878
return toArray(tseslint.configs[this.configName])
7979
.flat()
80-
.map(config => ({
80+
.map((config: FlatConfig.Config) => ({
8181
...config,
8282
...(config.files && config.files.includes('**/*.ts')
8383
? { files: [...config.files, '**/*.vue'] }

src/createConfig.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ export default function createConfig({
5151
rootDir,
5252
})
5353
return defineConfigWithVueTs(
54-
...configNamesToExtend.map(name => vueTsConfigs[name as ExtendableConfigName]),
54+
...configNamesToExtend.map(
55+
name => vueTsConfigs[name as ExtendableConfigName],
56+
),
5557
)
5658
}

src/fpHelpers.ts

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,55 @@
11
// This file is for some generic helper functions that aren't tied to the main functionality of the project.
22

3-
export function omit<T extends Record<string, any>, K extends keyof T>(obj: T, keys: K[]): Omit<T, K> {
3+
export function omit<T extends Record<string, any>, K extends keyof T>(
4+
obj: T,
5+
keys: K[],
6+
): Omit<T, K> {
47
return Object.fromEntries(
5-
Object.entries(obj).filter(([key]) => !keys.includes(key as K))
6-
) as Omit<T, K>;
8+
Object.entries(obj).filter(([key]) => !keys.includes(key as K)),
9+
) as Omit<T, K>
710
}
811

912
// https://dev.to/nexxeln/implementing-the-pipe-operator-in-typescript-30ip
1013
interface Pipe {
11-
<A>(value: A): A;
12-
<A, B>(value: A, fn1: (input: A) => B): B;
13-
<A, B, C>(value: A, fn1: (input: A) => B, fn2: (input: B) => C): C;
14+
<A>(value: A): A
15+
<A, B>(value: A, fn1: (input: A) => B): B
16+
<A, B, C>(value: A, fn1: (input: A) => B, fn2: (input: B) => C): C
1417
<A, B, C, D>(
1518
value: A,
1619
fn1: (input: A) => B,
1720
fn2: (input: B) => C,
18-
fn3: (input: C) => D
19-
): D;
21+
fn3: (input: C) => D,
22+
): D
2023
<A, B, C, D, E>(
2124
value: A,
2225
fn1: (input: A) => B,
2326
fn2: (input: B) => C,
2427
fn3: (input: C) => D,
25-
fn4: (input: D) => E
26-
): E;
28+
fn4: (input: D) => E,
29+
): E
2730
<A, B, C, D, E, F>(
2831
value: A,
2932
fn1: (input: A) => B,
3033
fn2: (input: B) => C,
3134
fn3: (input: C) => D,
3235
fn4: (input: D) => E,
33-
fn5: (input: E) => F
34-
): F;
36+
fn5: (input: E) => F,
37+
): F
38+
<A, B, C, D, E, F, G>(
39+
value: A,
40+
fn1: (input: A) => B,
41+
fn2: (input: B) => C,
42+
fn3: (input: C) => D,
43+
fn4: (input: D) => E,
44+
fn5: (input: E) => F,
45+
fn6: (input: F) => G,
46+
): G
3547
// ... and so on
3648
}
3749

3850
export const pipe: Pipe = (value: any, ...fns: Function[]): unknown => {
39-
return fns.reduce((acc, fn) => fn(acc), value);
40-
};
41-
51+
return fns.reduce((acc, fn) => fn(acc), value)
52+
}
4253

4354
export function partition<T>(
4455
array: T[],

src/groupVueFiles.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,39 @@
11
import fs from 'node:fs'
22
import fg from 'fast-glob'
33
import path from 'node:path'
4+
import { debuglog } from 'node:util'
5+
6+
const debug = debuglog('@vue/eslint-config-typescript:groupVueFiles')
47

58
type VueFilesByGroup = {
69
typeCheckable: string[]
710
nonTypeCheckable: string[]
811
}
912

10-
export default function groupVueFiles(rootDir: string): VueFilesByGroup {
13+
export default function groupVueFiles(
14+
rootDir: string,
15+
globalIgnores: string[],
16+
): VueFilesByGroup {
17+
debug(`Grouping .vue files in ${rootDir}`)
18+
19+
const ignore = [
20+
'**/node_modules/**',
21+
'**/.git/**',
22+
23+
// Global ignore patterns from ESLint config are relative to the ESLint base path,
24+
// which is usually the cwd, but could be different if `--config` is provided via CLI.
25+
// This is way too complicated, so we only use process.cwd() as a best-effort guess here.
26+
// Could be improved in the future if needed.
27+
...globalIgnores.map(pattern =>
28+
fg.convertPathToPattern(path.resolve(process.cwd(), pattern)),
29+
),
30+
]
31+
debug(`Ignoring patterns: ${ignore.join(', ')}`)
32+
1133
const { vueFilesWithScriptTs, otherVueFiles } = fg
1234
.sync(['**/*.vue'], {
1335
cwd: rootDir,
14-
ignore: ['**/node_modules/**'],
36+
ignore,
1537
})
1638
.reduce(
1739
(acc, file) => {

src/index.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
export {
2-
defineConfigWithVueTs,
3-
configureVueProject,
4-
} from './utilities'
1+
export { defineConfigWithVueTs, configureVueProject } from './utilities'
52
export { vueTsConfigs } from './configs'
63

74
// Compatibility layer for the `createConfig` function in <= 14.2.0

src/utilities.ts

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import process from 'node:process'
22
import tseslint from 'typescript-eslint'
33
import type { TSESLint } from '@typescript-eslint/utils'
4+
import type { FlatConfig } from '@typescript-eslint/utils/ts-eslint'
45
import pluginVue from 'eslint-plugin-vue'
56

67
import { TsEslintConfigForVue } from './configs'
@@ -43,16 +44,16 @@ export type ProjectOptions = {
4344
/**
4445
* Whether to override some `no-unsafe-*` rules to avoid false positives on Vue component operations.
4546
* Defaults to `true`.
46-
*
47+
*
4748
* Due to limitations in the integration between Vue and TypeScript-ESLint,
4849
* TypeScript-ESLint cannot get the full type information for `.vue` files
4950
* and will use fallback types that contain some `any`s.
5051
* Therefore, some `no-unsafe-*` rules will error on functions that operate on Vue components,
5152
* such as `createApp`, `createRouter`, `useTemplateRef`, etc.
52-
*
53+
*
5354
* Setting this option to `true` will override those `no-unsafe-*` rules
5455
* to allow these patterns in the project.
55-
*
56+
*
5657
* If you're using a metaframework such as Nuxt or Quasar
5758
* that handles app creation & router configuration for you,
5859
* you might not need to interact with component types directly.
@@ -82,7 +83,8 @@ export function configureVueProject(userOptions: ProjectOptions): void {
8283
projectOptions.tsSyntaxInTemplates = userOptions.tsSyntaxInTemplates
8384
}
8485
if (userOptions.allowComponentTypeUnsafety !== undefined) {
85-
projectOptions.allowComponentTypeUnsafety = userOptions.allowComponentTypeUnsafety
86+
projectOptions.allowComponentTypeUnsafety =
87+
userOptions.allowComponentTypeUnsafety
8688
}
8789
if (userOptions.scriptLangs) {
8890
projectOptions.scriptLangs = userOptions.scriptLangs
@@ -104,6 +106,7 @@ export function defineConfigWithVueTs(
104106
return pipe(
105107
configs,
106108
flattenConfigs,
109+
collectGlobalIgnores,
107110
deduplicateVuePlugin,
108111
insertAndReorderConfigs,
109112
resolveVueTsConfigs,
@@ -165,6 +168,29 @@ function flattenConfigs(
165168
)
166169
}
167170

171+
let globalIgnores: string[] = []
172+
173+
/**
174+
* Fields that are considered metadata and not part of the config object.
175+
*/
176+
const META_FIELDS = new Set(['name', 'basePath'])
177+
178+
function collectGlobalIgnores(configs: RawConfigItem[]): RawConfigItem[] {
179+
configs.forEach(config => {
180+
if (config instanceof TsEslintConfigForVue) return
181+
182+
if (!config.ignores) return
183+
184+
if (Object.keys(config).filter(key => !META_FIELDS.has(key)).length !== 1)
185+
return
186+
187+
// Configs that only contain `ignores` (and possibly `name`/`basePath`) are treated as global ignores
188+
globalIgnores.push(...config.ignores)
189+
})
190+
191+
return configs
192+
}
193+
168194
function resolveVueTsConfigs(configs: RawConfigItem[]): ConfigItem[] {
169195
return configs.flatMap(config =>
170196
config instanceof TsEslintConfigForVue ? config.toConfigArray() : config,
@@ -206,7 +232,7 @@ function insertAndReorderConfigs(configs: RawConfigItem[]): RawConfigItem[] {
206232
return configs
207233
}
208234

209-
const vueFiles = groupVueFiles(projectOptions.rootDir)
235+
const vueFiles = groupVueFiles(projectOptions.rootDir, globalIgnores)
210236
const configsWithoutTypeAwareRules = configs.map(extractTypeAwareRules)
211237

212238
const hasTypeAwareConfigs = configs.some(
@@ -233,7 +259,10 @@ function insertAndReorderConfigs(configs: RawConfigItem[]): RawConfigItem[] {
233259
...(needsTypeAwareLinting
234260
? [
235261
...createSkipTypeCheckingConfigs(vueFiles.nonTypeCheckable),
236-
...createTypeCheckingConfigs(vueFiles.typeCheckable, projectOptions.allowComponentTypeUnsafety),
262+
...createTypeCheckingConfigs(
263+
vueFiles.typeCheckable,
264+
projectOptions.allowComponentTypeUnsafety,
265+
),
237266
]
238267
: []),
239268

@@ -269,7 +298,7 @@ function extractTypeAwareRules(config: RawConfigItem): RawConfigItem {
269298
}
270299

271300
const rulesRequiringTypeInformation = new Set(
272-
Object.entries(tseslint.plugin.rules!)
301+
Object.entries((tseslint.plugin as FlatConfig.Plugin).rules!)
273302
// @ts-expect-error
274303
.filter(([_name, def]) => def?.meta?.docs?.requiresTypeChecking)
275304
.map(([name, _def]) => `@typescript-eslint/${name}`)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue,css,scss,sass,less,styl}]
2+
charset = utf-8
3+
indent_size = 2
4+
indent_style = space
5+
insert_final_newline = true
6+
trim_trailing_whitespace = true
7+
end_of_line = lf
8+
max_line_length = 100
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* text=auto eol=lf
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
.DS_Store
12+
dist
13+
dist-ssr
14+
coverage
15+
*.local
16+
17+
# Editor directories and files
18+
.vscode/*
19+
!.vscode/extensions.json
20+
.idea
21+
*.suo
22+
*.ntvs*
23+
*.njsproj
24+
*.sln
25+
*.sw?
26+
27+
*.tsbuildinfo
28+
29+
.eslintcache
30+
31+
# Cypress
32+
/cypress/videos/
33+
/cypress/screenshots/
34+
35+
# Vitest
36+
__screenshots__/

0 commit comments

Comments
 (0)