Skip to content

Commit 310a287

Browse files
committed
feat: merge passed options.plugins
1 parent d29b18f commit 310a287

File tree

7 files changed

+101
-12
lines changed

7 files changed

+101
-12
lines changed

.prettierignore

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/coverage
2+
/.nyc_output
3+
node_modules
4+
/es
5+
.eslintcache
6+
*.js
7+
*.js.flow
8+
*.d.ts
9+
!/src/**/*.ts
10+
!/src/**/*.js
11+
!/src/**/*.js.flow
12+
!/test/**/*.ts
13+
!/test/**/*.js
14+
!/.babelrc.js
15+
/test/fixtures

README.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ project, it falls back to parsing with reasonable default options.
1717

1818
# API
1919

20-
## `parseSync(file: string, options?: { encoding?: BufferEncoding } & Omit<ParserOptions, 'plugins'>): File`
20+
## `parseSync(file: string, options?: { encoding?: BufferEncoding } & ParserOptions): File`
2121

2222
```ts
2323
import { parseSync } from 'babel-parse-wild-code'
@@ -26,8 +26,9 @@ import { parseSync } from 'babel-parse-wild-code'
2626
Parses the given file synchronously, returning the `File` node.
2727

2828
`encoding` defaults to `utf8`. The remaining options are passed to `@babel/parser`'s `parse` function.
29+
`options.plugins` will be merged with the resolved options for the file.
2930

30-
## `parseAsync(file: string, options?: { encoding?: BufferEncoding } & Omit<ParserOptions, 'plugins'>): Promise<File>`
31+
## `parseAsync(file: string, options?: { encoding?: BufferEncoding } & ParserOptions): Promise<File>`
3132

3233
```ts
3334
import { parseAsync } from 'babel-parse-wild-code'
@@ -36,6 +37,7 @@ import { parseAsync } from 'babel-parse-wild-code'
3637
Parses the given file asynchronously, returning a `Promise` that will resolve to the `File` node.
3738

3839
`encoding` defaults to `utf8`. The remaining options are passed to `@babel/parser`'s `parse` function.
40+
`options.plugins` will be merged with the resolved options for the file.
3941

4042
## `clearCache(): void`
4143

@@ -48,7 +50,7 @@ automatically when the user's Babel version or config changes, but setting up th
4850
complicated. Clearing the cache before you parse a bunch of files is simpler and won't have a huge
4951
impact on performance.
5052

51-
## `getParserSync(file: string, options?: Omit<ParserOptions, 'plugins'>): Parser`
53+
## `getParserSync(file: string, options?: ParserOptions): Parser`
5254

5355
```ts
5456
import { getParserSync } from 'babel-parse-wild-code'
@@ -58,8 +60,9 @@ Gets a fully-configured parser for the given file synchronously.
5860

5961
`options` is additional options for `@babel/parser`'s `parse` function. For example when working
6062
with `jscodeshift` or `recast`, you should pass `{ tokens: true }`.
63+
`options.plugins` will be merged with the resolved options for the file.
6164

62-
## `getParserAsync(file: string, options?: Omit<ParserOptions, 'plugins'>): Promise<Parser>`
65+
## `getParserAsync(file: string, options?: ParserOptions): Promise<Parser>`
6366

6467
```ts
6568
import { getParserSync } from 'babel-parse-wild-code'
@@ -69,6 +72,7 @@ Gets a fully-configured parser for the given file asynchronously.
6972

7073
`options` is additional options for `@babel/parser`'s `parse` function. For example when working
7174
with `jscodeshift` or `recast`, you should pass `{ tokens: true }`.
75+
`options.plugins` will be merged with the resolved options for the file.
7276

7377
## `class Parser`
7478

