Skip to content

Commit db93304

Browse files
authored
Improve export name extraction for shortcode generation (#1160)
* Improve export name extraction Many different types of export syntax wasn't supported, primarily destructuring for objects and arrays. This adds export extraction to the import name extraction step so we can more accurately determine what shortcodes to generate. * Place gatsby-plugin-mdx in the root for now, seems to not be resolving properly * Fix linting * Make null handling more clear * Fix handling of null specifiers * Move dep to proper place
1 parent ea9970a commit db93304

10 files changed

Lines changed: 256 additions & 22 deletions

File tree

‎package.json‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
"eslint-plugin-prettier": "3.1.4",
6464
"eslint-plugin-react": "7.20.3",
6565
"gatsby": "2.24.3",
66+
"gatsby-plugin-mdx": "^1.2.27",
6667
"hast-util-select": "4.0.0",
6768
"husky": "4.2.5",
6869
"jest": "26.1.0",
@@ -134,5 +135,6 @@
134135
"bracketSpacing": false,
135136
"semi": false,
136137
"trailingComma": "none"
137-
}
138+
},
139+
"dependencies": {}
138140
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
const {declare} = require('@babel/helper-plugin-utils')
2+
3+
class BabelPluginExtractExportNames {
4+
constructor() {
5+
const names = []
6+
this.state = {names}
7+
8+
this.plugin = declare(api => {
9+
api.assertVersion(7)
10+
const {types: t} = api
11+
12+
const handleDeclarations = node => {
13+
if (!node.declaration) {
14+
return
15+
}
16+
17+
const {declarations} = node.declaration
18+
if (!declarations) {
19+
return
20+
}
21+
22+
declarations.forEach(declaration => {
23+
if (t.isIdentifier(declaration.id)) {
24+
// Export const foo = 'bar'
25+
names.push(declaration.id.name)
26+
} else if (t.isArrayPattern(declaration.id)) {
27+
// Export const [ a, b ] = []
28+
declaration.id.elements.forEach(decl => {
29+
names.push(decl.name)
30+
})
31+
} else if (t.isObjectPattern(declaration.id)) {
32+
// Export const { a, b } = {}
33+
declaration.id.properties.forEach(decl => {
34+
names.push(decl.key.name)
35+
})
36+
}
37+
})
38+
}
39+
40+
const handleSpecifiers = node => {
41+
const {specifiers} = node
42+
43+
if (!specifiers) {
44+
return
45+
}
46+
47+
specifiers.forEach(specifier => {
48+
if (t.isExportDefaultSpecifier(specifier)) {
49+
names.push(specifier.exported.name)
50+
} else {
51+
names.push(specifier.local.name)
52+
}
53+
})
54+
}
55+
56+
return {
57+
visitor: {
58+
ExportNamedDeclaration(path) {
59+
handleDeclarations(path.node)
60+
handleSpecifiers(path.node)
61+
}
62+
}
63+
}
64+
})
65+
}
66+
}
67+
68+
module.exports = BabelPluginExtractExportNames
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"name": "babel-plugin-extract-export-names",
3+
"version": "2.0.0-next.1",
4+
"description": "Extract export names",
5+
"repository": "mdx-js/mdx",
6+
"homepage": "https://mdxjs.com",
7+
"bugs": "https://github.com/mdx-js/mdx/issues",
8+
"funding": {
9+
"type": "opencollective",
10+
"url": "https://opencollective.com/unified"
11+
},
12+
"author": "John Otander <johnotander@gmail.com> (http://johnotander.com)",
13+
"license": "MIT",
14+
"files": [
15+
"index.js"
16+
],
17+
"keywords": [
18+
"mdx",
19+
"markdown",
20+
"react",
21+
"jsx",
22+
"remark",
23+
"babel"
24+
],
25+
"dependencies": {
26+
"@babel/helper-plugin-utils": "7.10.4"
27+
}
28+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# `babel-plugin-extract-export-names`
2+
3+
Babel plugin that extracts all variable names from
4+
export statements.Used by the [MDX](https://mdxjs.com)
5+
pragma.
6+
7+
## Installation
8+
9+
```sh
10+
yarn add babel-plugin-extract-export-names
11+
```
12+
13+
## Usage
14+
15+
```js
16+
const babel = require('@babel/core')
17+
18+
const BabelPluginExtractExportNames = require('babel-plugin-extract-export-names')
19+
20+
const jsx = `
21+
export const foo = 'bar'
22+
export const [A] = [1]
23+
`
24+
25+
const plugin = new BabelPluginExtractExportNames()
26+
27+
const result = babel.transform(jsx, {
28+
configFile: false,
29+
plugins: [plugin.plugin]
30+
})
31+
32+
console.log(plugin.state.names)
33+
```
34+
35+
## License
36+
37+
MIT
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
const babel = require('@babel/core')
2+
3+
const BabelPluginExtractExportNames = require('..')
4+
5+
const FIXTURE = `
6+
export const foo = 'bar'
7+
export const foo2 = {
8+
bar: 'baze',
9+
hi: \`Hello! \${foo.toJSON() || 'hrm'}\`,
10+
abc: {
11+
def: 123
12+
}
13+
}
14+
export const foo3 = [1, 2, 3, { a: 'b' }]
15+
export const A = 'baz'
16+
export const [B] = [1]
17+
export const [C, D, E] = [a, { b: 'c' }]
18+
export const { F } = { foo: 'bar' }
19+
export const { G, H } = {}
20+
export { Super } from './super'
21+
`
22+
23+
const transform = str => {
24+
const plugin = new BabelPluginExtractExportNames()
25+
26+
const result = babel.transform(str, {
27+
configFile: false,
28+
plugins: [plugin.plugin]
29+
})
30+
31+
return {
32+
...result,
33+
state: plugin.state
34+
}
35+
}
36+
37+
describe('babel-plugin-extract-export-names', () => {
38+
test('adds export names to state', () => {
39+
const result = transform(FIXTURE)
40+
41+
expect(result.state.names).toEqual([
42+
'foo',
43+
'foo2',
44+
'foo3',
45+
'A',
46+
'B',
47+
'C',
48+
'D',
49+
'E',
50+
'F',
51+
'G',
52+
'H',
53+
'Super'
54+
])
55+
})
56+
})

‎packages/babel-plugin-extract-import-names/test/index.test.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const transform = str => {
2121
}
2222
}
2323

