diff --git a/eslint.config.js b/eslint.config.js index 149f951..386c61a 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -2,4 +2,10 @@ // eslint-disable-next-line antfu/no-import-dist import { xwbx } from "./dist/index.js"; -export default xwbx({ typescript: true, vue: true, astro: true, unocss: true }); +export default xwbx({ + ignores: ["fixtures"], + typescript: true, + vue: true, + astro: true, + unocss: true, +}); diff --git a/fixtures/input/astro.astro b/fixtures/input/astro.astro new file mode 100644 index 0000000..df4e8e5 --- /dev/null +++ b/fixtures/input/astro.astro @@ -0,0 +1,21 @@ +--- +const isJsx = true +const content = "hi!"; +--- + +
+
{content}
+
+ {isJsx && ( +

{content}

+ )} +
+
+ + + diff --git a/fixtures/input/css.css b/fixtures/input/css.css new file mode 100644 index 0000000..12a4724 --- /dev/null +++ b/fixtures/input/css.css @@ -0,0 +1,10 @@ +@media (max-width: 480px) { + .bd-examples {margin-right: -.75rem;margin-left: -.75rem + } + + .bd-examples>[class^="col-"] { + padding-right: .75rem; + padding-left: .75rem; + + } +} diff --git a/fixtures/input/html.html b/fixtures/input/html.html new file mode 100644 index 0000000..1516dca --- /dev/null +++ b/fixtures/input/html.html @@ -0,0 +1,17 @@ + + + + + My tITlE + + + +

Hello world!
This is HTML5 Boilerplate.

+ + + + diff --git a/fixtures/input/javascript.js b/fixtures/input/javascript.js new file mode 100644 index 0000000..ab9c71f --- /dev/null +++ b/fixtures/input/javascript.js @@ -0,0 +1,72 @@ +// This file is generated by ChatGPT + +// eslint-disable-next-line no-console +var 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); + +let a, b, c, d, foo + +if (a + || b + || c || d + || (d && b) + ) { + foo() + } diff --git a/fixtures/input/jsx.jsx b/fixtures/input/jsx.jsx new file mode 100644 index 0000000..d5adb05 --- /dev/null +++ b/fixtures/input/jsx.jsx @@ -0,0 +1,21 @@ +export function HelloWorld({ + greeting = "hello", greeted = '"World"', silent = false, onMouseOver,}) { + + if(!greeting){ + return null}; + + // TODO: Don't use random in render + let num = Math.floor (Math.random() * 1E+7).toString() + .replace(/\.\d+/ig, "") + + return
+ { greeting.slice( 0, 1 ).toUpperCase() + greeting.slice(1).toLowerCase() } + {greeting.endsWith(",") + ? " " : ", " } + + { greeted } + + { (silent)? ".": "!"} +
; + +} diff --git a/fixtures/input/markdown.md b/fixtures/input/markdown.md new file mode 100644 index 0000000..a7f61a3 --- /dev/null +++ b/fixtures/input/markdown.md @@ -0,0 +1,35 @@ +Header +====== + +_Look,_ code blocks are formatted *too!* + +```js +// This should be handled by ESLint instead of Prettier +function identity(x) { + if (foo) { + console.log('bar'); + } + } +``` + +```css +/* This should be handled by Prettier */ +.foo { color:red;} +``` + +Pilot|Airport|Hours +--|:--:|--: +John Doe|SKG|1338 +Jane Roe|JFK|314 + +- - - - - - - - - - - - - - - + ++ List + + with a [link] (/to/somewhere) ++ and [another one] + + + [another one]: http://example.com 'Example title' + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. +Curabitur consectetur maximus risus, sed maximus tellus tincidunt et. diff --git a/fixtures/input/svelte.svelte b/fixtures/input/svelte.svelte new file mode 100644 index 0000000..bf114b9 --- /dev/null +++ b/fixtures/input/svelte.svelte @@ -0,0 +1,8 @@ + + +
+ +
{@html content}
+
\ No newline at end of file diff --git a/fixtures/input/toml.toml b/fixtures/input/toml.toml new file mode 100644 index 0000000..31e10f1 --- /dev/null +++ b/fixtures/input/toml.toml @@ -0,0 +1,24 @@ +comma = [ + 1 + ,2 + ,3, +] + +[foo] + b = 1 + c = "hello" + a = {answer = 42} + +"indent" = [ +1, + 2 +] + +['a-table'] +apple.type = "fruit" +orange.type = "fruit" +apple.skin = "thin" +orange.skin = "thick" + +apple.color = "red" +orange.color = "orange" diff --git a/fixtures/input/tsconfig.json b/fixtures/input/tsconfig.json new file mode 100644 index 0000000..66372fb --- /dev/null +++ b/fixtures/input/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "skipDefaultLibCheck": true, + "skipLibCheck": true + } +} diff --git a/fixtures/input/tsx.tsx b/fixtures/input/tsx.tsx new file mode 100644 index 0000000..97ca089 --- /dev/null +++ b/fixtures/input/tsx.tsx @@ -0,0 +1,24 @@ +export function Component1() { + return
; +} + +export function jsx2() { + const props = {a:1, + b:2} + return < a foo= 'bar' bar={`foo` } > +
Inline Text
+ + Block Text + +
+ Mixed +
Foo
+ Text Bar +
+

+ foobarbaz +

+ +} diff --git a/fixtures/input/typescript.ts b/fixtures/input/typescript.ts new file mode 100644 index 0000000..97bbe6d --- /dev/null +++ b/fixtures/input/typescript.ts @@ -0,0 +1,80 @@ +// 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 +var 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(); + +var fn = (): string => { + return 'hello' + 1 +} + +log(car1, car2, favoriteFruit, numericValue, fn()) + diff --git a/fixtures/input/vue-ts.vue b/fixtures/input/vue-ts.vue new file mode 100644 index 0000000..61ed8c6 --- /dev/null +++ b/fixtures/input/vue-ts.vue @@ -0,0 +1,34 @@ + + + + + + + diff --git a/fixtures/input/vue.vue b/fixtures/input/vue.vue new file mode 100644 index 0000000..b540d06 --- /dev/null +++ b/fixtures/input/vue.vue @@ -0,0 +1,24 @@ + + + diff --git a/fixtures/input/xml.xml b/fixtures/input/xml.xml new file mode 100644 index 0000000..8fbc57b --- /dev/null +++ b/fixtures/input/xml.xml @@ -0,0 +1,9 @@ + +Effective Java45.00 + Bluetooth Speaker120.00 + Clean Code + 33.50 + + + + diff --git a/fixtures/output/all/astro.astro b/fixtures/output/all/astro.astro new file mode 100644 index 0000000..fb1c8f9 --- /dev/null +++ b/fixtures/output/all/astro.astro @@ -0,0 +1,18 @@ +--- +const isJsx = true; +const content = "hi!"; +--- + +
+
{content}
+
+ {isJsx &&

{content}

} +
+
+ + diff --git a/fixtures/output/all/css.css b/fixtures/output/all/css.css new file mode 100644 index 0000000..077c760 --- /dev/null +++ b/fixtures/output/all/css.css @@ -0,0 +1,11 @@ +@media (max-width: 480px) { + .bd-examples { + margin-right: -0.75rem; + margin-left: -0.75rem; + } + + .bd-examples > [class^="col-"] { + padding-right: 0.75rem; + padding-left: 0.75rem; + } +} diff --git a/fixtures/output/all/html.html b/fixtures/output/all/html.html new file mode 100644 index 0000000..30e8a3a --- /dev/null +++ b/fixtures/output/all/html.html @@ -0,0 +1,28 @@ + + + + + My tITlE + + + +

