Skip to content

Commit

Permalink
feat: allow customize indent and quotes
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Oct 5, 2023
1 parent a76fde9 commit bbac132
Show file tree
Hide file tree
Showing 12 changed files with 253 additions and 16 deletions.
15 changes: 13 additions & 2 deletions README.md
Expand Up @@ -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
Expand Down
63 changes: 63 additions & 0 deletions 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)
83 changes: 83 additions & 0 deletions 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())
22 changes: 22 additions & 0 deletions fixtures/output/tab-double-quotes/vue-ts.vue
@@ -0,0 +1,22 @@
<script setup lang="ts">
// Define reactive data and props
import { ref } from "vue"
const greeting = ref("Hello, Vue 3!")
const counter = ref<number | string>(0)
// Define a function
function incrementCounter() {
counter.value++
}
</script>

<template>
<div>
<h1>{{ greeting }}</h1>
<button @click="incrementCounter">
Click me!
</button>
<p>Counter: {{ counter }}</p>
</div>
</template>
24 changes: 24 additions & 0 deletions fixtures/output/tab-double-quotes/vue.vue
@@ -0,0 +1,24 @@
<script setup>
// Define reactive data and props
import { ref } from "vue"
const greeting = ref(`Hello, Vue 3!${1}`)
const counter = ref(0)
// Define a function
function incrementCounter() {
counter.value++
}
</script>

<template>
<div>
<h1>
{{ greeting }}
</h1>
<button @click="incrementCounter">
Click me!
</button>
<p>Counter: {{ counter }}</p>
</div>
</template>
15 changes: 10 additions & 5 deletions 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',
Expand All @@ -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 },
Expand Down Expand Up @@ -85,15 +90,15 @@ 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'],
'style/object-property-newline': ['error', { allowMultiplePropertiesPerLine: true }],
'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 }],
Expand Down
4 changes: 2 additions & 2 deletions src/configs/typescript.ts
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
},
},
{
Expand Down
6 changes: 6 additions & 0 deletions src/configs/vue.ts
Expand Up @@ -11,6 +11,10 @@ export function vue(
stylistic = true,
} = options

const {
indent = 2,
} = typeof stylistic === 'boolean' ? {} : stylistic

return [
{
name: 'antfu:vue:setup',
Expand Down Expand Up @@ -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,
Expand Down
11 changes: 8 additions & 3 deletions src/configs/yaml.ts
Expand Up @@ -11,6 +11,11 @@ export function yaml(
stylistic = true,
} = options

const {
indent = 2,
quotes = 'single',
} = typeof stylistic === 'boolean' ? {} : stylistic

return [
{
name: 'antfu:yaml:setup',
Expand Down Expand Up @@ -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',
}
: {},
Expand Down
9 changes: 7 additions & 2 deletions src/factory.ts
Expand Up @@ -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({
Expand Down
9 changes: 7 additions & 2 deletions src/types.ts
Expand Up @@ -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 {
Expand Down Expand Up @@ -170,7 +175,7 @@ export interface OptionsConfig extends OptionsComponentExts {
*
* @default true
*/
stylistic?: boolean
stylistic?: boolean | StylisticConfig

/**
* Control to disable some rules in editors.
Expand Down
8 changes: 8 additions & 0 deletions test/fixtures.test.ts
Expand Up @@ -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(
Expand Down

0 comments on commit bbac132

Please sign in to comment.