From bbac13209e21be4bf979427625ad559dbd4df8a1 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Thu, 5 Oct 2023 09:20:18 +0800 Subject: [PATCH] feat: allow customize indent and quotes --- README.md | 15 +++- .../output/tab-double-quotes/javascript.js | 63 ++++++++++++++ .../output/tab-double-quotes/typescript.ts | 83 +++++++++++++++++++ fixtures/output/tab-double-quotes/vue-ts.vue | 22 +++++ fixtures/output/tab-double-quotes/vue.vue | 24 ++++++ src/configs/stylistic.ts | 15 ++-- src/configs/typescript.ts | 4 +- src/configs/vue.ts | 6 ++ src/configs/yaml.ts | 11 ++- src/factory.ts | 9 +- src/types.ts | 9 +- test/fixtures.test.ts | 8 ++ 12 files changed, 253 insertions(+), 16 deletions(-) create mode 100644 fixtures/output/tab-double-quotes/javascript.js create mode 100644 fixtures/output/tab-double-quotes/typescript.ts create mode 100644 fixtures/output/tab-double-quotes/vue-ts.vue create mode 100644 fixtures/output/tab-double-quotes/vue.vue diff --git a/README.md b/README.md index 4f71dbea45..8d0ddd57c5 100644 --- a/README.md +++ b/README.md @@ -129,10 +129,21 @@ And that's it! Or you can configure each integration individually, for example: import antfu from '@antfu/eslint-config' export default antfu({ - stylistic: true, // enable stylistic formatting rules + // Enable stylistic formatting rules + // stylistic: true, + + // Or customize the stylistic rules + stylistic: { + indent: 2, // 4, or 'tab' + quotes: 'single', // or 'double' + }, + + // TypeScript and Vue are auto-detected, you can also explicitly enable them: typescript: true, vue: true, - jsonc: false, // disable jsonc support + + // Disable jsonc and yaml support + jsonc: false, yaml: false, // `.eslintignore` is no longer supported in Flat config, use `ignores` instead diff --git a/fixtures/output/tab-double-quotes/javascript.js b/fixtures/output/tab-double-quotes/javascript.js new file mode 100644 index 0000000000..54fe8971f4 --- /dev/null +++ b/fixtures/output/tab-double-quotes/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/tab-double-quotes/typescript.ts b/fixtures/output/tab-double-quotes/typescript.ts new file mode 100644 index 0000000000..6be5f7961f --- /dev/null +++ b/fixtures/output/tab-double-quotes/typescript.ts @@ -0,0 +1,83 @@ +// Define a TypeScript interface +interface 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 +interface 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/tab-double-quotes/vue-ts.vue b/fixtures/output/tab-double-quotes/vue-ts.vue new file mode 100644 index 0000000000..389ece7b4d --- /dev/null +++ b/fixtures/output/tab-double-quotes/vue-ts.vue @@ -0,0 +1,22 @@ + + + diff --git a/fixtures/output/tab-double-quotes/vue.vue b/fixtures/output/tab-double-quotes/vue.vue new file mode 100644 index 0000000000..3336cc6739 --- /dev/null +++ b/fixtures/output/tab-double-quotes/vue.vue @@ -0,0 +1,24 @@ + + + diff --git a/src/configs/stylistic.ts b/src/configs/stylistic.ts index 0a59117824..ac8ef2bea0 100644 --- a/src/configs/stylistic.ts +++ b/src/configs/stylistic.ts @@ -1,7 +1,12 @@ -import type { FlatESLintConfigItem } from '../types' +import type { FlatESLintConfigItem, StylisticConfig } from '../types' import { pluginAntfu, pluginStylistic } from '../plugins' -export function stylistic(): FlatESLintConfigItem[] { +export function stylistic(options: StylisticConfig = {}): FlatESLintConfigItem[] { + const { + indent = 2, + quotes = 'single', + } = options + return [ { name: 'antfu:stylistic', @@ -26,7 +31,7 @@ export function stylistic(): FlatESLintConfigItem[] { 'style/computed-property-spacing': ['error', 'never', { enforceForClassMembers: true }], 'style/dot-location': ['error', 'property'], 'style/eol-last': 'error', - 'style/indent': ['error', 2, { + 'style/indent': ['error', indent, { ArrayExpression: 1, CallExpression: { arguments: 1 }, FunctionDeclaration: { body: 1, parameters: 1 }, @@ -85,7 +90,7 @@ export function stylistic(): FlatESLintConfigItem[] { 'style/no-mixed-spaces-and-tabs': 'error', 'style/no-multi-spaces': 'error', 'style/no-multiple-empty-lines': ['error', { max: 1, maxBOF: 0, maxEOF: 0 }], - 'style/no-tabs': 'error', + 'style/no-tabs': indent === 'tab' ? 'off' : 'error', 'style/no-trailing-spaces': 'error', 'style/no-whitespace-before-property': 'error', 'style/object-curly-spacing': ['error', 'always'], @@ -93,7 +98,7 @@ export function stylistic(): FlatESLintConfigItem[] { 'style/operator-linebreak': ['error', 'before'], 'style/padded-blocks': ['error', { blocks: 'never', classes: 'never', switches: 'never' }], 'style/quote-props': ['error', 'consistent-as-needed'], - 'style/quotes': ['error', 'single', { allowTemplateLiterals: true, avoidEscape: true }], + 'style/quotes': ['error', quotes, { allowTemplateLiterals: true, avoidEscape: true }], 'style/rest-spread-spacing': ['error', 'never'], 'style/semi': ['error', 'never'], 'style/semi-spacing': ['error', { after: true, before: false }], diff --git a/src/configs/typescript.ts b/src/configs/typescript.ts index f618a6b281..88b54eb745 100644 --- a/src/configs/typescript.ts +++ b/src/configs/typescript.ts @@ -81,7 +81,7 @@ export function typescript( 'antfu/generic-spacing': 'error', 'antfu/named-tuple-spacing': 'error', 'antfu/no-cjs-exports': 'error', - + 'no-dupe-class-members': OFF, 'no-invalid-this': OFF, 'no-loss-of-precision': OFF, @@ -119,11 +119,11 @@ export function typescript( rules: { 'eslint-comments/no-unlimited-disable': OFF, 'import/no-duplicates': OFF, - 'unused-imports/no-unused-vars': OFF, 'no-restricted-syntax': [ 'error', '[declare=true]', ], + 'unused-imports/no-unused-vars': OFF, }, }, { diff --git a/src/configs/vue.ts b/src/configs/vue.ts index 560e1fb0b8..8eac8579ae 100644 --- a/src/configs/vue.ts +++ b/src/configs/vue.ts @@ -11,6 +11,10 @@ export function vue( stylistic = true, } = options + const { + indent = 2, + } = typeof stylistic === 'boolean' ? {} : stylistic + return [ { name: 'antfu:vue:setup', @@ -53,6 +57,8 @@ export function vue( 'vue/dot-location': ['error', 'property'], 'vue/dot-notation': ['error', { allowKeywords: true }], 'vue/eqeqeq': ['error', 'smart'], + 'vue/html-indent': ['error', indent], + 'vue/html-quotes': ['error', 'double'], 'vue/max-attributes-per-line': OFF, 'vue/multi-word-component-names': OFF, 'vue/no-dupe-keys': OFF, diff --git a/src/configs/yaml.ts b/src/configs/yaml.ts index 99dcea56f8..e7ffa569fb 100644 --- a/src/configs/yaml.ts +++ b/src/configs/yaml.ts @@ -11,6 +11,11 @@ export function yaml( stylistic = true, } = options + const { + indent = 2, + quotes = 'single', + } = typeof stylistic === 'boolean' ? {} : stylistic + return [ { name: 'antfu:yaml:setup', @@ -44,10 +49,10 @@ export function yaml( 'yaml/flow-mapping-curly-spacing': 'error', 'yaml/flow-sequence-bracket-newline': 'error', 'yaml/flow-sequence-bracket-spacing': 'error', - 'yaml/indent': ['error', 2], + 'yaml/indent': ['error', indent], 'yaml/key-spacing': 'error', - 'yaml/no-tab-indent': 'error', - 'yaml/quotes': ['error', { avoidEscape: false, prefer: 'single' }], + 'yaml/no-tab-indent': indent === 'tab' ? 'off' : 'error', + 'yaml/quotes': ['error', { avoidEscape: false, prefer: quotes }], 'yaml/spaced-comment': 'error', } : {}, diff --git a/src/factory.ts b/src/factory.ts index 08cab9587b..d82f1db525 100644 --- a/src/factory.ts +++ b/src/factory.ts @@ -98,8 +98,13 @@ export function antfu(options: OptionsConfig & FlatESLintConfigItem = {}, ...use })) } - if (enableStylistic) - configs.push(stylistic()) + if (enableStylistic) { + configs.push(stylistic( + typeof enableStylistic === 'boolean' + ? {} + : enableStylistic, + )) + } if (options.test ?? true) { configs.push(test({ diff --git a/src/types.ts b/src/types.ts index c06ba29622..8b739b73c9 100644 --- a/src/types.ts +++ b/src/types.ts @@ -99,7 +99,12 @@ export interface OptionsHasTypeScript { } export interface OptionsStylistic { - stylistic?: boolean + stylistic?: boolean | StylisticConfig +} + +export interface StylisticConfig { + indent?: number | 'tab' + quotes?: 'single' | 'double' } export interface OptionsOverrides { @@ -170,7 +175,7 @@ export interface OptionsConfig extends OptionsComponentExts { * * @default true */ - stylistic?: boolean + stylistic?: boolean | StylisticConfig /** * Control to disable some rules in editors. diff --git a/test/fixtures.test.ts b/test/fixtures.test.ts index 562ba4b000..474e5bcaa3 100644 --- a/test/fixtures.test.ts +++ b/test/fixtures.test.ts @@ -25,6 +25,14 @@ runWithConfig('no-style', { vue: true, stylistic: false, }) +runWithConfig('tab-double-quotes', { + typescript: true, + vue: true, + stylistic: { + indent: 'tab', + quotes: 'double', + }, +}) // https://github.com/antfu/eslint-config/issues/255 runWithConfig(