src/index.ts

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,30 @@ function isEmpty(obj: any): boolean {
1515

1616
type BabelParser = Pick<typeof defaultBabelParser, 'parse' | 'parseExpression'>
1717

18+
function mergePlugins(
19+
a: ParserPlugin[] | undefined,
20+
b: ParserPlugin[] | undefined
21+
): ParserPlugin[] | undefined {
22+
if (!b) return a
23+
if (!a) return b
24+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
25+
const map: Map<string, any> = new Map(
26+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
27+
a.map((p: ParserPlugin): [string, any] =>
28+
Array.isArray(p) ? p : [p, undefined]
29+
)
30+
)
31+
for (const p of b) {
32+
if (Array.isArray(p)) map.set(p[0], { ...map.get(p[0]), ...p[1] })
33+
else if (!map.has(p)) map.set(p, map.get(p))
34+
}
35+
return [...map.entries()].map(
36+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
37+
(e: [string, any]) => (e[1] === undefined ? e[0] : e)
38+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
39+
) as any
40+
}
41+
1842
export class Parser {
1943
readonly babelParser: BabelParser
2044
readonly parserOpts: ParserOptions
@@ -37,7 +61,11 @@ export class Parser {
3761
}
3862

3963
bindParserOpts(parserOpts: ParserOptions): Parser {
40-
return new Parser(this.babelParser, { ...this.parserOpts, ...parserOpts })
64+
return new Parser(this.babelParser, {
65+
...this.parserOpts,
66+
...parserOpts,
67+
plugins: mergePlugins(this.parserOpts.plugins, parserOpts.plugins),
68+
})
4169
}
4270
}
4371

@@ -141,10 +169,7 @@ function createParserFromConfig(babelParser: BabelParser, config: any): Parser {
141169
return new Parser(babelParser, opts.parserOpts)
142170
}
143171

144-
export function getParserSync(
145-
file: string,
146-
options?: Omit<ParserOptions, 'plugins'>
147-
): Parser {
172+
export function getParserSync(file: string, options?: ParserOptions): Parser {
148173
let result
149174
const parentDir = Path.dirname(file)
150175
const extname = Path.extname(file)
@@ -185,7 +210,7 @@ export function getParserSync(
185210

186211
export async function getParserAsync(
187212
file: string,
188-
options?: Omit<ParserOptions, 'plugins'>
213+
options?: ParserOptions
189214
): Promise<Parser> {
190215
let promise
191216
if (/\.ts$/.test(file)) promise = Promise.resolve(tsParser)
@@ -241,7 +266,7 @@ export function parseSync(
241266
{
242267
encoding = 'utf8',
243268
...options
244-
}: { encoding?: BufferEncoding } & Omit<ParserOptions, 'plugins'> = {}
269+
}: { encoding?: BufferEncoding } & ParserOptions = {}
245270
): t.File {
246271
const parser = getParserSync(file, options)
247272
return parser.parse(readFileSync(file, encoding))
@@ -252,7 +277,7 @@ export async function parseAsync(
252277
{
253278
encoding = 'utf8',
254279
...options
255-
}: { encoding?: BufferEncoding } & Omit<ParserOptions, 'plugins'> = {}
280+
}: { encoding?: BufferEncoding } & ParserOptions = {}
256281
): Promise<t.File> {
257282
const parser = await getParserAsync(file, options)
258283
return parser.parse(await readFile(file, encoding))
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
type Foo = number
2+
3+
let person = { score: 25 }
4+
5+
let newScore = person.score |> double(#) |> add(7, #) |> boundScore(0, 100, #)
6+
7+
newScore //=> 57
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
type Foo = number
2+
3+
let person = { score: 25 }
4+
5+
let newScore =
6+
person.score |> double |> ((_) => add(7, _)) |> ((_) => boundScore(0, 100, _))
7+
8+
newScore //=> 57
9+
await blah
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
type Foo = number
2+
3+
let person = { score: 25 }
4+
5+
let newScore =
6+
person.score |> double |> ((_) => add(7, _)) |> ((_) => boundScore(0, 100, _))
7+
8+
newScore //=> 57
9+
await blah

test/index.spec.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,26 @@ describe('parseSync', function () {
2626
parseSync(Path.join(fixturesDir, 'babelPipeline', 'test.js')).type
2727
).to.equal('File')
2828
})
29+
it('passing plugins works', () => {
30+
expect(
31+
parseSync(
32+
Path.join(fixturesDir, 'babelPipeline', 'topLevelAwaitTest.js'),
33+
{ plugins: ['topLevelAwait'] }
34+
).type
35+
).to.equal('File')
36+
expect(
37+
parseSync(
38+
Path.join(fixturesDir, 'babelPipeline', 'topLevelAwaitTest.ts'),
39+
{ plugins: ['topLevelAwait'] }
40+
).type
41+
).to.equal('File')
42+
expect(
43+
parseSync(
44+
Path.join(fixturesDir, 'babelPipeline', 'pluginOptionsOverrideTest.js'),
45+
{ plugins: [['pipelineOperator', { proposal: 'smart' }]] }
46+
).type
47+
).to.equal('File')
48+
})
2949
it('works on ts file', () => {
3050
expect(
3151
parseSync(Path.join(fixturesDir, 'babelPipeline', 'test.ts')).type

0 commit comments

Comments
 (0)