UNPKG

@mui/internal-docs-infra

Version:

MUI Infra - internal documentation creation tools.

422 lines (386 loc) 18.6 kB
import _extends from "@babel/runtime/helpers/esm/extends"; import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray"; /** * Export variant functionality to add extra files like package.json, tsconfig, etc. * Users can pass configuration options that vary the output here. */ import { externalsToPackages } from "../pipeline/loaderUtils/index.js"; import { getFileNameFromUrl } from "../pipeline/loaderUtils/getFileNameFromUrl.js"; import { createPathContext } from "../CodeHighlighter/examineVariant.js"; import { mergeMetadata, extractMetadata } from "../CodeHighlighter/mergeMetadata.js"; /** * Merges multiple file objects into a single object. * Similar to mergeExternals but for file structures. * Automatically adds metadata: false to files that don't have a metadata property. */ function mergeFiles() { var merged = {}; for (var _len = arguments.length, fileSets = new Array(_len), _key = 0; _key < _len; _key++) { fileSets[_key] = arguments[_key]; } for (var _i = 0, _fileSets = fileSets; _i < _fileSets.length; _i++) { var fileSet = _fileSets[_i]; for (var _i2 = 0, _Object$entries = Object.entries(fileSet); _i2 < _Object$entries.length; _i2++) { var _Object$entries$_i = _slicedToArray(_Object$entries[_i2], 2), fileName = _Object$entries$_i[0], fileData = _Object$entries$_i[1]; // Later files override earlier ones (similar to Object.assign behavior) var normalizedData = typeof fileData === 'string' ? { source: fileData } : _extends({}, fileData); // Add metadata: false if not already set (source files default to false) if (!('metadata' in normalizedData)) { normalizedData.metadata = false; } merged[fileName] = normalizedData; } } return merged; } /** * Extract filename from URL or return undefined if not available */ export function getFilenameFromVariant(variantCode) { if (variantCode.fileName) { return variantCode.fileName; } if (variantCode.url) { var _getFileNameFromUrl = getFileNameFromUrl(variantCode.url), fileName = _getFileNameFromUrl.fileName; return fileName || undefined; } return undefined; } /** * Generate a unique entrypoint filename that doesn't conflict with existing files */ export function generateEntrypointFilename(existingFiles, sourceFilename, useTypescript) { var pathPrefix = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : ''; var ext = useTypescript ? 'tsx' : 'jsx'; var candidates = ["".concat(pathPrefix, "App.").concat(ext), "".concat(pathPrefix, "entrypoint.").concat(ext), "".concat(pathPrefix, "main.").concat(ext)]; // If we have a source filename, also try variations if (sourceFilename) { var baseName = sourceFilename.replace(/\.[^.]*$/, ''); candidates.push("".concat(pathPrefix).concat(baseName, "-entry.").concat(ext)); } for (var _i3 = 0, _candidates = candidates; _i3 < _candidates.length; _i3++) { var candidate = _candidates[_i3]; if (candidate !== "".concat(pathPrefix).concat(sourceFilename) && !existingFiles[candidate]) { return candidate; } } // Generate with hash if all candidates are taken var hash = Math.random().toString(36).substring(2, 8); return "".concat(pathPrefix, "entrypoint-").concat(hash, ".").concat(ext); } /** * Generate the relative import path from entrypoint to source file */ export function getRelativeImportPath(sourceFilename) { if (!sourceFilename) { return './App'; // Default fallback } // Remove extension for import var baseName = sourceFilename.replace(/\.[^.]*$/, ''); return "./".concat(baseName); } /** * Default HTML template function for Vite-based demos */ export function defaultHtmlTemplate(_ref) { var language = _ref.language, title = _ref.title, description = _ref.description, head = _ref.head, entrypoint = _ref.entrypoint; return "<!DOCTYPE html>\n<html lang=\"".concat(language, "\">\n <head>\n <meta charset=\"utf-8\" />\n <title>").concat(title, "</title>\n ").concat(description ? "<meta name=\"description\" content=\"".concat(description, "\" />") : '', "\n <meta name=\"viewport\" content=\"initial-scale=1, width=device-width\" />").concat(head ? "\n ".concat(head.split('\n').join('\n ')) : '', "\n </head>\n <body>\n <div id=\"root\"></div>").concat(entrypoint ? "\n <script type=\"module\" src=\"".concat(entrypoint, "\"></script>") : '', "\n </body>\n</html>\n"); } /** * Export a variant as a standalone project with metadata files properly scoped */ export function exportVariant(variantCode) { var _frameworkFiles$varia; var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var _config$title = config.title, title = _config$title === void 0 ? 'Demo' : _config$title, titlePrefix = config.titlePrefix, titleSuffix = config.titleSuffix, _config$description = config.description, description = _config$description === void 0 ? 'Demo created with Vite' : _config$description, descriptionPrefix = config.descriptionPrefix, descriptionSuffix = config.descriptionSuffix, variantName = config.variantName, _config$language = config.language, language = _config$language === void 0 ? 'en' : _config$language, _config$htmlPrefix = config.htmlPrefix, htmlPrefix = _config$htmlPrefix === void 0 ? '' : _config$htmlPrefix, _config$sourcePrefix = config.sourcePrefix, sourcePrefix = _config$sourcePrefix === void 0 ? 'src/' : _config$sourcePrefix, _config$assetPrefix = config.assetPrefix, assetPrefix = _config$assetPrefix === void 0 ? '' : _config$assetPrefix, _config$frameworkHand = config.frameworkHandlesEntrypoint, frameworkHandlesEntrypoint = _config$frameworkHand === void 0 ? false : _config$frameworkHand, _config$htmlSkipJsLin = config.htmlSkipJsLink, htmlSkipJsLink = _config$htmlSkipJsLin === void 0 ? false : _config$htmlSkipJsLin, htmlTemplate = config.htmlTemplate, headTemplate = config.headTemplate, rootIndexTemplate = config.rootIndexTemplate, _config$dependencies = config.dependencies, dependencies = _config$dependencies === void 0 ? {} : _config$dependencies, _config$devDependenci = config.devDependencies, devDependencies = _config$devDependenci === void 0 ? {} : _config$devDependenci, _config$scripts = config.scripts, scripts = _config$scripts === void 0 ? {} : _config$scripts, packageType = config.packageType, _config$packageJsonFi = config.packageJsonFields, packageJsonFields = _config$packageJsonFi === void 0 ? {} : _config$packageJsonFi, _config$tsconfigOptio = config.tsconfigOptions, tsconfigOptions = _config$tsconfigOptio === void 0 ? {} : _config$tsconfigOptio, _config$viteConfig = config.viteConfig, viteConfig = _config$viteConfig === void 0 ? {} : _config$viteConfig, _config$useTypescript = config.useTypescript, useTypescript = _config$useTypescript === void 0 ? false : _config$useTypescript, _config$extraMetadata = config.extraMetadataFiles, extraMetadataFiles = _config$extraMetadata === void 0 ? {} : _config$extraMetadata, _config$frameworkFile = config.frameworkFiles, frameworkFiles = _config$frameworkFile === void 0 ? {} : _config$frameworkFile, transformVariant = config.transformVariant, _config$versions = config.versions, versions = _config$versions === void 0 ? {} : _config$versions, resolveDependencies = config.resolveDependencies; // Build final title and description with prefixes and suffixes var finalTitle = [titlePrefix, title, titleSuffix].filter(Boolean).join(''); var finalDescription = [descriptionPrefix, description, descriptionSuffix].filter(Boolean).join(''); // Use extractMetadata to properly separate metadata and non-metadata files var _extractMetadata = extractMetadata(variantCode), processedVariantCode = _extractMetadata.variant, processedGlobals = _extractMetadata.metadata; if (transformVariant) { var transformed = transformVariant(processedVariantCode, variantName, processedGlobals); if (transformed) { // Re-extract metadata after transformation var result = transformed.variant && extractMetadata(transformed.variant); processedVariantCode = (result == null ? void 0 : result.variant) || processedVariantCode; // Start fresh with only the new metadata and explicitly transformed globals // Do NOT merge with the original processedGlobals to avoid duplication processedGlobals = _extends(_extends({}, result == null ? void 0 : result.metadata), transformed.globals); } } // If packageType is explicitly provided (even as undefined), use that value var finalPackageType; if ('packageType' in config) { finalPackageType = packageType; } else { finalPackageType = !Object.keys(frameworkFiles).length ? 'module' : undefined; } // Get existing extraFiles and source filename var sourceFilename = getFilenameFromVariant(processedVariantCode); // Get path context to understand navigation var pathContext = createPathContext(variantCode); // Determine if we need to rename the source file var ext = useTypescript ? 'tsx' : 'jsx'; var isSourceFileIndex = sourceFilename === "index.".concat(ext); var hasBackNavigation = pathContext.maxSourceBackNavigation > 0; var actualSourceFilename = sourceFilename; // Use urlDirectory to construct the full path from src root var directoryPath = pathContext.urlDirectory.slice(1).join('/'); // Remove 'src' and join the rest var actualRootFile = directoryPath ? "".concat(sourcePrefix).concat(directoryPath, "/").concat(sourceFilename) : "".concat(sourcePrefix).concat(sourceFilename); // If the source file is index.tsx and it's in the src root, we need to rename it if (isSourceFileIndex && !hasBackNavigation) { actualSourceFilename = generateEntrypointFilename(processedVariantCode.extraFiles || {}, sourceFilename, useTypescript); // When renaming due to conflicts, place the file in src root regardless of original location actualRootFile = "".concat(sourcePrefix).concat(actualSourceFilename); } // The main entrypoint is always src/index.tsx (or .jsx) var mainEntrypointFilename = "index.".concat(ext); var entrypoint = !htmlSkipJsLink ? "".concat(sourcePrefix).concat(mainEntrypointFilename) : undefined; // Get relative import path for the main component var importPath; if (!hasBackNavigation) { // Component is in src root - import directly importPath = getRelativeImportPath(actualSourceFilename); } else { // Component is in a subdirectory - import with full path from src root var componentPath = directoryPath ? "".concat(directoryPath, "/").concat(actualSourceFilename) : actualSourceFilename; importPath = "./".concat((componentPath || '').replace(/\.[^.]*$/, '')); // Remove extension } // Strip /index from the end of import paths since module resolution handles it automatically if (importPath.endsWith('/index')) { importPath = importPath.slice(0, -6); // Remove '/index' } var importString = processedVariantCode.namedExport ? "import { ".concat(processedVariantCode.namedExport, " as App } from '").concat(importPath, "';") : "import App from '".concat(importPath, "';"); // Collect all files that will be generated var generatedFiles = {}; // Update the variant's fileName if we renamed it if (isSourceFileIndex && !hasBackNavigation && actualSourceFilename && actualSourceFilename !== sourceFilename) { processedVariantCode.fileName = actualSourceFilename; } // Check if they're providing their own framework var isFramework = 'frameworkFiles' in config; var externalPackages = externalsToPackages(processedVariantCode.externals || []); var variantDeps = Object.keys(externalPackages).reduce(function (acc, pkg) { // Check if we have a specific version for this package first if (versions[pkg]) { acc[pkg] = versions[pkg]; } else if (resolveDependencies) { var resolvedDeps = resolveDependencies(pkg); Object.assign(acc, resolvedDeps); } else { // Simple fallback: just use 'latest' for each package acc[pkg] = 'latest'; } return acc; }, {}); // Collect metadata files to be generated var metadataFiles = {}; // Generate package.json var packageJson = _extends(_extends({ "private": true, name: finalTitle.toLowerCase().replace(/[^a-z0-9]/g, '-'), version: '0.0.0', description: finalDescription }, finalPackageType && { type: finalPackageType }), {}, { // Add type if specified scripts: _extends(_extends({}, !isFramework && { dev: 'vite', build: 'vite build', preview: 'vite preview' }), scripts), dependencies: _extends(_extends({ react: versions.react || 'latest', 'react-dom': versions['react-dom'] || 'latest' }, variantDeps), dependencies), devDependencies: _extends(_extends(_extends({}, !isFramework && { '@vitejs/plugin-react': 'latest', vite: 'latest' }), useTypescript && { typescript: 'latest', '@types/react': versions['@types/react'] || 'latest', '@types/react-dom': versions['@types/react-dom'] || 'latest' }), devDependencies) }, packageJsonFields); metadataFiles['package.json'] = { source: "".concat(JSON.stringify(packageJson, null, 2), "\n") }; // Generate entrypoint and HTML files unless framework handles them if (!frameworkHandlesEntrypoint) { // Create entrypoint file that imports the main component var defaultEntrypointContent = "import * as React from 'react';\nimport * as ReactDOM from 'react-dom/client';\n".concat(importString, "\n\nReactDOM.createRoot(document.getElementById('root')").concat(useTypescript ? '!' : '', ").render(\n <React.StrictMode>\n <App />\n </React.StrictMode>\n);\n"); var entrypointContent = rootIndexTemplate ? rootIndexTemplate({ importString: importString, useTypescript: useTypescript }) : defaultEntrypointContent; generatedFiles[mainEntrypointFilename] = { source: entrypointContent }; } // Add Vite config file only if no framework files (Vite-specific) if (!isFramework) { var viteConfigContent = "import { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n plugins: [react()],\n define: { 'process.env': {} },\n ...".concat(JSON.stringify(viteConfig, null, 2).split('\n').join('\n '), "\n});\n"); metadataFiles["vite.config.".concat(useTypescript ? 'ts' : 'js')] = { source: viteConfigContent }; } // Add TypeScript configuration if requested if (useTypescript) { // Check if frameworkFiles already includes a tsconfig var hasFrameworkTsConfig = (frameworkFiles == null ? void 0 : frameworkFiles.globals) && Object.keys(frameworkFiles.globals).some(function (fileName) { return fileName.includes('tsconfig.json') && !fileName.includes('tsconfig.node.json'); }); if (!hasFrameworkTsConfig) { // Main tsconfig.json (default Vite config) var defaultTsConfig = _extends({ compilerOptions: _extends({ target: 'ES2020', useDefineForClassFields: true, lib: ['ES2020', 'DOM', 'DOM.Iterable'], module: 'ESNext', skipLibCheck: true, moduleResolution: 'bundler', allowImportingTsExtensions: true, resolveJsonModule: true, isolatedModules: true, noEmit: true, jsx: 'react-jsx', strict: true, noUnusedLocals: true, noUnusedParameters: true, noFallthroughCasesInSwitch: true }, tsconfigOptions), include: ['src'] }, !isFramework && { references: [{ path: './tsconfig.node.json' }] }); metadataFiles['tsconfig.json'] = { source: "".concat(JSON.stringify(defaultTsConfig, null, 2), "\n") }; } // Only add tsconfig.node.json for Vite (not for framework files) if (!isFramework) { // Node tsconfig for Vite config var nodeTsConfig = { compilerOptions: { composite: true, skipLibCheck: true, module: 'ESNext', moduleResolution: 'bundler', allowSyntheticDefaultImports: true }, include: ['vite.config.ts'] }; metadataFiles['tsconfig.node.json'] = { source: "".concat(JSON.stringify(nodeTsConfig, null, 2), "\n") }; } } // Generate HTML file after all files are ready if (!frameworkHandlesEntrypoint) { // Add index.html var headContent = headTemplate ? headTemplate({ sourcePrefix: sourcePrefix, assetPrefix: assetPrefix, variant: processedVariantCode, variantName: variantName }) : undefined; var htmlContent = htmlTemplate ? htmlTemplate({ language: language, title: finalTitle, description: finalDescription, head: headContent, entrypoint: entrypoint, variant: processedVariantCode, variantName: variantName }) : defaultHtmlTemplate({ language: language, title: finalTitle, description: finalDescription, head: headContent, entrypoint: entrypoint }); var htmlFileName = htmlPrefix ? "".concat(htmlPrefix, "index.html") : 'index.html'; metadataFiles[htmlFileName] = { source: htmlContent }; } // Merge all metadata files including framework metadata and globals var allMetadataFiles = mergeFiles(processedGlobals || {}, metadataFiles, extraMetadataFiles, frameworkFiles.globals || {}); // Merge all files using mergeMetadata to properly position everything with 'src/' (sourcePrefix opt) prefix var allSourceFilesWithFramework = mergeFiles(processedVariantCode.extraFiles || {}, generatedFiles, ((_frameworkFiles$varia = frameworkFiles.variant) == null ? void 0 : _frameworkFiles$varia.extraFiles) || {}); // Update the variant with all source files including framework source files var finalVariantWithSources = _extends(_extends({}, processedVariantCode), {}, { extraFiles: allSourceFilesWithFramework }); // Use mergeMetadata to position everything correctly var finalVariant = mergeMetadata(finalVariantWithSources, allMetadataFiles, { metadataPrefix: sourcePrefix }); // Return new VariantCode with properly positioned files return { exported: finalVariant, rootFile: actualRootFile }; }