Skip to content

Commit

Permalink
feat: new ESLint config API
Browse files Browse the repository at this point in the history
BREAKING CHANGE: eslint configs is changed. We made it full configurable of ESLint and remove all the hard coding config properties in 0.3.x. Now, you are allowed to write lint command which you're more familar with rather than JS config.
  • Loading branch information
fi3ework committed Feb 6, 2022
1 parent 57c9e84 commit aace273
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 61 deletions.
1 change: 1 addition & 0 deletions packages/vite-plugin-checker/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"@types/eslint": "^7.2.14",
"@types/lodash.debounce": "^4.0.6",
"@types/lodash.pick": "^4.4.6",
"optionator": "^0.9.1",
"vls": "^0.7.2"
}
}
76 changes: 76 additions & 0 deletions packages/vite-plugin-checker/src/checkers/eslint/cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/* eslint-disable */

// Copied from /eslint@7.28.0/node_modules/eslint/lib/cli.js

function quietFixPredicate(message) {
return message.severity === 2
}

export function translateOptions({
cache,
cacheFile,
cacheLocation,
cacheStrategy,
config,
env,
errorOnUnmatchedPattern,
eslintrc,
ext,
fix,
fixDryRun,
fixType,
global,
ignore,
ignorePath,
ignorePattern,
inlineConfig,
parser,
parserOptions,
plugin,
quiet,
reportUnusedDisableDirectives,
resolvePluginsRelativeTo,
rule,
rulesdir,
}) {
return {
allowInlineConfig: inlineConfig,
cache,
cacheLocation: cacheLocation || cacheFile,
cacheStrategy,
errorOnUnmatchedPattern,
extensions: ext,
fix: (fix || fixDryRun) && (quiet ? quietFixPredicate : true),
fixTypes: fixType,
ignore,
ignorePath,
overrideConfig: {
env:
env &&
env.reduce((obj, name) => {
obj[name] = true
return obj
}, {}),
globals:
global &&
global.reduce((obj, name) => {
if (name.endsWith(':true')) {
obj[name.slice(0, -5)] = 'writable'
} else {
obj[name] = 'readonly'
}
return obj
}, {}),
ignorePatterns: ignorePattern,
parser,
parserOptions,
plugins: plugin,
rules: rule,
},
overrideConfigFile: config,
reportUnusedDisableDirectives: reportUnusedDisableDirectives ? 'error' : void 0,
resolvePluginsRelativeTo,
rulePaths: rulesdir,
useEslintrc: eslintrc,
}
}
76 changes: 36 additions & 40 deletions packages/vite-plugin-checker/src/checkers/eslint/main.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import chokidar from 'chokidar'
import { ESLint } from 'eslint'
// @ts-ignore
import optionator from 'eslint/lib/options'
import path from 'path'
import invariant from 'tiny-invariant'
import { parentPort } from 'worker_threads'
import chokidar from 'chokidar'

