Skip to content

Commit c485dcb

Browse files
committed
feat: support sub exports
1 parent c0bf973 commit c485dcb

File tree

10 files changed

+134
-201
lines changed

10 files changed

+134
-201
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,10 @@ Will be converted to:
204204
const { default: bar, foo } = await import('./foo')
205205
```
206206

207+
## Custom Commands
208+
209+
It's also possible to define custom commands.
210+
207211
## Sponsors
208212

209213
<p align="center">

build.config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ export default defineBuildConfig({
44
entries: [
55
'src/index',
66
'src/config',
7+
'src/types',
8+
'src/commands.ts',
79
],
810
declaration: true,
911
clean: true,

package.json

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"type": "module",
44
"version": "0.1.0",
55
"packageManager": "[email protected]",
6-
"description": "Anthony extended ESLint rules",
6+
"description": "Command in comment for one-off codemod with ESLint",
77
"author": "Anthony Fu <[email protected]>",
88
"license": "MIT",
99
"funding": "https://github.com/sponsors/antfu",
@@ -14,7 +14,8 @@
1414
},
1515
"bugs": "https://github.com/antfu/eslint-plugin-command/issues",
1616
"keywords": [
17-
"eslint-plugin"
17+
"eslint-plugin",
18+
"codemod"
1819
],
1920
"sideEffects": false,
2021
"exports": {
@@ -27,6 +28,16 @@
2728
"types": "./dist/config.d.ts",
2829
"import": "./dist/config.mjs",
2930
"require": "./dist/config.cjs"
31+
},
32+
"./commands": {
33+
"types": "./dist/commands.d.ts",
34+
"import": "./dist/commands.mjs",
35+
"require": "./dist/commands.cjs"
36+
},
37+
"./types": {
38+
"types": "./dist/types.d.ts",
39+
"import": "./dist/types.mjs",
40+
"require": "./dist/types.cjs"
3041
}
3142
},
3243
"main": "./dist/index.mjs",

src/commands/_test-utils.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
import { RuleTester } from 'eslint'
2+
import * as tsParser from '@typescript-eslint/parser'
3+
import { createRuleWithCommands } from '../rule'
4+
import type { Command } from '../types'
5+
16
export function d(str: TemplateStringsArray) {
27
const lines = str[0].split('\n')
38
const commonIndent = lines.slice(1).reduce((min, line) => {
@@ -8,3 +13,50 @@ export function d(str: TemplateStringsArray) {
813
}, Number.POSITIVE_INFINITY)
914
return lines.map(line => line.slice(commonIndent)).join('\n')
1015
}
16+
17+
type Arrayable<T> = T | T[]
18+
19+
export interface TestCase extends RuleTester.ValidTestCase {
20+
output?: string | null
21+
errors?: Arrayable<string | RuleTester.TestCaseError>
22+
}
23+
24+
export function run(command: Command, ...cases: (TestCase | string)[]) {
25+
const ruleTester: RuleTester = new RuleTester({
26+
languageOptions: {
27+
parser: tsParser,
28+
},
29+
})
30+
31+
const validCases: (TestCase | string)[] = []
32+
const invalidCases: TestCase[] = []
33+
34+
for (const c of cases) {
35+
if (typeof c === 'string')
36+
validCases.push(c)
37+
else if (c.errors)
38+
invalidCases.push(c)
39+
else
40+
validCases.push(c)
41+
}
42+
43+
ruleTester.run(
44+
command.name,
45+
createRuleWithCommands([command]) as any,
46+
{
47+
valid: validCases,
48+
invalid: invalidCases.map(i => ({
49+
...i,
50+
code: i.code,
51+
output: i.output ?? null,
52+
errors: (Array.isArray(i.errors) ? i.errors : [i.errors])
53+
.filter(notFalsy)
54+
.map(id => typeof id === 'string' ? ({ messageId: id }) : id),
55+
})),
56+
},
57+
)
58+
}
59+
60+
function notFalsy<T>(value: T): value is Exclude<T, null | undefined | false> {
61+
return !!value
62+
}

src/commands/keep-sorted.test.ts

Lines changed: 17 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,18 @@
1-
import { RuleTester } from 'eslint'
2-
import * as tsParser from '@typescript-eslint/parser'
3-
import { createRuleWithCommands } from '../rule'
41
import { keepSorted as command } from './keep-sorted'
5-
import { d } from './_test-utils'
2+
import { d, run } from './_test-utils'
63

7-
const valids = [
4+
run(
5+
command,
86
// Already sorted
97
d`
10-
// @keep-sorted
11-
export const arr = [
12-
'apple',
13-
'bar',
14-
'foo',
15-
]`,
16-
]
8+
// @keep-sorted
9+
export const arr = [
10+
'apple',
11+
'bar',
12+
'foo',
13+
]`
1714

