Skip to content

Commit 0ef9065

Browse files
Improve test harness
1 parent b01b8c3 commit 0ef9065

File tree

2 files changed

+201
-109
lines changed

2 files changed

+201
-109
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,147 @@
11
import dedent from 'dedent'
2-
import { expect, test } from 'vitest'
2+
import { describe, expect, test } from 'vitest'
33
import { extractStaticImportMap, findSimplePlugins } from './extract-static-imports'
44

55
const js = dedent
66

7-
test('extracts different kind of imports from an ESM file', () => {
8-
let extracted = extractStaticImportMap(js`
9-
import plugin1 from './plugin1'
10-
import * as plugin2 from './plugin2'
11-
import plugin6, { plugin3, plugin4, default as plugin5 } from './plugin3'
12-
import plugin8, * as plugin7 from './plugin7'
13-
`)
7+
describe('findSimplePlugins', () => {
8+
test('parses all export styles', () => {
9+
expect(
10+
findSimplePlugins(js`
11+
import plugin1 from './plugin1'
12+
import * as plugin2 from './plugin2'
1413
15-
expect(extracted).toEqual({
16-
plugin1: { module: './plugin1', export: null },
17-
plugin2: { module: './plugin2', export: '*' },
18-
plugin3: { module: './plugin3', export: 'plugin3' },
19-
plugin4: { module: './plugin3', export: 'plugin4' },
20-
plugin5: { module: './plugin3', export: 'default' },
21-
plugin6: { module: './plugin3', export: null },
22-
plugin7: { module: './plugin7', export: '*' },
23-
plugin8: { module: './plugin7', export: null },
24-
})
25-
})
14+
export default {
15+
plugins: [plugin1, plugin2, 'plugin3']
16+
}
17+
`),
18+
).toEqual(['./plugin1', './plugin2', 'plugin3'])
19+
20+
expect(
21+
findSimplePlugins(js`
22+
import plugin1 from './plugin1'
23+
import * as plugin2 from './plugin2'
24+
25+
export default {
26+
plugins: [plugin1, plugin2, 'plugin3']
27+
} as any
28+
`),
29+
).toEqual(['./plugin1', './plugin2', 'plugin3'])
30+
31+
expect(
32+
findSimplePlugins(js`
33+
import plugin1 from './plugin1'
34+
import * as plugin2 from './plugin2'
35+
36+
export default {
37+
plugins: [plugin1, plugin2, 'plugin3']
38+
} satisfies any
39+
`),
40+
).toEqual(['./plugin1', './plugin2', 'plugin3'])
41+
42+
expect(
43+
findSimplePlugins(js`
44+
import plugin1 from './plugin1'
45+
import * as plugin2 from './plugin2'
46+
47+
module.exports = {
48+
plugins: [plugin1, plugin2, 'plugin3']
49+
} as any
50+
`),
51+
).toEqual(['./plugin1', './plugin2', 'plugin3'])
2652

27-
test('find simple plugins', () => {
28-
expect(
29-
findSimplePlugins(js`
53+
expect(
54+
findSimplePlugins(js`
55+
import plugin1 from './plugin1'
56+
import * as plugin2 from './plugin2'
57+
58+
module.exports = {
59+
plugins: [plugin1, plugin2, 'plugin3']
60+
} satisfies any
61+
`),
62+
).toEqual(['./plugin1', './plugin2', 'plugin3'])
63+
64+
expect(
65+
findSimplePlugins(js`
3066
import plugin1 from './plugin1'
3167
import * as plugin2 from './plugin2'
3268
33-
export default {
69+
module.exports = {
3470
plugins: [plugin1, plugin2, 'plugin3']
3571
}
3672
`),
37-
).toEqual(['./plugin1', './plugin2', 'plugin3'])
73+
).toEqual(['./plugin1', './plugin2', 'plugin3'])
74+
})
3875

39-
expect(
40-
findSimplePlugins(js`
76+
test('bails out on inline plugins', () => {
77+
expect(
78+
findSimplePlugins(js`
4179
import plugin1 from './plugin1'
4280
4381
export default {
4482
plugins: [plugin1, () => {} ]
4583
}
4684
`),
47-
).toEqual(null)
85+
).toEqual(null)
4886

49-
expect(
50-
findSimplePlugins(js`
87+
expect(
88+
findSimplePlugins(js`
5189
let plugin1 = () => {}
5290
5391
export default {
5492
plugins: [plugin1]
5593
}
5694
`),
57-
).toEqual(null)
95+
).toEqual(null)
96+
})
5897

59-
expect(
60-
findSimplePlugins(js`
98+
test('bails out on named imports for plugins', () => {
99+
expect(
100+
findSimplePlugins(js`
61101
import {plugin1} from './plugin1'
62102
63103
export default {
64104
plugins: [plugin1]
65105
}
66106
`),
67-
).toEqual(null)
107+
).toEqual(null)
108+
})
68109

69-
expect(
70-
findSimplePlugins(js`
110+
test('returns no plugins if none are exported', () => {
111+
expect(
112+
findSimplePlugins(js`
71113
export default {
72114
plugins: []
73115
}
74116
`),
75-
).toEqual([])
117+
).toEqual([])
76118

77-
expect(
78-
findSimplePlugins(js`
119+
expect(
120+
findSimplePlugins(js`
79121
export default {}
80122
`),
81-
).toEqual([])
123+
).toEqual([])
124+
})
125+
})
126+
127+
describe('extractStaticImportMap', () => {
128+
test('extracts different kind of imports from an ESM file', () => {
129+
let extracted = extractStaticImportMap(js`
130+
import plugin1 from './plugin1'
131+
import * as plugin2 from './plugin2'
132+
import plugin6, { plugin3, plugin4, default as plugin5 } from './plugin3'
133+
import plugin8, * as plugin7 from './plugin7'
134+
`)
135+
136+
expect(extracted).toEqual({
137+
plugin1: { module: './plugin1', export: null },
138+
plugin2: { module: './plugin2', export: '*' },
139+
plugin3: { module: './plugin3', export: 'plugin3' },
140+
plugin4: { module: './plugin3', export: 'plugin4' },
141+
plugin5: { module: './plugin3', export: 'default' },
142+
plugin6: { module: './plugin3', export: null },
143+
plugin7: { module: './plugin7', export: '*' },
144+
plugin8: { module: './plugin7', export: null },
145+
})
146+
})
82147
})

packages/@tailwindcss-upgrade/src/utils/extract-static-imports.ts

+97-70
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,103 @@ let parser = new Parser()
55
parser.setLanguage(TS.typescript)
66
const treesitter = String.raw
77

8+
const PLUGINS_QUERY = new Parser.Query(
9+
TS.typescript,
10+
treesitter`
11+
; export default = {}
12+
(export_statement
13+
value: (satisfies_expression (object
14+
(pair
15+
key: (property_identifier) @name (#eq? @name "plugins")
16+
value: (array) @imports
17+
)
18+
))?
19+
value: (as_expression (object
20+
(pair
21+
key: (property_identifier) @name (#eq? @name "plugins")
22+
value: (array) @imports
23+
)
24+
))?
25+
value: (object
26+
(pair
27+
key: (property_identifier) @name (#eq? @name "plugins")
28+
value: (array) @imports
29+
)
30+
)?
31+
)
32+
33+
; module.exports = {}
34+
(expression_statement
35+
(assignment_expression
36+
left: (member_expression) @left (#eq? @left "module.exports")
37+
right: (satisfies_expression (object
38+
(pair
39+
key: (property_identifier) @name (#eq? @name "plugins")
40+
value: (array) @imports
41+
)
42+
))?
43+
right: (as_expression (object
44+
(pair
45+
key: (property_identifier) @name (#eq? @name "plugins")
46+
value: (array) @imports
47+
)
48+
))?
49+
right: (object
50+
(pair
51+
key: (property_identifier) @name (#eq? @name "plugins")
52+
value: (array) @imports
53+
)
54+
)?
55+
)
56+
)
57+
58+
`,
59+
)
60+
export function findSimplePlugins(source: string): string[] | null {
61+
try {
62+
let tree = parser.parse(source)
63+
let root = tree.rootNode
64+
65+
let imports = extractStaticImportMap(source)
66+
let captures = PLUGINS_QUERY.matches(root)
67+
68+
let plugins = []
69+
for (let match of captures) {
70+
for (let capture of match.captures) {
71+
if (capture.name !== 'imports') continue
72+
73+
for (let pluginDefinition of capture.node.children) {
74+
if (
75+
pluginDefinition.type === '[' ||
76+
pluginDefinition.type === ']' ||
77+
pluginDefinition.type === ','
78+
)
79+
continue
80+
81+
switch (pluginDefinition.type) {
82+
case 'identifier':
83+
let source = imports[pluginDefinition.text]
84+
if (!source || (source.export !== null && source.export !== '*')) {
85+
return null
86+
}
87+
plugins.push(source.module)
88+
break
89+
case 'string':
90+
plugins.push(pluginDefinition.children[1].text)
91+
break
92+
default:
93+
return null
94+
}
95+
}
96+
}
97+
}
98+
return plugins
99+
} catch (error) {
100+
console.error(error)
101+
return null
102+
}
103+
}
104+
8105
const ESM_IMPORT_QUERY = new Parser.Query(
9106
TS.typescript,
10107
treesitter`
@@ -69,73 +166,3 @@ export function extractStaticImportMap(source: string) {
69166

70167
return imports
71168
}
72-
73-
const PLUGINS_QUERY = new Parser.Query(
74-
TS.typescript,
75-
treesitter`
76-
(export_statement
77-
value: (satisfies_expression (object
78-
(pair
79-
key: (property_identifier) @name (#eq? @name "plugins")
80-
value: (array) @imports
81-
)
82-
))?
83-
value: (as_expression (object
84-
(pair
85-
key: (property_identifier) @name (#eq? @name "plugins")
86-
value: (array) @imports
87-
)
88-
))?
89-
value: (object
90-
(pair
91-
key: (property_identifier) @name (#eq? @name "plugins")
92-
value: (array) @imports
93-
)
94-
)?
95-
)
96-
`,
97-
)
98-
export function findSimplePlugins(source: string): string[] | null {
99-
try {
100-
let tree = parser.parse(source)
101-
let root = tree.rootNode
102-
103-
let imports = extractStaticImportMap(source)
104-
let captures = PLUGINS_QUERY.matches(root)
105-
106-
let plugins = []
107-
for (let match of captures) {
108-
for (let capture of match.captures) {
109-
if (capture.name !== 'imports') continue
110-
111-
for (let pluginDefinition of capture.node.children) {
112-
if (
113-
pluginDefinition.type === '[' ||
114-
pluginDefinition.type === ']' ||
115-
pluginDefinition.type === ','
116-
)
117-
continue
118-
119-
switch (pluginDefinition.type) {
120-
case 'identifier':
121-
let source = imports[pluginDefinition.text]
122-
if (!source || (source.export !== null && source.export !== '*')) {
123-
return null
124-
}
125-
plugins.push(source.module)
126-
break
127-
case 'string':
128-
plugins.push(pluginDefinition.children[1].text)
129-
break
130-
default:
131-
return null
132-
}
133-
}
134-
}
135-
}
136-
return plugins
137-
} catch (error) {
138-
console.error(error)
139-
return null
140-
}
141-
}

0 commit comments

Comments
 (0)