+ Hello world!
+ This is HTML5 Boilerplate. +

+ + + + diff --git a/fixtures/output/all/javascript.js b/fixtures/output/all/javascript.js new file mode 100644 index 0000000..eda3378 --- /dev/null +++ b/fixtures/output/all/javascript.js @@ -0,0 +1,71 @@ +// This file is generated by ChatGPT + +// eslint-disable-next-line no-console +var 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); + +let a, b, c, d, foo; + +if (a || b || c || d || (d && b)) { + foo(); +} diff --git a/fixtures/output/all/jsx.jsx b/fixtures/output/all/jsx.jsx new file mode 100644 index 0000000..250b285 --- /dev/null +++ b/fixtures/output/all/jsx.jsx @@ -0,0 +1,34 @@ +export function HelloWorld({ + greeting = "hello", + greeted = '"World"', + silent = false, + onMouseOver, +}) { + if (!greeting) { + return null; + } + + // TODO: Don't use random in render + let num = Math.floor(Math.random() * 1e7) + .toString() + .replace(/\.\d+/gi, ""); + + return ( +
+ + {greeting.slice(0, 1).toUpperCase() + greeting.slice(1).toLowerCase()} + + {greeting.endsWith(",") ? ( + " " + ) : ( + ", " + )} + {greeted} + {silent ? "." : "!"} +
+ ); +} diff --git a/fixtures/output/all/markdown.md b/fixtures/output/all/markdown.md new file mode 100644 index 0000000..6b24021 --- /dev/null +++ b/fixtures/output/all/markdown.md @@ -0,0 +1,35 @@ +# Header + +_Look,_ code blocks are formatted _too!_ + +```js +// This should be handled by ESLint instead of Prettier +function identity(x) { + if (foo) { + console.log("bar"); + } +} +``` + +```css +/* This should be handled by Prettier */ +.foo { + color: red; +} +``` + +| Pilot | Airport | Hours | +| -------- | :-----: | ----: | +| John Doe | SKG | 1338 | +| Jane Roe | JFK | 314 | + +--- + +- List +- with a [link] (/to/somewhere) +- and [another one] + + [another one]: http://example.com "Example title" + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. +Curabitur consectetur maximus risus, sed maximus tellus tincidunt et. diff --git a/fixtures/output/all/toml.toml b/fixtures/output/all/toml.toml new file mode 100644 index 0000000..a28003c --- /dev/null +++ b/fixtures/output/all/toml.toml @@ -0,0 +1,23 @@ +comma = [ + 1, + 2, + 3, +] + +[foo] + b = 1 + c = "hello" + a = {answer = 42} + +"indent" = [ +1, + 2 +] + +['a-table'] +apple.type = "fruit" +apple.skin = "thin" +apple.color = "red" +orange.type = "fruit" +orange.skin = "thick" +orange.color = "orange" diff --git a/fixtures/output/all/tsx.tsx b/fixtures/output/all/tsx.tsx new file mode 100644 index 0000000..6fa1309 --- /dev/null +++ b/fixtures/output/all/tsx.tsx @@ -0,0 +1,24 @@ +export function Component1() { + return
; +} + +export function jsx2() { + const props = { a: 1, b: 2 }; + return ( + +
+ Inline Text +
+ Block Text +
+ Mixed +
Foo
+ Text Bar +
+

+ foobar + baz +

+
+ ); +} diff --git a/fixtures/output/all/typescript.ts b/fixtures/output/all/typescript.ts new file mode 100644 index 0000000..1ef3132 --- /dev/null +++ b/fixtures/output/all/typescript.ts @@ -0,0 +1,80 @@ +// 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(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/all/vue-ts.vue b/fixtures/output/all/vue-ts.vue new file mode 100644 index 0000000..9772479 --- /dev/null +++ b/fixtures/output/all/vue-ts.vue @@ -0,0 +1,36 @@ + + + + + + + diff --git a/fixtures/output/all/vue.vue b/fixtures/output/all/vue.vue new file mode 100644 index 0000000..aeca5aa --- /dev/null +++ b/fixtures/output/all/vue.vue @@ -0,0 +1,25 @@ + + + diff --git a/fixtures/output/no-style/astro.astro b/fixtures/output/no-style/astro.astro new file mode 100644 index 0000000..14bedf6 --- /dev/null +++ b/fixtures/output/no-style/astro.astro @@ -0,0 +1,21 @@ +--- +const isJsx = true +const content = "hi!"; +--- + +
+
{content}
+
+ {isJsx && ( +

{content}

+ )} +
+
+ + + diff --git a/fixtures/output/no-style/javascript.js b/fixtures/output/no-style/javascript.js new file mode 100644 index 0000000..bf2406e --- /dev/null +++ b/fixtures/output/no-style/javascript.js @@ -0,0 +1,72 @@ +// 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 +for (const person of people) { + 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); + +let a, b, c, d, foo + +if (a + || b + || c || d + || (d && b) + ) { + foo() + } diff --git a/fixtures/output/no-style/jsx.jsx b/fixtures/output/no-style/jsx.jsx new file mode 100644 index 0000000..f5f1f2c --- /dev/null +++ b/fixtures/output/no-style/jsx.jsx @@ -0,0 +1,21 @@ +export function HelloWorld({ + greeting = "hello", greeted = '"World"', silent = false, onMouseOver,}) { + + if(!greeting){ + return null}; + + // TODO: Don't use random in render + const num = Math.floor (Math.random() * 1E+7).toString() + .replaceAll(/\.\d+/g, "") + + return
+ { greeting.slice( 0, 1 ).toUpperCase() + greeting.slice(1).toLowerCase() } + {greeting.endsWith(",") + ? " " : ", " } + + { greeted } + + { (silent)? ".": "!"} +
; + +} diff --git a/fixtures/output/no-style/toml.toml b/fixtures/output/no-style/toml.toml new file mode 100644 index 0000000..a28003c --- /dev/null +++ b/fixtures/output/no-style/toml.toml @@ -0,0 +1,23 @@ +comma = [ + 1, + 2, + 3, +] + +[foo] + b = 1 + c = "hello" + a = {answer = 42} + +"indent" = [ +1, + 2 +] + +['a-table'] +apple.type = "fruit" +apple.skin = "thin" +apple.color = "red" +orange.type = "fruit" +orange.skin = "thick" +orange.color = "orange" diff --git a/fixtures/output/no-style/typescript.ts b/fixtures/output/no-style/typescript.ts new file mode 100644 index 0000000..18c8252 --- /dev/null +++ b/fixtures/output/no-style/typescript.ts @@ -0,0 +1,80 @@ +// 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/no-style/vue-ts.vue b/fixtures/output/no-style/vue-ts.vue new file mode 100644 index 0000000..f55c567 --- /dev/null +++ b/fixtures/output/no-style/vue-ts.vue @@ -0,0 +1,34 @@ + + + + + + + diff --git a/fixtures/output/no-style/vue.vue b/fixtures/output/no-style/vue.vue new file mode 100644 index 0000000..e0774d6 --- /dev/null +++ b/fixtures/output/no-style/vue.vue @@ -0,0 +1,24 @@ + + + diff --git a/fixtures/output/tab-single-quotes/astro.astro b/fixtures/output/tab-single-quotes/astro.astro new file mode 100644 index 0000000..5f25d96 --- /dev/null +++ b/fixtures/output/tab-single-quotes/astro.astro @@ -0,0 +1,18 @@ +--- +const isJsx = true; +const content = 'hi!'; +--- + +
+
{content}
+
+ {isJsx &&

{content}

} +
+
+ + diff --git a/fixtures/output/tab-single-quotes/css.css b/fixtures/output/tab-single-quotes/css.css new file mode 100644 index 0000000..5f19626 --- /dev/null +++ b/fixtures/output/tab-single-quotes/css.css @@ -0,0 +1,11 @@ +@media (max-width: 480px) { + .bd-examples { + margin-right: -0.75rem; + margin-left: -0.75rem; + } + + .bd-examples > [class^='col-'] { + padding-right: 0.75rem; + padding-left: 0.75rem; + } +} diff --git a/fixtures/output/tab-single-quotes/html.html b/fixtures/output/tab-single-quotes/html.html new file mode 100644 index 0000000..aaa5e79 --- /dev/null +++ b/fixtures/output/tab-single-quotes/html.html @@ -0,0 +1,28 @@ + + + + + My tITlE + + + +