18-
const invalids = [
15+
,
1916
// Object property
2017
{
2118
code: d`
@@ -32,7 +29,7 @@ const invalids = [
3229
bar: () => {},
3330
foo,
3431
}`,
35-
messageId: ['command-fix'],
32+
errors: ['command-fix'],
3633
},
3734
// Array elements
3835
{
@@ -50,7 +47,7 @@ const invalids = [
5047
'bar',
5148
'foo',
5249
]`,
53-
messageId: ['command-fix'],
50+
errors: ['command-fix'],
5451
},
5552
// Type interface members
5653
{
@@ -72,7 +69,7 @@ const invalids = [
7269
parentPath: Path | null
7370
}
7471
`,
75-
messageId: ['command-fix'],
72+
errors: ['command-fix'],
7673
},
7774
// Type type members
7875
{
@@ -94,7 +91,7 @@ const invalids = [
9491
parentPath: Path | null
9592
}
9693
`,
97-
messageId: ['command-fix'],
94+
errors: ['command-fix'],
9895
},
9996
{
10097
code: d`
@@ -117,7 +114,7 @@ const invalids = [
117114
parentPath: null,
118115
})
119116
}`,
120-
messageId: ['command-fix'],
117+
errors: ['command-fix'],
121118
},
122119
// Export statement
123120
{
@@ -135,22 +132,6 @@ const invalids = [
135132
bar,
136133
foo,
137134
}`,
138-
messageId: ['command-fix'],
135+
errors: ['command-fix'],
139136
},
140-
]
141-
142-
const ruleTester: RuleTester = new RuleTester({
143-
languageOptions: {
144-
parser: tsParser,
145-
},
146-
})
147-
148-
ruleTester.run(command.name, createRuleWithCommands([command]) as any, {
149-
valid: valids,
150-
invalid: invalids.map(i => ({
151-
code: i.code,
152-
output: i.output,
153-
errors: (Array.isArray(i.messageId) ? i.messageId : [i.messageId])
154-
.map(id => ({ messageId: id })),
155-
})),
156-
})
137+
)

src/commands/to-arrow.test.ts

Lines changed: 9 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,18 @@
1-
import { RuleTester } from 'eslint'
2-
import * as tsParser from '@typescript-eslint/parser'
3-
import { createRuleWithCommands } from '../rule'
41
import { toArrow as command } from './to-arrow'
5-
import { d } from './_test-utils'
2+
import { d, run } from './_test-utils'
63

