@mui/internal-docs-infra
Version:
MUI Infra - internal documentation creation tools.
154 lines (148 loc) • 5.44 kB
JavaScript
import { parseImportsAndComments } from "../loaderUtils/index.mjs";
import { processRelativeImports } from "../loaderUtils/processRelativeImports.mjs";
import { isJavaScriptModule } from "../loaderUtils/resolveModulePath.mjs";
/**
* Imports record passed to {@link LoadIsomorphicCodeSourceOptions.resolveImports}.
*
* Mirrors the shape produced by `parseImportsAndComments` once names have been
* flattened, so resolvers can look up each import by its source path.
*/
/**
* Creates a `LoadSource` function that performs all the platform-independent
* work shared between server-side and client-side source loaders: fetching
* the file via the supplied `fetchSource`, parsing its imports and comments,
* reshaping externals, and assembling `extraFiles` / `extraDependencies` for
* recursive loading.
*
* Platform-specific concerns (`fs.readFile`, `fetch`, module resolution
* against a real filesystem vs. a remote tree) are injected via the
* `fetchSource` and `resolveImports` options.
*/
export function createLoadIsomorphicCodeSource(options) {
const {
fetchSource,
resolveImports,
includeDependencies = true,
storeAt = 'flat',
removeCommentsWithPrefix,
notableCommentsPrefix
} = options;
return async function loadSource(url) {
const source = await fetchSource(url);
if (!includeDependencies) {
return {
source
};
}
// Static assets (JSON, images, etc.) have no imports to resolve.
const isJavascriptModuleFile = isJavaScriptModule(url);
const isCssFile = url.toLowerCase().endsWith('.css');
if (!isJavascriptModuleFile && !isCssFile) {
return {
source
};
}
const {
relative: importResult,
externals,
comments,
code: processedCode
} = await parseImportsAndComments(source, url, {
removeCommentsWithPrefix,
notableCommentsPrefix
});
// Use the comment-stripped source when `removeCommentsWithPrefix` rewrote
// the file; fall back to the raw source otherwise.
const finalSource = processedCode ?? source;
// Reshape externals from the parser's per-import structure into the
// framework's flat `Externals` record (drops position info that was only
// needed for source rewriting).
const transformedExternals = {};
for (const [modulePath, externalImport] of Object.entries(externals)) {
transformedExternals[modulePath] = externalImport.names.map(importName => ({
name: importName.name,
type: importName.type,
isType: importName.isType
}));
}
const externalsResult = Object.keys(transformedExternals).length > 0 ? transformedExternals : undefined;
if (Object.keys(importResult).length === 0) {
return {
source: finalSource,
externals: externalsResult,
comments
};
}
// `processRelativeImports` expects names as plain strings (alias-aware).
const importsCompatible = {};
for (const [importPath, {
url: importUrl,
names,
positions
}] of Object.entries(importResult)) {
importsCompatible[importPath] = {
url: importUrl,
names: names.map(({
name,
alias
}) => alias || name),
positions
};
}
let processedSource;
let extraFiles;
let extraDependencies;
if (isCssFile) {
// CSS imports are already absolute paths after `parseImportsAndComments`.
const result = processRelativeImports(finalSource, importsCompatible, storeAt);
processedSource = result.processedSource;
extraFiles = result.extraFiles;
extraDependencies = Object.values(importResult).map(({
url: importUrl
}) => importUrl);
} else {
// JS/TS: optionally resolve each import to an absolute URL via the
// platform-specific resolver. When no resolver is supplied, fall back to
// the raw import URLs (suitable for callers that pre-resolve themselves
// or don't need rewritten output).
let resolvedPathsMap;
if (resolveImports) {
const relativeImportsCompatible = {};
for (const [importPath, {
url: importUrl,
names,
includeTypeDefs,
positions
}] of Object.entries(importResult)) {
relativeImportsCompatible[importPath] = {
url: importUrl,
names: names.map(({
name,
alias
}) => alias || name),
positions,
...(includeTypeDefs && {
includeTypeDefs
})
};
}
resolvedPathsMap = await resolveImports(relativeImportsCompatible);
}
const result = processRelativeImports(finalSource, importsCompatible, storeAt, true, resolvedPathsMap);
processedSource = result.processedSource;
extraFiles = result.extraFiles;
extraDependencies = resolvedPathsMap ? Object.values(importResult).map(({
url: importUrl
}) => resolvedPathsMap.get(importUrl)).filter(resolved => resolved !== undefined) : Object.values(importResult).map(({
url: importUrl
}) => importUrl);
}
return {
source: processedSource,
extraFiles: Object.keys(extraFiles).length > 0 ? extraFiles : undefined,
extraDependencies: extraDependencies.length > 0 ? extraDependencies : undefined,
externals: externalsResult,
comments
};
};
}