From 6a72bf5c7cb9771086460406e731c3b5156855e6 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Wed, 27 Sep 2023 01:24:10 +0800 Subject: [PATCH] fix: install plugins globally for easy overrides --- fixtures/output/ts-override/javascript.js | 63 +++++++++++++++++ fixtures/output/ts-override/typescript.ts | 83 +++++++++++++++++++++++ fixtures/output/ts-override/vue-ts.vue | 1 + fixtures/output/ts-override/vue.vue | 1 + src/configs/jsonc.ts | 8 ++- src/configs/markdown.ts | 10 ++- src/configs/stylistic.ts | 3 +- src/configs/test.ts | 4 +- src/configs/typescript.ts | 16 ++--- src/configs/vue.ts | 8 ++- src/configs/yml.ts | 8 ++- test/fixtures.test.ts | 21 +++++- 12 files changed, 199 insertions(+), 27 deletions(-) create mode 100644 fixtures/output/ts-override/javascript.js create mode 100644 fixtures/output/ts-override/typescript.ts create mode 100644 fixtures/output/ts-override/vue-ts.vue create mode 100644 fixtures/output/ts-override/vue.vue diff --git a/fixtures/output/ts-override/javascript.js b/fixtures/output/ts-override/javascript.js new file mode 100644 index 0000000000..d518fef816 --- /dev/null +++ b/fixtures/output/ts-override/javascript.js @@ -0,0 +1,63 @@ +// This file is generated by ChatGPT + +// eslint-disable-next-line no-console +const log = console.log + +// Define a class using ES6 class syntax +class Person { + constructor(name, age) { + this.name = name + this.age = age + } + + // Define a method within the class + sayHello() { + log(`Hello, my name is ${this.name} and I am ${this.age} years old.`) + } +} + +// Create an array of objects +const people = [ + new Person('Alice', 30), + new Person('Bob', 25), + new Person('Charlie', 35), +] + +// Use the forEach method to iterate over the array +people.forEach((person) => { + person.sayHello() +}) + +// Use a template literal to create a multiline string +const multilineString = ` + This is a multiline string + that spans multiple lines. +` + +// Use destructuring assignment to extract values from an object +const { name, age } = people[0] +log(`First person in the array is ${name} and they are ${age} years old.`, multilineString) + +// Use the spread operator to create a new array +const numbers = [1, 2, 3] +const newNumbers = [...numbers, 4, 5] +log(newNumbers) + +// Use a try-catch block for error handling +try { + // Attempt to parse an invalid JSON string + JSON.parse('invalid JSON') +} +catch (error) { + console.error('Error parsing JSON:', error.message) +} + +// Use a ternary conditional operator +const isEven = num => num % 2 === 0 +const number = 7 +log(`${number} is ${isEven(number) ? 'even' : 'odd'}.`) + +// Use a callback function with setTimeout for asynchronous code +setTimeout(() => { + log('This code runs after a delay of 2 seconds.') +}, 2000) diff --git a/fixtures/output/ts-override/typescript.ts b/fixtures/output/ts-override/typescript.ts new file mode 100644 index 0000000000..38f1ec2ec3 --- /dev/null +++ b/fixtures/output/ts-override/typescript.ts @@ -0,0 +1,83 @@ +// Define a TypeScript interface +type Person = { + name: string + age: number +} + +// Create an array of objects with the defined interface +const people: Person[] = [ + { name: 'Alice', age: 30 }, + { name: 'Bob', age: 25 }, + { name: 'Charlie', age: 35 }, +] + +// eslint-disable-next-line no-console +const log = console.log + +// Use a for...of loop to iterate over the array +for (const person of people) + log(`Hello, my name is ${person.name} and I am ${person.age} years old.`) + +// Define a generic function +function identity< T >(arg: T): T { + return arg +} + +// Use the generic function with type inference +const result = identity( + 'TypeScript is awesome', +) +log(result) + +// Use optional properties in an interface +type Car = { + make: string + model?: string +} + +// Create objects using the interface +const car1: Car = { make: 'Toyota' } +const car2: Car = { + make: 'Ford', + model: 'Focus', +} + +// Use union types +type Fruit = 'apple' | 'banana' | 'orange' +const favoriteFruit: Fruit = 'apple' + +// Use a type assertion to tell TypeScript about the type +const inputValue: any = '42' +const numericValue = inputValue as number + +// Define a class with access modifiers +class Animal { + private name: string + constructor(name: string) { + this.name = name + } + + protected makeSound(sound: string) { + log(`${this.name} says ${sound}`) + } +} + +// Extend a class +class Dog extends Animal { + constructor(private alias: string) { + super(alias) + } + + bark() { + this.makeSound('Woof!') + } +} + +const dog = new Dog('Buddy') +dog.bark() + +function fn(): string { + return `hello${1}` +} + +log(car1, car2, favoriteFruit, numericValue, fn()) diff --git a/fixtures/output/ts-override/vue-ts.vue b/fixtures/output/ts-override/vue-ts.vue new file mode 100644 index 0000000000..fa9c587aaa --- /dev/null +++ b/fixtures/output/ts-override/vue-ts.vue @@ -0,0 +1 @@ +// unchanged diff --git a/fixtures/output/ts-override/vue.vue b/fixtures/output/ts-override/vue.vue new file mode 100644 index 0000000000..fa9c587aaa --- /dev/null +++ b/fixtures/output/ts-override/vue.vue @@ -0,0 +1 @@ +// unchanged diff --git a/src/configs/jsonc.ts b/src/configs/jsonc.ts index 355bdb79a7..1334b52f76 100644 --- a/src/configs/jsonc.ts +++ b/src/configs/jsonc.ts @@ -3,14 +3,16 @@ import { GLOB_JSON, GLOB_JSON5, GLOB_JSONC } from '../globs' import { parserJsonc, pluginJsonc } from '../plugins' export const jsonc: FlatESLintConfigItem[] = [ + { + plugins: { + jsonc: pluginJsonc as any, + }, + }, { files: [GLOB_JSON, GLOB_JSON5, GLOB_JSONC], languageOptions: { parser: parserJsonc, }, - plugins: { - jsonc: pluginJsonc as any, - }, rules: { 'jsonc/array-bracket-spacing': ['error', 'never'], 'jsonc/comma-dangle': ['error', 'never'], diff --git a/src/configs/markdown.ts b/src/configs/markdown.ts index 7d33f5c153..e2c82e3427 100644 --- a/src/configs/markdown.ts +++ b/src/configs/markdown.ts @@ -1,6 +1,6 @@ import type { FlatESLintConfigItem } from 'eslint-define-config' import { GLOB_MARKDOWN, GLOB_MARKDOWN_CODE } from '../globs' -import { pluginMarkdown, pluginTs } from '../plugins' +import { pluginMarkdown } from '../plugins' import { OFF } from '../flags' import type { OptionsComponentExts } from '../types' @@ -11,10 +11,12 @@ export function markdown(options: OptionsComponentExts = {}): FlatESLintConfigIt return [ { - files: [GLOB_MARKDOWN], plugins: { markdown: pluginMarkdown, }, + }, + { + files: [GLOB_MARKDOWN], processor: 'markdown/markdown', }, { @@ -29,9 +31,6 @@ export function markdown(options: OptionsComponentExts = {}): FlatESLintConfigIt }, }, }, - plugins: { - ts: pluginTs as any, - }, rules: { 'antfu/no-cjs-exports': OFF, 'antfu/no-ts-export-equal': OFF, @@ -56,7 +55,6 @@ export function markdown(options: OptionsComponentExts = {}): FlatESLintConfigIt 'ts/no-var-requires': OFF, 'unicode-bom': 'off', - 'unused-imports/no-unused-imports': OFF, 'unused-imports/no-unused-vars': OFF, }, diff --git a/src/configs/stylistic.ts b/src/configs/stylistic.ts index 2fa6bc5748..6322eb6b10 100644 --- a/src/configs/stylistic.ts +++ b/src/configs/stylistic.ts @@ -1,9 +1,10 @@ import type { FlatESLintConfigItem } from 'eslint-define-config' -import { pluginStylistic } from '../plugins' +import { pluginAntfu, pluginStylistic } from '../plugins' export const stylistic: FlatESLintConfigItem[] = [ { plugins: { + antfu: pluginAntfu, style: pluginStylistic, }, rules: { diff --git a/src/configs/test.ts b/src/configs/test.ts index bb90825395..7ae2e7b614 100644 --- a/src/configs/test.ts +++ b/src/configs/test.ts @@ -7,10 +7,12 @@ import type { OptionsIsInEditor } from '../types' export function test(options: OptionsIsInEditor = {}): FlatESLintConfigItem[] { return [ { - files: GLOB_TESTS, plugins: { 'no-only-tests': pluginNoOnlyTests, }, + }, + { + files: GLOB_TESTS, rules: { 'no-only-tests/no-only-tests': options.isInEditor ? OFF : 'error', }, diff --git a/src/configs/typescript.ts b/src/configs/typescript.ts index 8e302ac4fc..749a15967b 100644 --- a/src/configs/typescript.ts +++ b/src/configs/typescript.ts @@ -12,6 +12,14 @@ export function typescript(options?: OptionsComponentExts): FlatESLintConfigItem } = options ?? {} return [ + { + // Install the plugins without globs, so they can be configured separately. + plugins: { + antfu: pluginAntfu, + import: pluginImport, + ts: pluginTs as any, + }, + }, { files: [ GLOB_TS, @@ -24,11 +32,6 @@ export function typescript(options?: OptionsComponentExts): FlatESLintConfigItem sourceType: 'module', }, }, - plugins: { - antfu: pluginAntfu, - import: pluginImport, - ts: pluginTs as any, - }, rules: { ...renameRules( pluginTs.configs['eslint-recommended'].overrides![0].rules!, @@ -119,9 +122,6 @@ export function typescriptWithLanguageServer(options: OptionsTypeScriptWithLangu tsconfigRootDir, }, }, - plugins: { - ts: pluginTs as any, - }, rules: { 'dot-notation': OFF, 'no-implied-eval': OFF, diff --git a/src/configs/vue.ts b/src/configs/vue.ts index 8784024ac7..8d3e7f87ae 100644 --- a/src/configs/vue.ts +++ b/src/configs/vue.ts @@ -6,6 +6,11 @@ import type { OptionsHasTypeScript } from '../types' export function vue(options: OptionsHasTypeScript = {}): FlatESLintConfigItem[] { return [ + { + plugins: { + vue: pluginVue, + }, + }, { files: [GLOB_VUE], languageOptions: { @@ -19,9 +24,6 @@ export function vue(options: OptionsHasTypeScript = {}): FlatESLintConfigItem[] sourceType: 'module', }, }, - plugins: { - vue: pluginVue, - }, processor: pluginVue.processors['.vue'], rules: { ...pluginVue.configs.base.rules as any, diff --git a/src/configs/yml.ts b/src/configs/yml.ts index 3e6c5c1b29..6f89391378 100644 --- a/src/configs/yml.ts +++ b/src/configs/yml.ts @@ -4,14 +4,16 @@ import { parserYml, pluginYml } from '../plugins' import { OFF } from '../flags' export const yml: FlatESLintConfigItem[] = [ + { + plugins: { + yml: pluginYml as any, + }, + }, { files: [GLOB_YAML], languageOptions: { parser: parserYml, }, - plugins: { - yml: pluginYml as any, - }, rules: { 'style/spaced-comment': OFF, diff --git a/test/fixtures.test.ts b/test/fixtures.test.ts index a6f30aabee..a3779091be 100644 --- a/test/fixtures.test.ts +++ b/test/fixtures.test.ts @@ -3,6 +3,7 @@ import { afterAll, beforeAll, it } from 'vitest' import fs from 'fs-extra' import { execa } from 'execa' import fg from 'fast-glob' +import type { FlatESLintConfigItem } from 'eslint-define-config' import type { OptionsConfig } from '../src/types' beforeAll(async () => { @@ -21,7 +22,20 @@ runWithConfig('all', { vue: true, }) -function runWithConfig(name: string, configs: OptionsConfig) { +// https://github.com/antfu/eslint-config/issues/255 +runWithConfig( + 'ts-override', + { + typescript: true, + }, + { + rules: { + 'ts/consistent-type-definitions': ['error', 'type'], + }, + }, +) + +function runWithConfig(name: string, configs: OptionsConfig, ...items: FlatESLintConfigItem[]) { it.concurrent(name, async ({ expect }) => { const from = resolve('fixtures/input') const output = resolve('fixtures/output', name) @@ -36,7 +50,10 @@ function runWithConfig(name: string, configs: OptionsConfig) { // @eslint-disable import antfu from '@antfu/eslint-config' -export default antfu(${JSON.stringify(configs)}) +export default antfu( + ${JSON.stringify(configs)}, + ...${JSON.stringify(items) ?? []}, +) `) await execa('npx', ['eslint', '.', '--fix'], {