7-
const valids = [
4+
run(
5+
command,
86
'const foo = function () {}',
97
`export const foo = <T = 1>(arg: Z): Bar => {
108
const bar = () => {}
119
}`,
12-
]
13-
14-
const invalids = [
1510
{
1611
code: d`
1712
/// 2a
1813
const a = 1`,
1914
output: null,
20-
messageId: 'command-error',
15+
errors: 'command-error',
2116
},
2217
// Function declaration
2318
{
@@ -30,7 +25,7 @@ const invalids = [
3025
export const foo = async <T = 1>(arg: T): Bar => {
3126
const bar = () => {}
3227
}`,
33-
messageId: ['command-removal', 'command-fix'],
28+
errors: ['command-removal', 'command-fix'],
3429
},
3530
// Function expression
3631
{
@@ -43,7 +38,7 @@ const invalids = [
4338
const bar = async <T = 1>(arg: T): Bar => {
4439
function baz() {}
4540
}`,
46-
messageId: ['command-removal', 'command-fix'],
41+
errors: ['command-removal', 'command-fix'],
4742
},
4843
// Object method
4944
{
@@ -66,7 +61,7 @@ const invalids = [
6661
return 1
6762
},
6863
}`,
69-
messageId: ['command-removal', 'command-fix'],
64+
errors: ['command-removal', 'command-fix'],
7065
},
7166
// Class method
7267
{
@@ -89,22 +84,6 @@ const invalids = [
8984
return 1
9085
}
9186
}`,
92-
messageId: ['command-removal', 'command-fix'],
93-
},
94-
]
95-
96-
const ruleTester: RuleTester = new RuleTester({
97-
languageOptions: {
98-
parser: tsParser,
87+
errors: ['command-removal', 'command-fix'],
9988
},
100-
})
101-
102-
ruleTester.run(command.name, createRuleWithCommands([command]) as any, {
103-
valid: valids,
104-
invalid: invalids.map(i => ({
105-
code: i.code,
106-
output: i.output,
107-
errors: (Array.isArray(i.messageId) ? i.messageId : [i.messageId])
108-
.map(id => ({ messageId: id })),
109-
})),
110-
})
89+
)
Lines changed: 10 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,16 @@
1-
import { RuleTester } from 'eslint'
2-
import * as tsParser from '@typescript-eslint/parser'
3-
import { createRuleWithCommands } from '../rule'
41
import { toDynamicImport as command } from './to-dynamic-import'
5-
import { d } from './_test-utils'
2+
import { d, run } from './_test-utils'
63

7-
const valids = [
8-
'const foo = function () {}',
9-
]
10-
11-
const invalids = [
4+
run(
5+
command,
126
// Named import
137
{
148
code: d`
159
/// to-dynamic-import
1610
import { foo } from 'bar'`,
1711
output: d`
1812
const { foo } = await import('bar')`,
19-
messageId: ['command-removal', 'command-fix'],
13+
errors: ['command-removal', 'command-fix'],
2014
},
2115
// Default import
2216
{
@@ -25,7 +19,7 @@ const invalids = [
2519
import foo from 'bar'`,
2620
output: d`
2721
const { default: foo } = await import('bar')`,
28-
messageId: ['command-removal', 'command-fix'],
22+
errors: ['command-removal', 'command-fix'],
2923
},
3024
// Namespace
3125
{
@@ -34,7 +28,7 @@ const invalids = [
3428
import * as foo from 'bar'`,
3529
output: d`
3630
const foo = await import('bar')`,
37-
messageId: ['command-removal', 'command-fix'],
31+
errors: ['command-removal', 'command-fix'],
3832
},
3933
// Mixed
4034
{
@@ -43,15 +37,14 @@ const invalids = [
4337
import foo, { bar, baz as tex } from 'bar'`,
4438
output: d`
4539
const { default: foo, bar, baz: tex } = await import('bar')`,
46-
messageId: ['command-removal', 'command-fix'],
40+
errors: ['command-removal', 'command-fix'],
4741
},
4842
// Type import (error)
4943
{
5044
code: d`
5145
/// to-dynamic-import
5246
import type { Type } from 'baz'`,
53-
output: null,
54-
messageId: ['command-error'],
47+
errors: ['command-error'],
5548
},
5649
// Mixed with type import
5750
{
@@ -61,22 +54,6 @@ const invalids = [
6154
output: d`
6255
import { type Type } from 'bar'
6356
const { default: foo, bar } = await import('bar')`,
64-
messageId: ['command-removal', 'command-fix'],
65-
},
66-
]
67-
68-
const ruleTester: RuleTester = new RuleTester({
69-
languageOptions: {
70-
parser: tsParser,
57+
errors: ['command-removal', 'command-fix'],
7158
},
72-
})
73-
74-
ruleTester.run(command.name, createRuleWithCommands([command]) as any, {
75-
valid: valids,
76-
invalid: invalids.map(i => ({
77-
code: i.code,
78-
output: i.output,
79-
errors: (Array.isArray(i.messageId) ? i.messageId : [i.messageId])
80-
.map(id => ({ messageId: id })),
81-
})),
82-
})
59+
)

0 commit comments

Comments
 (0)