import { Checker } from '../../Checker'
import {
Expand All @@ -13,6 +15,7 @@ import {
normalizeEslintDiagnostic,
} from '../../logger'
import { ACTION_TYPES } from '../../types'
import { translateOptions } from './cli'

import type { CreateDiagnostic } from '../../types'
const createDiagnostic: CreateDiagnostic<'eslint'> = (pluginConfig) => {
Expand All @@ -28,25 +31,32 @@ const createDiagnostic: CreateDiagnostic<'eslint'> = (pluginConfig) => {
async configureServer({ root }) {
if (!pluginConfig.eslint) return

const extensions = pluginConfig.eslint.extensions ?? ['.js']
const overrideConfigFile = pluginConfig.eslint.configFile
? { overrideConfigFile: pluginConfig.eslint.configFile }
: {}
const options = optionator.parse(pluginConfig.eslint.lintCommand)
const translatedOptions = translateOptions(options) as ESLint.Options

// const extensions = config.extensions ?? ['.js']
// const overrideConfigFile = pluginConfig.eslint.configFile
// ? { overrideConfigFile: pluginConfig.eslint.configFile }
// : {}
const eslint = new ESLint({
cwd: root,
extensions,
...overrideConfigFile,
...translatedOptions,
...pluginConfig.eslint.devOptions,
// extensions,
// ...overrideConfigFile,
})
invariant(pluginConfig.eslint, 'config.eslint should not be `false`')
invariant(
pluginConfig.eslint.files,
`eslint.files is required, but got ${pluginConfig.eslint.files}`
)

const paths =
typeof pluginConfig.eslint.files === 'string'
? [pluginConfig.eslint.files]
: pluginConfig.eslint.files
// invariant(pluginConfig.eslint, 'config.eslint should not be `false`')
// invariant(
// pluginConfig.eslint.files,
// `eslint.files is required, but got ${pluginConfig.eslint.files}`
// )

// const paths =
// typeof pluginConfig.eslint.files === 'string'
// ? [pluginConfig.eslint.files]
// : pluginConfig.eslint.files
// const paths = config.

let diagnosticsCache: NormalizedDiagnostic[] = []

Expand All @@ -71,12 +81,13 @@ const createDiagnostic: CreateDiagnostic<'eslint'> = (pluginConfig) => {
}

const handleFileChange = async (filePath: string, type: 'change' | 'unlink') => {
if (!extensions.includes(path.extname(filePath))) return
// if (!extensions.includes(path.extname(filePath))) return

if (type === 'unlink') {
const absPath = path.resolve(root, filePath)
diagnosticsCache = diagnosticsCache.filter((d) => d.id !== absPath)
} else if (type === 'change') {
console.log(filePath)
const diagnosticsOfChangedFile = await eslint.lintFiles(filePath)
const newDiagnostics = diagnosticsOfChangedFile
.map((d) => normalizeEslintDiagnostic(d))
Expand All @@ -89,7 +100,8 @@ const createDiagnostic: CreateDiagnostic<'eslint'> = (pluginConfig) => {
}

// initial lint
const diagnostics = await eslint.lintFiles(paths)
const files = options._.slice(1)
const diagnostics = await eslint.lintFiles(files)
diagnosticsCache = diagnostics.map((p) => normalizeEslintDiagnostic(p)).flat(1)
dispatchDiagnostics()

Expand All @@ -98,7 +110,7 @@ const createDiagnostic: CreateDiagnostic<'eslint'> = (pluginConfig) => {
cwd: root,
ignored: (path: string) => path.includes('node_modules'),
})
watcher.add(paths)
watcher.add(files)
watcher.on('change', async (filePath) => {
handleFileChange(filePath, 'change')
})
Expand All @@ -116,29 +128,13 @@ export class EslintChecker extends Checker<'eslint'> {
absFilePath: __filename,
build: {
buildBin: (pluginConfig) => {
let ext = ['.js']
let files: string[] = []
let overrideConfigFile: string[] = []
let maxWarnings = ''

if (pluginConfig.eslint) {
ext = pluginConfig.eslint.extensions ?? ext
if (pluginConfig.eslint.maxWarnings !== undefined) {
maxWarnings = `--max-warnings=${pluginConfig.eslint.maxWarnings}`
}
files =
typeof pluginConfig.eslint.files === 'string'
? [pluginConfig.eslint.files]
: pluginConfig.eslint.files
overrideConfigFile = pluginConfig.eslint.configFile
? ['--config', pluginConfig.eslint.configFile]
: []
}
const { lintCommand } = pluginConfig.eslint
// const { _ } = cmdToOptions(lintCommand)

return [
'eslint',
['--ext', ext.join(','), maxWarnings, ...overrideConfigFile, ...files].filter(Boolean),
]
return ['eslint', lintCommand.split(' ').slice(1)]
}
return ['eslint', ['']]
},
},
createDiagnostic,
Expand Down
51 changes: 32 additions & 19 deletions packages/vite-plugin-checker/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { HMRPayload, ServerOptions, ConfigEnv } from 'vite'
import type { Worker } from 'worker_threads'
import type { ESLint } from 'eslint'

/* ----------------------------- userland plugin options ----------------------------- */

Expand Down Expand Up @@ -33,29 +34,41 @@ export type VlsConfig =
export type EslintConfig =
| false
| {
/** The lint target files. This can contain any of file paths, directory paths, and glob patterns. ([Details](https://eslint.org/docs/developer-guide/nodejs-api#parameters-1)). */
files: string | string[]
/**
* Specify linted file extensions, 'extensions' must be an array of non-empty strings, e.g. `['.jsx', '.js']`. ([Details](https://eslint.org/docs/developer-guide/nodejs-api#parameters)).
* @defaultValue: ['.js']
* lintCommand will be executed at build mode, and will also be used as
* default config for dev mode when options.eslint.devOptions.eslint is nullable.
*/
extensions?: string[]
/**
* millisecond for watcher to wait to trigger re-lint
* @defaultValue: 300
*/
// watchDelay?: number
/**
* Specify path to ESLint config file, if you wish to override ESLint's default configuration discovery.
* Equivalent to ESLint's "--config" option.
*/
configFile?: string
/*
* Fail a build if there are more than this many warnings.
*/
maxWarnings?: number
lintCommand: string
devOptions?: {
/** You can override the options of translated from lintCommand. */
eslint?: ESLint.Options
}
}

// {
// /** The lint target files. This can contain any of file paths, directory paths, and glob patterns. ([Details](https://eslint.org/docs/developer-guide/nodejs-api#parameters-1)). */
// files: string | string[]
// /**
// * Specify linted file extensions, 'extensions' must be an array of non-empty strings, e.g. `['.jsx', '.js']`. ([Details](https://eslint.org/docs/developer-guide/nodejs-api#parameters)).
// * @defaultValue: ['.js']
// */
// extensions?: string[]
// /**
// * millisecond for watcher to wait to trigger re-lint
// * @defaultValue: 300
// */
// // watchDelay?: number
// /**
// * Specify path to ESLint config file, if you wish to override ESLint's default configuration discovery.
// * Equivalent to ESLint's "--config" option.
// */
// configFile?: string
// /*
// * Fail a build if there are more than this many warnings.
// */
// maxWarnings?: number
// }

/** checkers shared configuration */
export interface SharedConfig {
/**
Expand Down
3 changes: 1 addition & 2 deletions playground/vanilla-ts/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ export default defineConfig({
reactRefresh(),
checker({
eslint: {
files: ['./src'],
extensions: ['.ts'],
lintCommand: 'eslint ./src --ext .ts',
},
}),
],
Expand Down
2 changes: 2 additions & 0 deletions pnpm-lock.yaml

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

1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"compilerOptions": {
"allowJs": true,
"target": "ES2015",
"lib": ["ESNext"],
"module": "CommonJS",
Expand Down

0 comments on commit aace273

Please sign in to comment.