Skip to content

Commit 9c2072a

Browse files
authored
Merge pull request #7058 from EnterpriseDB/bugfix/ditch-broken-native-import
Replace native import behavior with plugin that doesn't suffer from namespace collision
2 parents 5270c18 + d235c41 commit 9c2072a

File tree

2 files changed

+100
-0
lines changed

2 files changed

+100
-0
lines changed

gatsby-config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,7 @@ module.exports = {
419419
remarkPlugins: [
420420
[require("./src/plugins/code-in-tables")],
421421
[require("./src/plugins/replacement-expression")],
422+
[require("./src/plugins/import-files")],
422423
[
423424
require("remark-admonitions"),
424425
{

src/plugins/import-files.js

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
const path = require("path");
2+
const { read } = require("to-vfile");
3+
const remark = require("remark");
4+
const mdx = require("remark-mdx");
5+
const remarkFrontmatter = require("remark-frontmatter");
6+
const admonitions = require("remark-admonitions");
7+
const visit = require("unist-util-visit");
8+
9+
// This plugin handles import ... statements, processing them prior to compilation of JSX
10+
// This is necessary only until we move to MDX 2 or later (and, probably drop Gatsby) because of a bug in
11+
// Gatsby's use of MDX 1 that allowed for namespace collisions between files when the same symbol name is
12+
// used for different imports. Ref: https://github.com/gatsbyjs/gatsby/discussions/25069
13+
function replaceImports(options) {
14+
return async (tree, file) => {
15+
const containingFiles = [...(options?.containingFiles || [])];
16+
containingFiles.push(file.path);
17+
18+
const importConstants = {};
19+
const importRegex = /import (?<const>\w+) +from +['"](?<path>[^'"]+\.mdx?)/;
20+
const componentRegex = /<(?<name>\w+)(?:\s+[^>]*)?>/;
21+
visit(tree, "import", (node, index, parent) => {
22+
const importMatch = node.value?.match(importRegex);
23+
if (importMatch) {
24+
importConstants[importMatch.groups.const] = importMatch.groups.path;
25+
parent.children.splice(index, 1);
26+
return index;
27+
}
28+
});
29+
30+
// no need to go further if no imports
31+
if (!Object.keys(importConstants).length) return;
32+
33+
// load imported MDX files and parse them into ASTs
34+
const processor = remark()
35+
.use(remarkFrontmatter)
36+
.use(admonitions, {
37+
tag: "!!!",
38+
icons: "none",
39+
infima: true,
40+
customTypes: {
41+
seealso: "note",
42+
hint: "tip",
43+
interactive: "interactive",
44+
},
45+
})
46+
.use(mdx)
47+
.use(replaceImports, { containingFiles });
48+
for (let [constName, importPath] of Object.entries(importConstants)) {
49+
if (importPath.startsWith("versioned/"))
50+
importPath = importPath.replace(
51+
/^versioned\//,
52+
path.resolve("product_docs/docs/") + "/",
53+
);
54+
if (importPath.startsWith("unversioned/"))
55+
importPath = importPath.replace(
56+
/^unversioned\//,
57+
path.resolve("advocacy_docs/") + "/",
58+
);
59+
importPath = path.resolve(path.dirname(file.path), importPath);
60+
// check for cycle
61+
if (containingFiles.includes(importPath)) {
62+
importConstants[constName] = `Import cycle detected:
63+
${containingFiles.join(" -> ")}
64+
NOT importing ${importPath} into ${file.path} again.`;
65+
console.error(importConstants[constName]);
66+
continue;
67+
}
68+
69+
try {
70+
let importedFile = await read(importPath);
71+
let mdxAST = processor.parse(importedFile);
72+
await processor.run(mdxAST, importedFile);
73+
mdxAST.path = importPath;
74+
importConstants[constName] = mdxAST;
75+
} catch (err) {
76+
importConstants[constName] =
77+
`Import ${importPath} into ${file.path} failed:
78+
${err}`;
79+
console.error(importConstants[constName]);
80+
continue;
81+
}
82+
}
83+
84+
// find and replace the imported symbol(s)
85+
visit(tree, "jsx", (node, index, parent) => {
86+
const componentMatch = node.value.match(componentRegex)?.groups?.name;
87+
if (!importConstants[componentMatch]) return;
88+
89+
// replace the node
90+
const replacements = importConstants[componentMatch]?.children || [
91+
{ type: "text", value: importConstants[componentMatch] || "error" },
92+
];
93+
parent.children.splice(index, 1, ...replacements);
94+
return index + replacements.length;
95+
});
96+
};
97+
}
98+
99+
module.exports = replaceImports;

0 commit comments

Comments
 (0)