diff --git a/packages/documentation-framework/components/example/example.js b/packages/documentation-framework/components/example/example.js index 682f2f46f9..b0227899f3 100644 --- a/packages/documentation-framework/components/example/example.js +++ b/packages/documentation-framework/components/example/example.js @@ -79,7 +79,9 @@ export const Example = ({ // Content that appears between h3 and code block to explain example children, // Show dark theme switcher on full page examples - hasDarkThemeSwitcher = process.env.hasDarkThemeSwitcher + hasDarkThemeSwitcher = process.env.hasDarkThemeSwitcher, + // Map of relative imports matched to their npm package import path (passed to Codesandbox) + relativeImports }) => { if (isFullscreenPreview) { isFullscreen = false; @@ -98,9 +100,9 @@ export const Example = ({ const [editorCode, setEditorCode] = React.useState(code); const loc = useLocation(); - const scope = { ...liveContext, + // These 2 are in the bundle anyways for the site since we dogfood ...reactCoreModule, ...reactTableModule, ...(source === 'react-next' ? reactCoreNextModule : {}) @@ -158,7 +160,7 @@ export const Example = ({ const codeBoxParams = getParameters( lang === 'html' ? getStaticParams(title, editorCode) - : getReactParams(title, editorCode, scope, lang) + : getReactParams(title, editorCode, scope, lang, relativeImports) ); const fullscreenLink = loc.pathname.replace(/\/$/, '') + (loc.pathname.endsWith(source) ? '' : `/${source}`) diff --git a/packages/documentation-framework/helpers/codesandbox.js b/packages/documentation-framework/helpers/codesandbox.js index 854699c976..907d761099 100644 --- a/packages/documentation-framework/helpers/codesandbox.js +++ b/packages/documentation-framework/helpers/codesandbox.js @@ -2,6 +2,7 @@ const { parse } = require('@patternfly/ast-helpers'); const versions = require('../versions.json'); const overpass = require('./fonts'); const { capitalize } = require('./capitalize'); +const pathPrefix = process.env.pathPrefix; const getStaticParams = (title, html) => { const imgAssetRegex = /['"](\/assets\/images\/.*)['"]/g; @@ -106,7 +107,7 @@ function prettyExampleCode(title, code, declaration, identifier) { } // TODO: Make React examples work and use a template that has our assets. -function getReactParams(title, code, scope, lang) { +function getReactParams(title, code, scope, lang, relativeImports) { let toRender = null; try { let declaration = getExampleDeclaration(code); @@ -129,7 +130,7 @@ function getReactParams(title, code, scope, lang) { catch (err) { // Ignore } - + // Update image imports to point to pf.org const imgImportRegex = /import\s*(\w*).*['"](.*)(\.(png|jpe?g|webp|gif|svg))['"]/g; let imgImportMatch; while ((imgImportMatch = imgImportRegex.exec(code))) { @@ -137,6 +138,16 @@ function getReactParams(title, code, scope, lang) { code = code.replace(imgImportMatch[0], `const ${imgName} = "https://www.patternfly.org/v4${scope[imgName]}"`); } + const relImportRegex = /(?<=import[\s*{])([\w*{}\n\r\t, ]+)(?=[\s*]from\s["']([\.\/]+.*)["'])/gm; + let relImportMatch; + while (relImportMatch = relImportRegex.exec(code)) { + const [ relImportName, _name, relImportPath ] = relImportMatch; + if (relativeImports[relImportName]) { + code = code.replace(relImportPath, relativeImports[relImportName]); + } + } + + const dependencies = { '@patternfly/react-core': versions.Releases[0].versions['@patternfly/react-core'] }; diff --git a/packages/documentation-framework/scripts/md/mdx-hast-to-jsx.js b/packages/documentation-framework/scripts/md/mdx-hast-to-jsx.js index 5377210040..3e7c4729b4 100644 --- a/packages/documentation-framework/scripts/md/mdx-hast-to-jsx.js +++ b/packages/documentation-framework/scripts/md/mdx-hast-to-jsx.js @@ -69,12 +69,36 @@ function serializeRoot(node, options) { const importStatements = groups.import .map(node => node.value) - .map(imp => imp.replace(/(['"])\./g, (_, match) => `${match}${getRelPath()}${path.posix.sep}\.`)) + .map(imp => imp.replace(/(['"])\./g, (_, match) => `${match}${getRelPath()}${path.posix.sep}\.`)); + + // Map relative import name to '@package...' + const relativeImportsRegex = /(?:[\.\/]+.*)(@.*)['"]/gm; + let relativeImportMatch; + let relativeImportMatches = {}; + while (relativeImportMatch = relativeImportsRegex.exec(importStatements[0])) { + const [_match, absoluteImportPath] = relativeImportMatch; + if (absoluteImportPath && !absoluteImportPath.includes('srcImport')) { + // `@patternfly/react-core/src/demos/./examples/DashboardWrapper` to `DashboardWrapper` + let relativeFileImport = /(?<=\/)(\.+\/.*)/gm.exec(absoluteImportPath); + if (relativeFileImport) { + // Build map of relative imports (from example.js code) to npm package import path (used in codesandbox.js) + const relativeFilePath = relativeFileImport[0]; + const relativeImportName = relativeFilePath + .split('/') + .pop() + .split('.') + .shift(); + relativeImportMatches[relativeImportName] = absoluteImportPath; + } + } + } + + const importStatementsWithThumbnails = importStatements .concat(thumbnailImports) - .join('\n') + .join('\n'); // https://astexplorer.net/#/gist/9c531dd372dfc57e194c13c2889d31c3/03f2d6e889db1a733c6a079554e8af7784863739 - options.importSpecifiers = parse(importStatements).body + options.importSpecifiers = parse(importStatementsWithThumbnails).body .map(node => node.specifiers) .flat(1) .map(spec => spec.local ? spec.local.name : null) @@ -82,14 +106,13 @@ function serializeRoot(node, options) { const liveContext = options.importSpecifiers .filter(localName => !/srcImport.*/.test(localName)) // Images in MD like [!img](./src) .join(',\n '); - const childNodes = groups.rest .map(childNode => toJSX(childNode, node, options)) .join(''); let res = `import React from 'react'; import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from '@patternfly/documentation-framework/components'; -${importStatements} +${importStatementsWithThumbnails} const pageData = ${JSON.stringify(pageData, null, 2)}; `; if (liveContext) { @@ -97,6 +120,13 @@ const pageData = ${JSON.stringify(pageData, null, 2)}; ' ' + liveContext }\n};\n` } + if (relativeImportMatches) { + res += `pageData.relativeImports = {\n${ + ' ' + Object.entries(relativeImportMatches) + .map(([key, val]) => `'${key}': '${val}'`) + .join(',\n ') + }\n};\n`; + } if (examples) { res += `pageData.examples = {\n${ ' ' + Object.entries(examples)