24-
describe('babel-plugin-add-mdx-type-prop', () => {
24+
describe('babel-plugin-extract-import-names', () => {
2525
test('adds import names to state', () => {
2626
const result = transform(FIXTURE)
2727

‎packages/mdx/mdx-hast-to-jsx.js‎

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const toH = require('hast-to-hyperscript')
66
const {toTemplateLiteral} = require('@mdx-js/util')
77
const BabelPluginApplyMdxProp = require('babel-plugin-apply-mdx-type-prop')
88
const BabelPluginExtractImportNames = require('babel-plugin-extract-import-names')
9+
const BabelPluginExtractExportNames = require('babel-plugin-extract-export-names')
910

1011
function toJSX(node, parentNode = {}, options = {}) {
1112
if (node.type === 'root') {
@@ -79,13 +80,6 @@ function serializeRoot(node, options) {
7980
return true
8081
})
8182

82-
const exportNames = groups.export
83-
.map(node =>
84-
node.value.match(/^export\s*(var|const|let|class|function)?\s*(\w+)/)
85-
)
86-
.map(match => (Array.isArray(match) ? match[2] : null))
87-
.filter(Boolean)
88-
8983
const importStatements = groups.import
9084
.map(childNode => toJSX(childNode, node))
9185
.join('\n')
@@ -94,14 +88,6 @@ function serializeRoot(node, options) {
9488
.map(childNode => toJSX(childNode, node))
9589
.join('\n')
9690

97-
let layoutProps = 'const layoutProps = {'
98-
99-
if (exportNames.length !== 0) {
100-
layoutProps += '\n ' + exportNames.join(',\n ') + '\n'
101-
}
102-
103-
layoutProps += '};'
104-
10591
const mdxLayout = `const MDXLayout = ${layout ? layout : '"wrapper"'}`
10692

10793
const doc = groups.rest
@@ -120,16 +106,20 @@ MDXContent.isMDXComponent = true`
120106

121107
// Check JSX nodes against imports
122108
const babelPluginExtractImportNamesInstance = new BabelPluginExtractImportNames()
123-
transformSync(importStatements, {
109+
const babelPluginExtractExportNamesInstance = new BabelPluginExtractExportNames()
110+
const importsAndExports = [importStatements, exportStatements].join('\n')
111+
transformSync(importsAndExports, {
124112
configFile: false,
125113
babelrc: false,
126114
plugins: [
127115
require('@babel/plugin-syntax-jsx'),
128116
require('@babel/plugin-syntax-object-rest-spread'),
129-
babelPluginExtractImportNamesInstance.plugin
117+
babelPluginExtractImportNamesInstance.plugin,
118+
babelPluginExtractExportNamesInstance.plugin
130119
]
131120
})
132121
const importNames = babelPluginExtractImportNamesInstance.state.names
122+
const exportNames = babelPluginExtractExportNamesInstance.state.names
133123

134124
const babelPluginApplyMdxPropInstance = new BabelPluginApplyMdxProp()
135125
const babelPluginApplyMdxPropToExportsInstance = new BabelPluginApplyMdxProp()
@@ -154,6 +144,15 @@ MDXContent.isMDXComponent = true`
154144
]
155145
}).code
156146

147+
// TODO: Remove layout props entirely
148+
let layoutProps = 'const layoutProps = {'
149+
150+
if (exportNames.length !== 0) {
151+
layoutProps += '\n ' + exportNames.join(',\n ') + '\n'
152+
}
153+
154+
layoutProps += '};'
155+
157156
const allJsxNames = [
158157
...babelPluginApplyMdxPropInstance.state.names,
159158
...babelPluginApplyMdxPropToExportsInstance.state.names

‎packages/mdx/package.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
"@mdx-js/util": "^2.0.0-next.1",
4646
"babel-plugin-apply-mdx-type-prop": "^2.0.0-next.1",
4747
"babel-plugin-extract-import-names": "^2.0.0-next.1",
48+
"babel-plugin-extract-export-names": "^2.0.0-next.1",
4849
"camelcase-css": "2.0.1",
4950
"detab": "2.0.3",
5051
"hast-to-hyperscript": "9.0.0",

‎packages/remark-mdxjs/test/__snapshots__/test.js.snap‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ const makeShortcode = name => function MDXDefaultShortcode(props) {
88
console.warn(\\"Component \\" + name + \\" was not imported, exported, or provided by MDXProvider as global scope\\")
99
return <div {...props}/>
1010
};
11-
const Baz = makeShortcode(\\"Baz\\");
1211
const Paragraph = makeShortcode(\\"Paragraph\\");
1312
const Button = makeShortcode(\\"Button\\");
14-
const layoutProps = {};
13+
const layoutProps = {
14+
Baz
15+
};
1516
const MDXLayout = Foo
1617
export default function MDXContent({
1718
components,

‎yarn.lock‎

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12362,7 +12362,7 @@ gatsby-plugin-google-fonts@1.0.1:
1236212362
resolved "https://registry.yarnpkg.com/gatsby-plugin-google-fonts/-/gatsby-plugin-google-fonts-1.0.1.tgz#d71054f7bf207b9a8da227380369e18e6f4e0201"
1236312363
integrity sha512-p1NVkn27GUnDA5qHM+Z4cCcLCJIardzZXMon3640sT4xuL/AZJbsx3HEt2KY/5oZu0UXIkytkxzV2Da4rQeUIg==
1236412364

12365-
gatsby-plugin-mdx@1.2.26, gatsby-plugin-mdx@^1.2.26:
12365+
gatsby-plugin-mdx@1.2.26:
1236612366
version "1.2.26"
1236712367
resolved "https://registry.yarnpkg.com/gatsby-plugin-mdx/-/gatsby-plugin-mdx-1.2.26.tgz#3f5f2c929769cf0094eb78e0a052b916e40515d4"
1236812368
integrity sha512-1KZEBzRp69H6faiBHeTy0NmWr56Qa5MfLNhi3UqQdZDLRdVxCzgXML7TafBBXuBAsJJBCvQi0Df437fodkdpvQ==
@@ -12403,6 +12403,48 @@ gatsby-plugin-mdx@1.2.26, gatsby-plugin-mdx@^1.2.26:
1240312403
unist-util-remove "^1.0.3"
1240412404
unist-util-visit "^1.4.1"
1240512405

12406+
gatsby-plugin-mdx@^1.2.26, gatsby-plugin-mdx@^1.2.27:
12407+
version "1.2.27"
12408+
resolved "https://registry.yarnpkg.com/gatsby-plugin-mdx/-/gatsby-plugin-mdx-1.2.27.tgz#dadc9ce6e874b1f181c12b5cc019bb7217d4e457"
12409+
integrity sha512-2j5voALrvJ14JR9UzY9NygatVHRpGcm15jjJRDYtnT9k5ptKkqYLuiPcQ3eBxoqwjvAamLJ8WYRhc/poP/Ezuw==
12410+
dependencies:
12411+
"@babel/core" "^7.10.3"
12412+
"@babel/generator" "^7.10.3"
12413+
"@babel/helper-plugin-utils" "^7.10.3"
12414+
"@babel/plugin-proposal-object-rest-spread" "^7.10.3"
12415+
"@babel/preset-env" "^7.10.3"
12416+
"@babel/preset-react" "^7.10.1"
12417+
"@babel/types" "^7.10.3"
12418+
camelcase-css "^2.0.1"
12419+
change-case "^3.1.0"
12420+
core-js "^3.6.5"
12421+
dataloader "^1.4.0"
12422+
debug "^4.1.1"
12423+
escape-string-regexp "^1.0.5"
12424+
eval "^0.1.4"
12425+
fs-extra "^8.1.0"
12426+
gatsby-core-utils "^1.3.12"
12427+
gray-matter "^4.0.2"
12428+
json5 "^2.1.3"
12429+
loader-utils "^1.4.0"
12430+
lodash "^4.17.15"
12431+
mdast-util-to-string "^1.1.0"
12432+
mdast-util-toc "^3.1.0"
12433+
mime "^2.4.6"
12434+
p-queue "^5.0.0"
12435+
pretty-bytes "^5.3.0"
12436+
remark "^10.0.1"
12437+
remark-retext "^3.1.3"
12438+
retext-english "^3.0.4"
12439+
slugify "^1.4.4"
12440+
static-site-generator-webpack-plugin "^3.4.2"
12441+
style-to-object "^0.3.0"
12442+
underscore.string "^3.3.5"
12443+
unified "^8.4.2"
12444+
unist-util-map "^1.0.5"
12445+
unist-util-remove "^1.0.3"
12446+
unist-util-visit "^1.4.1"
12447+
1240612448
gatsby-plugin-page-creator@2.3.17, gatsby-plugin-page-creator@^2.3.17:
1240712449
version "2.3.17"
1240812450
resolved "https://registry.yarnpkg.com/gatsby-plugin-page-creator/-/gatsby-plugin-page-creator-2.3.17.tgz#9e63af4bb78342fbdd7a0c0f01c9f13409274c5b"

0 commit comments

Comments
 (0)