diff --git a/bun.lockb b/bun.lockb index 834615c..d8611b6 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/lib/comparator/index.ts b/lib/comparator/index.ts index 0453b6d..7691d6a 100644 --- a/lib/comparator/index.ts +++ b/lib/comparator/index.ts @@ -1,4 +1,3 @@ -import { AST_NODE_TYPES } from "@typescript-eslint/types"; import bt from "@babel/types"; import { C, Comparator } from "./comparator"; import { select } from "./select"; @@ -19,34 +18,24 @@ export function comparator(options: Partial): Comparator { const alpha = options.sortMembersAlphabetically === true; return C.chain( // signature - C.capture( - node(MemberTypes.TSIndexSignature), - C.by(functionSignature, C.defer), - ), + C.capture(node(MemberTypes.TSIndexSignature), C.nop), // field C.capture( - select - .or( - select.and( - node(MemberTypes.TSPropertySignature), - select.not(functionSignature), - ), - ) - .or( - select.and( - select - .or(node(MemberTypes.PropertyDefinition)) - .or(node(MemberTypes.TSAbstractPropertyDefinition)) - .or( - select.and( - bt.isNode, - select.or(bt.isClassProperty).or(bt.isClassPrivateProperty), - ), + select.or(node(MemberTypes.TSPropertySignature)).or( + select.and( + select + .or(node(MemberTypes.PropertyDefinition)) + .or(node(MemberTypes.TSAbstractPropertyDefinition)) + .or( + select.and( + bt.isNode, + select.or(bt.isClassProperty).or(bt.isClassPrivateProperty), ), - ($) => !($.value && functionExpressions.includes($.value.type)), - ), + ), + ($) => !($.value && functionExpressions.includes($.value.type)), ), + ), C.chain( classMember(), C.by(decorated, C.prefer), @@ -103,9 +92,7 @@ export function comparator(options: Partial): Comparator { $.value != null && functionExpressions.includes($.value.type), ), ) - .or( - select.and(node(MemberTypes.TSPropertySignature), functionSignature), - ), + .or(node(MemberTypes.TSPropertySignature)), C.chain( methodKind(), classMember(), @@ -118,16 +105,6 @@ export function comparator(options: Partial): Comparator { ); } -function functionSignature( - node: MemberNode< - AST_NODE_TYPES.TSPropertySignature | AST_NODE_TYPES.TSIndexSignature - >, -): boolean { - return ( - node.typeAnnotation?.typeAnnotation.type === AST_NODE_TYPES.TSFunctionType - ); -} - function node(key: K) { return function (node: MemberNode): node is MemberNode { return node.type === key; diff --git a/package.json b/package.json index 36cf2ce..593bcb8 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "check": "bun test && tsc && eslint ." }, "devDependencies": { + "@types/eslint": "^8.56.9", "@typescript-eslint/eslint-plugin": "^7.1.0", "@typescript-eslint/parser": "^7.1.0", "bun-types": "latest", diff --git a/tests/format/__snapshots__/index.test.ts.snap b/tests/format/__snapshots__/index.test.ts.snap index 2262aa6..3322dc2 100644 --- a/tests/format/__snapshots__/index.test.ts.snap +++ b/tests/format/__snapshots__/index.test.ts.snap @@ -27,11 +27,11 @@ type Y = { }; type Z = { + edge: () => void; dog: unknown; + "change-value": () => void; "big-value": number; "another-one": 0; - edge: () => void; - "change-value": () => void; }; interface A { @@ -119,6 +119,33 @@ function deco(a: unknown, b: unknown): void {} " `; +exports[`format {} issue-40-function-member.ts 1`] = ` +"type Link = { + foo: () => void; + text: string; + onClick: () => void; +}; + +type Literal = { + func: () => void; + value: number; + method(): void; +}; + +interface Interface { + func: () => void; + value: number; + method(): void; +} + +class Class { + value = 0; + method(): void {} + func = () => 0; +} +" +`; + exports[`format {} issue-34-literal-keys.js 1`] = ` "class A { [fruit] = 1; @@ -187,6 +214,7 @@ interface F { b: 0; [\`e\`]: 0; [\`f\`]: 0; + j: () => 0; new (): F; new (a: 0): F; new (a: 0, b: 0): F; @@ -197,8 +225,8 @@ interface F { } interface G { - [d: symbol]: 0; [c: number]: () => 0; + [d: symbol]: 0; a: 0; } " @@ -206,15 +234,15 @@ interface G { exports[`format {} type-alias.ts 1`] = ` "type A = { - [t: string]: unknown; [u: number]: () => number; + [t: string]: unknown; y: number; + x: () => () => number; [\`s\`]: number; r?: number; new (a: 0, b: 1): A; get w(): number; z(): number; - x: () => () => number; v?(): number; }; " @@ -274,8 +302,8 @@ type Y = { type Z = { "another-one": 0; "big-value": number; - dog: unknown; "change-value": () => void; + dog: unknown; edge: () => void; }; @@ -364,6 +392,33 @@ function deco(a: unknown, b: unknown): void {} " `; +exports[`format {"sortMembersAlphabetically":true} issue-40-function-member.ts 1`] = ` +"type Link = { + foo: () => void; + onClick: () => void; + text: string; +}; + +type Literal = { + func: () => void; + value: number; + method(): void; +}; + +interface Interface { + func: () => void; + value: number; + method(): void; +} + +class Class { + value = 0; + func = () => 0; + method(): void {} +} +" +`; + exports[`format {"sortMembersAlphabetically":true} issue-34-literal-keys.js 1`] = ` "class A { ["apple"] = 1; @@ -430,6 +485,7 @@ interface F { [c: number]: 0; [d: symbol]: 0; b: 0; + j: () => 0; [\`e\`]: 0; [\`f\`]: 0; new (): F; @@ -442,8 +498,8 @@ interface F { } interface G { - [d: symbol]: 0; [c: number]: () => 0; + [d: symbol]: 0; a: 0; } " @@ -451,15 +507,15 @@ interface G { exports[`format {"sortMembersAlphabetically":true} type-alias.ts 1`] = ` "type A = { - [t: string]: unknown; [u: number]: () => number; + [t: string]: unknown; r?: number; + x: () => () => number; y: number; [\`s\`]: number; new (a: 0, b: 1): A; get w(): number; v?(): number; - x: () => () => number; z(): number; }; " @@ -517,11 +573,11 @@ type Y = { }; type Z = { + edge: () => void; dog: unknown; + "change-value": () => void; "big-value": number; "another-one": 0; - edge: () => void; - "change-value": () => void; }; interface A { @@ -609,6 +665,33 @@ function deco(a: unknown, b: unknown): void {} " `; +exports[`format {"sortMembersAlphabetically":false} issue-40-function-member.ts 1`] = ` +"type Link = { + foo: () => void; + text: string; + onClick: () => void; +}; + +type Literal = { + func: () => void; + value: number; + method(): void; +}; + +interface Interface { + func: () => void; + value: number; + method(): void; +} + +class Class { + value = 0; + method(): void {} + func = () => 0; +} +" +`; + exports[`format {"sortMembersAlphabetically":false} issue-34-literal-keys.js 1`] = ` "class A { [fruit] = 1; @@ -677,6 +760,7 @@ interface F { b: 0; [\`e\`]: 0; [\`f\`]: 0; + j: () => 0; new (): F; new (a: 0): F; new (a: 0, b: 0): F; @@ -687,8 +771,8 @@ interface F { } interface G { - [d: symbol]: 0; [c: number]: () => 0; + [d: symbol]: 0; a: 0; } " @@ -696,15 +780,15 @@ interface G { exports[`format {"sortMembersAlphabetically":false} type-alias.ts 1`] = ` "type A = { - [t: string]: unknown; [u: number]: () => number; + [t: string]: unknown; y: number; + x: () => () => number; [\`s\`]: number; r?: number; new (a: 0, b: 1): A; get w(): number; z(): number; - x: () => () => number; v?(): number; }; " diff --git a/tests/format/index.test.ts b/tests/format/index.test.ts index cbe0fae..320e980 100644 --- a/tests/format/index.test.ts +++ b/tests/format/index.test.ts @@ -2,6 +2,7 @@ import { describe, test, expect } from "bun:test"; import { readdir, readFile } from "node:fs/promises"; import { join } from "node:path"; import { format } from "prettier"; +import { ESLint } from "eslint"; const plugins = ["./index.ts"]; @@ -72,5 +73,34 @@ describe("format", () => { }); }); }); + + describe("compatible with eslint-typescript", () => { + const eslint = new ESLint({ + overrideConfig: { + parser: "@typescript-eslint/parser", + plugins: ["@typescript-eslint"], + extends: [], + rules: { + "@typescript-eslint/member-ordering": "error", + }, + }, + useEslintrc: false, + }); + + test.each(filenames)("%s", async (name) => { + const path = join(dir, name); + const code = await readFile(path, "utf-8"); + const result = await format(code, { + ...opts, + filepath: path, + plugins, + }); + + const lintResults = await eslint.lintText(result); + + expect(lintResults).toHaveLength(1); + expect(lintResults[0].messages).toBeEmpty(); + }); + }); }); }); diff --git a/tests/format/testdata/interface.ts b/tests/format/testdata/interface.ts index ede1b94..14faffe 100644 --- a/tests/format/testdata/interface.ts +++ b/tests/format/testdata/interface.ts @@ -61,6 +61,7 @@ interface F { [`g`](): 0; set h(_: 0); get i(): 0; + j: () => 0; } interface G { diff --git a/tests/format/testdata/issue-40-function-member.ts b/tests/format/testdata/issue-40-function-member.ts new file mode 100644 index 0000000..f796ece --- /dev/null +++ b/tests/format/testdata/issue-40-function-member.ts @@ -0,0 +1,23 @@ +type Link = { + foo: () => void; + text: string; + onClick: () => void; +}; + +type Literal = { + method(): void; + func: () => void; + value: number; +} + +interface Interface { + method(): void; + func: () => void; + value: number; +} + +class Class { + method(): void {} + func = () => 0; + value = 0; +} \ No newline at end of file