+ Hello world!
+ This is HTML5 Boilerplate. +

+ + + + diff --git a/fixtures/output/tab-single-quotes/javascript.js b/fixtures/output/tab-single-quotes/javascript.js new file mode 100644 index 0000000..096216e --- /dev/null +++ b/fixtures/output/tab-single-quotes/javascript.js @@ -0,0 +1,71 @@ +// This file is generated by ChatGPT + +// eslint-disable-next-line no-console +var 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); + +let a, b, c, d, foo; + +if (a || b || c || d || (d && b)) { + foo(); +} diff --git a/fixtures/output/tab-single-quotes/jsx.jsx b/fixtures/output/tab-single-quotes/jsx.jsx new file mode 100644 index 0000000..4d403d1 --- /dev/null +++ b/fixtures/output/tab-single-quotes/jsx.jsx @@ -0,0 +1,34 @@ +export function HelloWorld({ + greeting = 'hello', + greeted = '"World"', + silent = false, + onMouseOver, +}) { + if (!greeting) { + return null; + } + + // TODO: Don't use random in render + let num = Math.floor(Math.random() * 1e7) + .toString() + .replace(/\.\d+/gi, ''); + + return ( +
+ + {greeting.slice(0, 1).toUpperCase() + greeting.slice(1).toLowerCase()} + + {greeting.endsWith(',') ? ( + ' ' + ) : ( + ", " + )} + {greeted} + {silent ? '.' : '!'} +
+ ); +} diff --git a/fixtures/output/tab-single-quotes/markdown.md b/fixtures/output/tab-single-quotes/markdown.md new file mode 100644 index 0000000..7eceb11 --- /dev/null +++ b/fixtures/output/tab-single-quotes/markdown.md @@ -0,0 +1,35 @@ +# Header + +_Look,_ code blocks are formatted _too!_ + +```js +// This should be handled by ESLint instead of Prettier +function identity(x) { + if (foo) { + console.log('bar'); + } +} +``` + +```css +/* This should be handled by Prettier */ +.foo { + color: red; +} +``` + +| Pilot | Airport | Hours | +| -------- | :-----: | ----: | +| John Doe | SKG | 1338 | +| Jane Roe | JFK | 314 | + +--- + +- List +- with a [link] (/to/somewhere) +- and [another one] + + [another one]: http://example.com 'Example title' + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. +Curabitur consectetur maximus risus, sed maximus tellus tincidunt et. diff --git a/fixtures/output/tab-single-quotes/toml.toml b/fixtures/output/tab-single-quotes/toml.toml new file mode 100644 index 0000000..a28003c --- /dev/null +++ b/fixtures/output/tab-single-quotes/toml.toml @@ -0,0 +1,23 @@ +comma = [ + 1, + 2, + 3, +] + +[foo] + b = 1 + c = "hello" + a = {answer = 42} + +"indent" = [ +1, + 2 +] + +['a-table'] +apple.type = "fruit" +apple.skin = "thin" +apple.color = "red" +orange.type = "fruit" +orange.skin = "thick" +orange.color = "orange" diff --git a/fixtures/output/tab-single-quotes/tsconfig.json b/fixtures/output/tab-single-quotes/tsconfig.json new file mode 100644 index 0000000..75dd2b2 --- /dev/null +++ b/fixtures/output/tab-single-quotes/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "skipDefaultLibCheck": true, + "skipLibCheck": true + } +} diff --git a/fixtures/output/tab-single-quotes/tsx.tsx b/fixtures/output/tab-single-quotes/tsx.tsx new file mode 100644 index 0000000..79b70ef --- /dev/null +++ b/fixtures/output/tab-single-quotes/tsx.tsx @@ -0,0 +1,24 @@ +export function Component1() { + return
; +} + +export function jsx2() { + const props = { a: 1, b: 2 }; + return ( + +
+ Inline Text +
+ Block Text +
+ Mixed +
Foo
+ Text Bar +
+

+ foobar + baz +

+
+ ); +} diff --git a/fixtures/output/tab-single-quotes/typescript.ts b/fixtures/output/tab-single-quotes/typescript.ts new file mode 100644 index 0000000..9473a71 --- /dev/null +++ b/fixtures/output/tab-single-quotes/typescript.ts @@ -0,0 +1,80 @@ +// 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(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-single-quotes/vue-ts.vue b/fixtures/output/tab-single-quotes/vue-ts.vue new file mode 100644 index 0000000..e52d917 --- /dev/null +++ b/fixtures/output/tab-single-quotes/vue-ts.vue @@ -0,0 +1,36 @@ + + + + + + + diff --git a/fixtures/output/tab-single-quotes/vue.vue b/fixtures/output/tab-single-quotes/vue.vue new file mode 100644 index 0000000..5d412ce --- /dev/null +++ b/fixtures/output/tab-single-quotes/vue.vue @@ -0,0 +1,25 @@ + + + diff --git a/package.json b/package.json index 40081ea..4aaf480 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "build:inspector": "pnpm build && npx @eslint/config-inspector build", "watch": "tsup --format esm,cjs --watch", "lint": "eslint .", + "test": "vitest", "typegen": "esno scripts/typegen.ts", "prepack": "pnpm run build", "release": "bumpp && pnpm publish", @@ -91,6 +92,7 @@ "devDependencies": { "@eslint/config-inspector": "^0.5.2", "@types/eslint": "^9.6.0", + "@types/fs-extra": "^11.0.4", "@types/node": "^22.2.0", "@unocss/eslint-plugin": "^0.62.1", "astro-eslint-parser": "^1.0.2", @@ -99,12 +101,15 @@ "eslint-plugin-astro": "^1.2.3", "eslint-typegen": "^0.3.0", "esno": "^4.7.0", + "execa": "^9.3.1", "fast-glob": "^3.3.2", + "fs-extra": "^11.2.0", "husky": "^9.1.4", "lint-staged": "^15.2.8", "prettier-plugin-astro": "^0.14.1", "tsup": "^8.2.4", - "typescript": "^5.5.4" + "typescript": "^5.5.4", + "vitest": "^2.0.5" }, "lint-staged": { "*": "eslint --fix" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index eab5175..cf4cc9d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -120,6 +120,9 @@ importers: '@types/eslint': specifier: ^9.6.0 version: 9.6.0 + '@types/fs-extra': + specifier: ^11.0.4 + version: 11.0.4 '@types/node': specifier: ^22.2.0 version: 22.2.0 @@ -144,9 +147,15 @@ importers: esno: specifier: ^4.7.0 version: 4.7.0 + execa: + specifier: ^9.3.1 + version: 9.3.1 fast-glob: specifier: ^3.3.2 version: 3.3.2 + fs-extra: + specifier: ^11.2.0 + version: 11.2.0 husky: specifier: ^9.1.4 version: 9.1.4 @@ -162,6 +171,9 @@ importers: typescript: specifier: ^5.5.4 version: 5.5.4 + vitest: + specifier: ^2.0.5 + version: 2.0.5(@types/node@22.2.0) packages: @@ -710,6 +722,13 @@ packages: cpu: [x64] os: [win32] + '@sec-ant/readable-stream@0.4.1': + resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} + + '@sindresorhus/merge-streams@4.0.0': + resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} + engines: {node: '>=18'} + '@types/eslint@8.56.11': resolution: {integrity: sha512-sVBpJMf7UPo/wGecYOpk2aQya2VUGeHhe38WG7/mN5FufNSubf5VT9Uh9Uyp8/eLJpu1/tuhJ/qTo4mhSB4V4Q==} @@ -719,9 +738,15 @@ packages: '@types/estree@1.0.5': resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + '@types/fs-extra@11.0.4': + resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/jsonfile@6.1.4': + resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} + '@types/mdast@3.0.15': resolution: {integrity: sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==} @@ -1490,6 +1515,10 @@ packages: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} engines: {node: '>=16.17'} + execa@9.3.1: + resolution: {integrity: sha512-gdhefCCNy/8tpH/2+ajP9IQc14vXchNdd0weyzSJEFURhRMGncQ+zKFxwjAufIewPEJm9BPOaJnvg2UtlH2gPQ==} + engines: {node: ^18.19.0 || >=20.5.0} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1509,6 +1538,10 @@ packages: fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + figures@6.1.0: + resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} + engines: {node: '>=18'} + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -1544,6 +1577,10 @@ packages: resolution: {integrity: sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==} engines: {node: '>=14'} + fs-extra@11.2.0: + resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} + engines: {node: '>=14.14'} + fs-minipass@2.1.0: resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} engines: {node: '>= 8'} @@ -1574,6 +1611,10 @@ packages: resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} engines: {node: '>=16'} + get-stream@9.0.1: + resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} + engines: {node: '>=18'} + get-tsconfig@4.7.6: resolution: {integrity: sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA==} @@ -1641,6 +1682,10 @@ packages: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} engines: {node: '>=16.17.0'} + human-signals@8.0.0: + resolution: {integrity: sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA==} + engines: {node: '>=18.18.0'} + husky@9.1.4: resolution: {integrity: sha512-bho94YyReb4JV7LYWRWxZ/xr6TtOTt8cMfmQ39MQYJ7f/YE268s3GdghGwi+y4zAeqewE5zYLvuhV0M0ijsDEA==} engines: {node: '>=18'} @@ -1733,6 +1778,10 @@ packages: resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} engines: {node: '>=8'} + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} @@ -1741,6 +1790,14 @@ packages: resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + is-stream@4.0.1: + resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==} + engines: {node: '>=18'} + + is-unicode-supported@2.0.0: + resolution: {integrity: sha512-FRdAyx5lusK1iHG0TWpVtk9+1i+GjrzRffhDg4ovQ7mcidMQ6mj+MhKPmvh7Xwyv5gIS06ns49CA7Sqg7lC22Q==} + engines: {node: '>=18'} + is-wsl@3.1.0: resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} engines: {node: '>=16'} @@ -1809,6 +1866,9 @@ packages: jsonc-parser@3.3.1: resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -2081,6 +2141,10 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} + parse-ms@4.0.0: + resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} + engines: {node: '>=18'} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -2184,6 +2248,10 @@ packages: engines: {node: '>=14'} hasBin: true + pretty-ms@9.1.0: + resolution: {integrity: sha512-o1piW0n3tgKIKCwk2vpM/vOV13zjJzvP37Ioze54YlTHE06m4tjEbzg9WsKkvTuyYln2DHjo5pY4qrZGI0otpw==} + engines: {node: '>=18'} + prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} @@ -2386,6 +2454,10 @@ packages: resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} engines: {node: '>=12'} + strip-final-newline@4.0.0: + resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==} + engines: {node: '>=18'} + strip-indent@3.0.0: resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} engines: {node: '>=8'} @@ -2560,6 +2632,10 @@ packages: unist-util-stringify-position@2.0.3: resolution: {integrity: sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==} + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + update-browserslist-db@1.1.0: resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==} hasBin: true @@ -2710,13 +2786,16 @@ packages: resolution: {integrity: sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==} engines: {node: '>=12.20'} + yoctocolors@2.1.1: + resolution: {integrity: sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==} + engines: {node: '>=18'} + snapshots: '@ampproject/remapping@2.3.0': dependencies: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 - optional: true '@antfu/install-pkg@0.3.4': dependencies: @@ -3111,6 +3190,10 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.20.0': optional: true + '@sec-ant/readable-stream@0.4.1': {} + + '@sindresorhus/merge-streams@4.0.0': {} + '@types/eslint@8.56.11': dependencies: '@types/estree': 1.0.5 @@ -3123,8 +3206,17 @@ snapshots: '@types/estree@1.0.5': {} + '@types/fs-extra@11.0.4': + dependencies: + '@types/jsonfile': 6.1.4 + '@types/node': 22.2.0 + '@types/json-schema@7.0.15': {} + '@types/jsonfile@6.1.4': + dependencies: + '@types/node': 22.2.0 + '@types/mdast@3.0.15': dependencies: '@types/unist': 2.0.10 @@ -3291,30 +3383,25 @@ snapshots: '@vitest/utils': 2.0.5 chai: 5.1.1 tinyrainbow: 1.2.0 - optional: true '@vitest/pretty-format@2.0.5': dependencies: tinyrainbow: 1.2.0 - optional: true '@vitest/runner@2.0.5': dependencies: '@vitest/utils': 2.0.5 pathe: 1.1.2 - optional: true '@vitest/snapshot@2.0.5': dependencies: '@vitest/pretty-format': 2.0.5 magic-string: 0.30.11 pathe: 1.1.2 - optional: true '@vitest/spy@2.0.5': dependencies: tinyspy: 3.0.0 - optional: true '@vitest/utils@2.0.5': dependencies: @@ -3322,7 +3409,6 @@ snapshots: estree-walker: 3.0.3 loupe: 3.1.1 tinyrainbow: 1.2.0 - optional: true '@voxpelli/config-array-find-files@0.1.2(@eslint/config-array@0.17.1)': dependencies: @@ -3405,8 +3491,7 @@ snapshots: array-union@2.1.0: {} - assertion-error@2.0.1: - optional: true + assertion-error@2.0.1: {} astro-eslint-parser@1.0.2(typescript@5.5.4): dependencies: @@ -3518,7 +3603,6 @@ snapshots: deep-eql: 5.0.2 loupe: 3.1.1 pathval: 2.0.0 - optional: true chalk@2.4.2: dependencies: @@ -3539,8 +3623,7 @@ snapshots: character-reference-invalid@1.1.4: {} - check-error@2.1.1: - optional: true + check-error@2.1.1: {} chokidar@3.6.0: dependencies: @@ -3625,8 +3708,7 @@ snapshots: dependencies: ms: 2.1.2 - deep-eql@5.0.2: - optional: true + deep-eql@5.0.2: {} deep-is@0.1.4: {} @@ -4077,7 +4159,6 @@ snapshots: estree-walker@3.0.3: dependencies: '@types/estree': 1.0.5 - optional: true esutils@2.0.3: {} @@ -4107,6 +4188,21 @@ snapshots: signal-exit: 4.1.0 strip-final-newline: 3.0.0 + execa@9.3.1: + dependencies: + '@sindresorhus/merge-streams': 4.0.0 + cross-spawn: 7.0.3 + figures: 6.1.0 + get-stream: 9.0.1 + human-signals: 8.0.0 + is-plain-obj: 4.1.0 + is-stream: 4.0.1 + npm-run-path: 5.3.0 + pretty-ms: 9.1.0 + signal-exit: 4.1.0 + strip-final-newline: 4.0.0 + yoctocolors: 2.1.1 + fast-deep-equal@3.1.3: {} fast-diff@1.3.0: {} @@ -4127,6 +4223,10 @@ snapshots: dependencies: reusify: 1.0.4 + figures@6.1.0: + dependencies: + is-unicode-supported: 2.0.0 + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -4165,6 +4265,12 @@ snapshots: cross-spawn: 7.0.3 signal-exit: 4.1.0 + fs-extra@11.2.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + fs-minipass@2.1.0: dependencies: minipass: 3.3.6 @@ -4176,8 +4282,7 @@ snapshots: get-east-asian-width@1.2.0: {} - get-func-name@2.0.2: - optional: true + get-func-name@2.0.2: {} get-port-please@3.1.2: {} @@ -4185,6 +4290,11 @@ snapshots: get-stream@8.0.1: {} + get-stream@9.0.1: + dependencies: + '@sec-ant/readable-stream': 0.4.1 + is-stream: 4.0.1 + get-tsconfig@4.7.6: dependencies: resolve-pkg-maps: 1.0.0 @@ -4267,6 +4377,8 @@ snapshots: human-signals@5.0.0: {} + human-signals@8.0.0: {} + husky@9.1.4: {} ignore@5.3.1: {} @@ -4344,10 +4456,16 @@ snapshots: is-path-inside@3.0.3: {} + is-plain-obj@4.1.0: {} + is-stream@2.0.1: {} is-stream@3.0.0: {} + is-stream@4.0.1: {} + + is-unicode-supported@2.0.0: {} + is-wsl@3.1.0: dependencies: is-inside-container: 1.0.0 @@ -4402,6 +4520,12 @@ snapshots: jsonc-parser@3.3.1: {} + jsonfile@6.1.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -4477,7 +4601,6 @@ snapshots: loupe@3.1.1: dependencies: get-func-name: 2.0.2 - optional: true lru-cache@10.4.3: {} @@ -4694,6 +4817,8 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + parse-ms@4.0.0: {} + path-exists@4.0.0: {} path-exists@5.0.0: {} @@ -4713,8 +4838,7 @@ snapshots: pathe@1.1.2: {} - pathval@2.0.0: - optional: true + pathval@2.0.0: {} perfect-debounce@1.0.0: {} @@ -4768,6 +4892,10 @@ snapshots: prettier@3.3.3: {} + pretty-ms@9.1.0: + dependencies: + parse-ms: 4.0.0 + prompts@2.4.2: dependencies: kleur: 3.0.3 @@ -4887,8 +5015,7 @@ snapshots: shebang-regex@3.0.0: {} - siginfo@2.0.0: - optional: true + siginfo@2.0.0: {} signal-exit@3.0.7: {} @@ -4937,11 +5064,9 @@ snapshots: stable-hash@0.0.4: {} - stackback@0.0.2: - optional: true + stackback@0.0.2: {} - std-env@3.7.0: - optional: true + std-env@3.7.0: {} string-argv@0.3.2: {} @@ -4975,6 +5100,8 @@ snapshots: strip-final-newline@3.0.0: {} + strip-final-newline@4.0.0: {} + strip-indent@3.0.0: dependencies: min-indent: 1.0.1 @@ -5035,19 +5162,15 @@ snapshots: dependencies: any-promise: 1.3.0 - tinybench@2.9.0: - optional: true + tinybench@2.9.0: {} tinyexec@0.1.4: {} - tinypool@1.0.0: - optional: true + tinypool@1.0.0: {} - tinyrainbow@1.2.0: - optional: true + tinyrainbow@1.2.0: {} - tinyspy@3.0.0: - optional: true + tinyspy@3.0.0: {} to-fast-properties@2.0.0: {} @@ -5149,6 +5272,8 @@ snapshots: dependencies: '@types/unist': 2.0.10 + universalify@2.0.1: {} + update-browserslist-db@1.1.0(browserslist@4.23.3): dependencies: browserslist: 4.23.3 @@ -5183,7 +5308,6 @@ snapshots: - sugarss - supports-color - terser - optional: true vite@5.4.0(@types/node@22.2.0): dependencies: @@ -5193,7 +5317,6 @@ snapshots: optionalDependencies: '@types/node': 22.2.0 fsevents: 2.3.3 - optional: true vitest@2.0.5(@types/node@22.2.0): dependencies: @@ -5227,7 +5350,6 @@ snapshots: - sugarss - supports-color - terser - optional: true vue-eslint-parser@9.4.3(eslint@9.9.0(jiti@1.21.6)): dependencies: @@ -5258,7 +5380,6 @@ snapshots: dependencies: siginfo: 2.0.0 stackback: 0.0.2 - optional: true word-wrap@1.2.5: {} @@ -5297,3 +5418,5 @@ snapshots: yocto-queue@0.1.0: {} yocto-queue@1.1.1: {} + + yoctocolors@2.1.1: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..c186cf5 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - 'fixtures/*' diff --git a/src/configs/formatters.ts b/src/configs/formatters.ts index 25db28f..5b36579 100644 --- a/src/configs/formatters.ts +++ b/src/configs/formatters.ts @@ -22,7 +22,7 @@ import type { OptionsFormatters, TypedFlatConfigItem } from "../types"; import type { Options as PrettierOptions } from "prettier"; export async function formatters( - options: OptionsFormatters | true = {}, + options?: OptionsFormatters, ): Promise { let prettierOptions: PrettierOptions = { tabWidth: 2, @@ -40,7 +40,7 @@ export async function formatters( slidev: isPackageExists("@slidev/cli"), xml: isPackageExists("@prettier/plugin-xml"), }; - if (options === true) { + if (!options) { options = { ...defaultOptions, }; diff --git a/src/factory.ts b/src/factory.ts index dca1356..0a581b4 100644 --- a/src/factory.ts +++ b/src/factory.ts @@ -27,7 +27,6 @@ import { yaml, } from "./configs"; import { interopDefault, isInEditorEnv } from "./utils"; -// import { formatters } from './configs/formatters' import type { RuleOptions } from "./typegen"; import type { Awaitable, @@ -137,9 +136,14 @@ export function xwbx( command(), sortImport(), - formatters(options.formatters ?? true), ); - + if (options.formatters ?? true) { + configs.push( + formatters( + typeof options.formatters === "object" ? options.formatters : undefined, + ), + ); + } if (enableVue) { componentExts.push("vue"); } diff --git a/src/types.ts b/src/types.ts index d2f3e9d..1a7e74e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -353,8 +353,12 @@ export interface OptionsConfig * * Requires installing: * - `eslint-plugin-format` + * + * When set to `true`, it will enable all formatters. + * + * @default true */ - formatters?: OptionsFormatters; + formatters?: boolean | OptionsFormatters; /** * Control to disable some rules in editors. diff --git a/test/fixtures.test.ts b/test/fixtures.test.ts new file mode 100644 index 0000000..ee104d8 --- /dev/null +++ b/test/fixtures.test.ts @@ -0,0 +1,94 @@ +import { join, resolve } from "node:path"; +import { execa } from "execa"; +import fg from "fast-glob"; +import fs from "fs-extra"; +import { afterAll, beforeAll, it } from "vitest"; +import type { OptionsConfig, TypedFlatConfigItem } from "../src/types"; + +beforeAll(async () => { + await fs.rm("_fixtures", { recursive: true, force: true }); +}); +afterAll(async () => { + await fs.rm("_fixtures", { recursive: true, force: true }); +}); + +runWithConfig("all", { + typescript: true, + vue: true, + astro: true, + formatters: true, +}); +runWithConfig("no-style", { + typescript: true, + vue: true, + astro: true, + formatters: false, +}); +runWithConfig("tab-single-quotes", { + typescript: true, + vue: true, + astro: true, + formatters: { + prettierOptions: { + useTabs: true, + singleQuote: true, + }, + }, +}); + +function runWithConfig( + name: string, + configs: OptionsConfig, + ...items: TypedFlatConfigItem[] +) { + it.concurrent( + name, + async ({ expect }) => { + const from = resolve("fixtures/input"); + const output = resolve("fixtures/output", name); + const target = resolve("_fixtures", name); + + await fs.copy(from, target, { + filter: (src) => { + return !src.includes("node_modules"); + }, + }); + await fs.writeFile( + join(target, "eslint.config.js"), + ` +// @eslint-disable +import xwbx from '@xwbx/eslint-config' + +export default xwbx( + ${JSON.stringify(configs)}, + ...${JSON.stringify(items) ?? []}, +) + `, + ); + + await execa("npx", ["eslint", ".", "--fix"], { + cwd: target, + stdio: "pipe", + }); + + const files = await fg("**/*", { + ignore: ["node_modules", "eslint.config.js"], + cwd: target, + }); + + await Promise.all( + files.map(async (file) => { + const content = await fs.readFile(join(target, file), "utf-8"); + const source = await fs.readFile(join(from, file), "utf-8"); + const outputPath = join(output, file); + if (content === source) { + if (fs.existsSync(outputPath)) await fs.remove(outputPath); + return; + } + await expect.soft(content).toMatchFileSnapshot(join(output, file)); + }), + ); + }, + 30_000, + ); +} diff --git a/test/types.ts b/test/types.ts new file mode 100644 index 0000000..b5000c3 --- /dev/null +++ b/test/types.ts @@ -0,0 +1,6 @@ +import type { TypedFlatConfigItem } from "../src"; +import type { Linter } from "eslint"; + +// Make sure they are compatible +((): Linter.Config => ({}) as TypedFlatConfigItem)(); +((): TypedFlatConfigItem => ({}) as Linter.Config)();