Skip to content

Commit 0df7977

Browse files
authored
fix(gatsby-plugin-mdx): support import shorthand syntax (#26198)
The "shorthand" syntax is an import that only imports a path, without declaring any symbols: ```js import "./foo.css" ``` This happened in the real world so we have to support it. This fixes #25734
1 parent 9c8b442 commit 0df7977

File tree

3 files changed

+81
-3
lines changed

3 files changed

+81
-3
lines changed

packages/gatsby-plugin-mdx/utils/__tests__/__snapshots__/import-parser.js.snap

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -985,6 +985,26 @@ Object {
985985
`;
986986

987987
exports[`regex import scanner syntactic coverage should parse brute force regular case 62 1`] = `
988+
Object {
989+
"input": "import \\"./empty.css\\"",
990+
"result": Object {
991+
"bindings": Array [],
992+
"segments": Array [],
993+
},
994+
}
995+
`;
996+
997+
exports[`regex import scanner syntactic coverage should parse brute force regular case 63 1`] = `
998+
Object {
999+
"input": "import \\"./empty.css\\"; // This happens in the real world",
1000+
"result": Object {
1001+
"bindings": Array [],
1002+
"segments": Array [],
1003+
},
1004+
}
1005+
`;
1006+
1007+
exports[`regex import scanner syntactic coverage should parse brute force regular case 64 1`] = `
9881008
Object {
9891009
"input": "import multi as dong, {foo} from 'bar'
9901010
import as as x, {from as y} from 'bar'",

packages/gatsby-plugin-mdx/utils/__tests__/import-parser.js

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ function getBruteForceCases() {
7272
import foo from 'bar' // commment containing confusing from "chars"
7373
import foo from 'bar' // import bad from 'imp'
7474
import foo from 'bar'//next to it
75+
import "./empty.css"
76+
import "./empty.css"; // This happens in the real world
7577
`
7678
.trim()
7779
.split(/\n/g)
@@ -94,7 +96,11 @@ describe(`regex import scanner`, () => {
9496
const output = parseImportBindings(input, true)
9597
const bindings = output.bindings
9698

97-
expect(output.bindings.length).not.toBe(0)
99+
if (input.includes(`empty`)) {
100+
expect(output.bindings.length).toBe(0)
101+
} else {
102+
expect(output.bindings.length).not.toBe(0)
103+
}
98104
// Note: putting everything in the snapshot makes reviews easier
99105
expect({ input, result: output }).toMatchSnapshot()
100106
expect(
@@ -288,5 +294,56 @@ import {A} from "@your/name"
288294
]
289295
`)
290296
})
297+
298+
it(`double import with shorthand import`, async () => {
299+
// Note: the point of this test is to have two back2back imports clustered
300+
// as one pseudo-node in the ast where the first is the short-hand
301+
// version of `import` that declares no symbols.
302+
303+
const { content } = grayMatter(`
304+
---
305+
title: double test
306+
---
307+
308+
import "./foo.css"
309+
import Events from "@components/events/events"
310+
311+
<Events />
312+
`)
313+
314+
const compiler = mdx.createCompiler()
315+
const fileOpts = { contents: content }
316+
const mdast = await compiler.parse(fileOpts)
317+
318+
const imports = mdast.children.filter(obj => obj.type === `import`)
319+
320+
// Assert the md parser outputs same mdast (update test if this changes)
321+
expect(
322+
imports.map(({ type, value }) => {
323+
return { type, value }
324+
})
325+
).toMatchInlineSnapshot(`
326+
Array [
327+
Object {
328+
"type": "import",
329+
"value": "import \\"./foo.css\\"
330+
import Events from \\"@components/events/events\\"",
331+
},
332+
]
333+
`)
334+
335+
// Take the imports being parsed and feed them to the import parser
336+
expect(parseImportBindings(imports[0].value, true))
337+
.toMatchInlineSnapshot(`
338+
Object {
339+
"bindings": Array [
340+
"Events",
341+
],
342+
"segments": Array [
343+
"Events",
344+
],
345+
}
346+
`)
347+
})
291348
})
292349
})

packages/gatsby-plugin-mdx/utils/import-parser.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
* `from` tail. What's left ought to be a string in the form of
88
* `id[ as id] [, id[ as id]]`
99
* (where the brackets represent optional repeating parts). The left-most id
10-
* might also contain star (namespaced import).
10+
* might also contain star (namespaced import). This step also strips
11+
* `import "foo"` shorthand imports.
1112
* The second part will trim and split the string on comma, then each segment
1213
* is split on `as` (in a proper way) and the right-most identifier is returned.
1314
*
@@ -19,7 +20,7 @@
1920
*/
2021
function parseImportBindings(importCode, returnSegments = false) {
2122
const str = importCode.replace(
22-
/^\s*import|[{},]|\s*from\s*['"][^'"]*?['"].*?$/gm,
23+
/^\s*import\s*['"][^'"]*?['"].*?$|^\s*import|[{},]|\s*from\s*['"][^'"]*?['"].*?$/gm,
2324
` , `
2425
)
2526
const segments = str

0 commit comments

Comments
 (0)