Skip to content

Commit ba6c355

Browse files
authored
Load compatible plugins on demand and tighten plugin detection (#437)
1 parent c39497f commit ba6c355

1 file changed

Lines changed: 15 additions & 36 deletions

File tree

src/create-plugin.ts

Lines changed: 15 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { createMatcher } from './options'
44
import { loadIfExists, maybeResolve } from './resolve'
55
import type { TransformOptions } from './transform'
66
import type { TransformerEnv } from './types'
7+
import { isAbsolute } from 'path'
78

89
export function createPlugin(transforms: TransformOptions<any>[]) {
910
// Prettier parsers and printers may be async functions at definition time.
@@ -62,32 +63,24 @@ async function createParser({
6263
}) {
6364
let parser: Parser<any> = { ...original }
6465

65-
let compatible: { pluginName: string; mod: unknown }[] = []
66-
67-
for (let pluginName of opts.compatible ?? []) {
68-
let mod = await loadIfExistsESM(pluginName)
69-
compatible.push({ pluginName, mod })
70-
}
71-
72-
function load(options: ParserOptions<any>) {
66+
async function load(options: ParserOptions<any>) {
7367
let parser: Parser<any> = { ...original }
7468

75-
for (let { pluginName, mod } of compatible) {
76-
let plugin = findEnabledPlugin(options, pluginName, mod)
77-
if (plugin) Object.assign(parser, plugin.parsers[name])
69+
for (const pluginName of opts.compatible || []) {
70+
let plugin = await findEnabledPlugin(options, pluginName)
71+
if (plugin?.parsers?.[name]) Object.assign(parser, plugin.parsers[name])
7872
}
7973

8074
return parser
8175
}
8276

83-
parser.preprocess = (code: string, options: ParserOptions) => {
84-
let parser = load(options)
85-
77+
parser.preprocess = async (code: string, options: ParserOptions) => {
78+
let parser = await load(options)
8679
return parser.preprocess ? parser.preprocess(code, options) : code
8780
}
8881

8982
parser.parse = async (code, options) => {
90-
let original = load(options)
83+
let original = await load(options)
9184

9285
// @ts-expect-error: `options` is passed twice for compat with older plugins that were written
9386
// for Prettier v2 but still work with v3.
@@ -189,39 +182,25 @@ async function loadIfExistsESM(name: string): Promise<Plugin<any>> {
189182
)
190183
}
191184

192-
function findEnabledPlugin(options: ParserOptions<any>, name: string, mod: any) {
193-
let path = maybeResolve(name)
185+
function findEnabledPlugin(options: ParserOptions<any>, name: string) {
194186

195187
for (let plugin of options.plugins) {
196188
if (plugin instanceof URL) {
197189
if (plugin.protocol !== 'file:') continue
198190
if (plugin.hostname !== '') continue
199191

200192
plugin = plugin.pathname
201-
}
202-
203-
if (typeof plugin === 'string') {
204-
if (plugin === name || plugin === path) {
205-
return mod
193+
} if (typeof plugin !== 'string') {
194+
if (!plugin.name) {
195+
continue
206196
}
207-
208-
continue
197+
plugin = plugin.name
209198
}
210199

211-
// options.plugins.*.name == name
212-
if (plugin.name === name) {
213-
return mod
214-
}
215200

216-
// options.plugins.*.name == path
217-
if (plugin.name === path) {
218-
return mod
219-
}
201+
if (plugin === name || (isAbsolute(plugin) && plugin.includes(name) && maybeResolve(name) === plugin)) {
202+
return loadIfExistsESM(name)
220203

221-
// basically options.plugins.* == mod
222-
// But that can't work because prettier normalizes plugins which destroys top-level object identity
223-
if (plugin.parsers && mod.parsers && plugin.parsers == mod.parsers) {
224-
return mod
225204
}
226205
}
227206
}

0 commit comments

Comments
 (0)