dumi
Version:
📖 Documentation Generator of React Component
374 lines (372 loc) • 12.7 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/features/compile/utoopackLoaders.ts
var utoopackLoaders_exports = {};
__export(utoopackLoaders_exports, {
LOADER_CTX_FILENAME: () => LOADER_CTX_FILENAME,
UTOOPACK_DEMO_ASSETS_FILENAME: () => UTOOPACK_DEMO_ASSETS_FILENAME,
UTOOPACK_LOADER_CTX_KEY: () => UTOOPACK_LOADER_CTX_KEY,
buildLoaderContextContent: () => buildLoaderContextContent,
getUtoopackRules: () => getUtoopackRules
});
module.exports = __toCommonJS(utoopackLoaders_exports);
var import_esbuild = __toESM(require("@umijs/bundler-utils/compiled/esbuild"));
var import_utils = require("@umijs/utils");
var import_path = __toESM(require("path"));
var import_utils2 = require("./utils");
var mdLoaderPath = require.resolve("../../loaders/markdown");
var utilsRegisterPath = require.resolve("@umijs/utils");
var esbuildImplementorPath = require.resolve("@umijs/bundler-utils/compiled/esbuild");
var UTOOPACK_LOADER_CTX_KEY = "__dumiLoaderContextPath";
var LOADER_CTX_FILENAME = "dumi-loader-ctx.cjs";
var UTOOPACK_DEMO_ASSETS_FILENAME = "dumi-utoopack-demo-assets.jsonl";
function toSerializable(value) {
return JSON.parse(JSON.stringify(value));
}
function findInRequireCache(target) {
for (const [filename, mod] of Object.entries(require.cache)) {
if (!(mod == null ? void 0 : mod.exports))
continue;
const exp = mod.exports;
if (exp === target)
return { modulePath: filename, exportName: "module.exports" };
if ((exp == null ? void 0 : exp.default) === target)
return { modulePath: filename, exportName: "default" };
for (const [k, v] of Object.entries(exp)) {
if (v === target)
return { modulePath: filename, exportName: k };
}
}
return null;
}
function normalizeFnSource(fn) {
return Function.prototype.toString.call(fn).replace(/\s+/g, " ");
}
function isSameFunction(candidate, target) {
return typeof candidate === "function" && candidate.name === target.name && normalizeFnSource(candidate) === normalizeFnSource(target);
}
function findInModuleExports(target, mod) {
const exp = mod.exports;
if (!exp)
return null;
if (isSameFunction(exp, target)) {
return { modulePath: mod.filename, exportName: "module.exports" };
}
if (isSameFunction(exp == null ? void 0 : exp.default, target)) {
return { modulePath: mod.filename, exportName: "default" };
}
for (const [k, v] of Object.entries(exp)) {
if (isSameFunction(v, target)) {
return { modulePath: mod.filename, exportName: k };
}
}
return null;
}
function findInSourceFiles(target, sourceFiles) {
import_utils.register.register({ implementor: import_esbuild.default });
import_utils.register.clearFiles();
try {
for (const file of sourceFiles) {
try {
require(file);
const mod = require.cache[file];
if (!(mod == null ? void 0 : mod.exports))
continue;
const found = findInModuleExports(target, mod);
if (found)
return found;
} catch {
}
}
return null;
} finally {
for (const file of import_utils.register.getFiles()) {
delete require.cache[file];
}
for (const file of sourceFiles) {
delete require.cache[file];
}
import_utils.register.restore();
}
}
function toRequireRef(found) {
const modRef = `require(${JSON.stringify(found.modulePath)})`;
return found.exportName === "module.exports" ? modRef : `(${modRef})[${JSON.stringify(found.exportName)}]`;
}
function toTechStackRefs(techStacks) {
const refs = [];
for (const ts of techStacks) {
const ctor = ts.constructor;
let ref;
if (ctor !== Object) {
const found = findInRequireCache(ctor);
if (found) {
ref = `new (${toRequireRef(found)})()`;
}
} else {
const found = findInRequireCache(ts);
if (found) {
ref = toRequireRef(found);
}
}
if (ref) {
refs.push(ref);
} else {
const name = ts.constructor.name ? ` (${ts.constructor.name})` : "";
console.warn(
`[dumi] Utoopack markdown loader cannot serialize tech stack "${ts.name}"${name}. Please export the tech stack class from a module.`
);
}
}
return refs;
}
function toPluginTargetRef(target, sourceFiles) {
if (typeof target === "string")
return JSON.stringify(target);
const found = findInRequireCache(target) ?? findInSourceFiles(target, sourceFiles);
if (!found) {
const name = target.name ? ` "${target.name}"` : "";
throw new Error(
`Utoopack markdown loader requires extra unified plugin function${name} to be exported from a module.`
);
}
return toRequireRef(found);
}
function toPluginRefs(plugins = [], sourceFiles = []) {
return `[${plugins.map((plugin) => {
if (Array.isArray(plugin)) {
const [target, options] = plugin;
const optionsRef = typeof options === "undefined" ? "undefined" : JSON.stringify(options);
return `[${toPluginTargetRef(
target,
sourceFiles
)}, ${optionsRef}]`;
}
return toPluginTargetRef(plugin, sourceFiles);
}).join(", ")}]`;
}
function buildLoaderContextContent(techStacks, builtins = {}, routes = {}, extraRemarkPlugins = [], extraRehypePlugins = [], sourceFiles = [], demoAssetsFile) {
const refs = toTechStackRefs(techStacks);
return `'use strict';
try {
require(${JSON.stringify(
utilsRegisterPath
)}).register.register({ implementor: require(${JSON.stringify(
esbuildImplementorPath
)}) });
} catch (e) {
console.warn('[dumi] failed to register TS require hook for utoopack loader context:', e);
}
exports.techStacks = [${refs.join(", ")}];
exports.builtins = ${JSON.stringify(builtins)};
exports.routes = ${JSON.stringify(routes)};
exports.demoAssetsFile = ${JSON.stringify(demoAssetsFile)};
exports.extraRemarkPlugins = ${toPluginRefs(
extraRemarkPlugins,
sourceFiles
)};
exports.extraRehypePlugins = ${toPluginRefs(
extraRehypePlugins,
sourceFiles
)};
`;
}
var getUtoopackRules = (api, config = api.config) => {
const disableLiveDemo = (0, import_utils2.shouldDisabledLiveDemo)(api);
const loaderContextPath = import_path.default.join(
api.paths.absTmpPath,
LOADER_CTX_FILENAME
);
const cfgResolve = config.resolve ?? {};
const serializableBaseOpts = toSerializable({
cwd: api.cwd,
alias: config.alias || {},
resolve: {
atomDirs: cfgResolve.atomDirs ?? [{ type: "component", dir: "src" }],
docDirs: cfgResolve.docDirs ?? ["docs"],
codeBlockMode: cfgResolve.codeBlockMode ?? "active",
forceKebabCaseRouting: cfgResolve.forceKebabCaseRouting ?? true,
...cfgResolve.entryFile ? { entryFile: cfgResolve.entryFile } : {}
},
routes: {},
builtins: {},
locales: config.locales || [],
pkg: api.pkg,
disableLiveDemo,
[UTOOPACK_LOADER_CTX_KEY]: loaderContextPath
});
const externalDemoLoader = {
loader: require.resolve("../../loaders/demo"),
options: toSerializable({
cwd: api.cwd,
[UTOOPACK_LOADER_CTX_KEY]: loaderContextPath
})
};
return {
// handle ?watch=parent virtual module: return empty content to establish file-watching dependency
"**/*": [
{
condition: { query: /^\?watch=parent$/ },
loaders: [require.resolve("../../loaders/null")],
as: "*.js"
},
// handle raw content for demo source display (?dumi-raw)
{
condition: { query: /^\?dumi-raw$/ },
loaders: [
require.resolve("../../loaders/post-raw"),
require.resolve("raw-loader"),
require.resolve("../../loaders/pre-raw")
],
as: "*.js"
},
// handle untouched raw content for user imports like `import source from './file?raw'`
{
condition: { query: /^\?raw$/ },
loaders: [require.resolve("raw-loader")],
as: "*.js"
},
// handle external demo component files (?techStack=xxx)
// techStacks are NOT serializable; pass loaderContextPath and hydrate in the loader
{
condition: {
all: [{ query: /^\?techStack=.*$/ }, { path: /\.tsx$/ }]
},
loaders: [externalDemoLoader],
as: "*.tsx"
},
{
condition: {
all: [{ query: /^\?techStack=.*$/ }, { path: /\.ts$/ }]
},
loaders: [externalDemoLoader],
as: "*.ts"
},
{
condition: {
all: [{ query: /^\?techStack=.*$/ }, { path: /\.jsx$/ }]
},
loaders: [externalDemoLoader],
as: "*.jsx"
},
{
condition: {
all: [
{ query: /^\?techStack=.*$/ },
{ not: { path: /\.(tsx?|jsx)$/ } }
]
},
loaders: [externalDemoLoader],
as: "*.js"
}
],
// extract frontmatter/toc metadata from JS/TS page components (?type=frontmatter)
// NOTE:
// - Markdown ?type=frontmatter is already handled by the '*.md' rule below.
// - After the md loader outputs JS, utoopack will expose that virtual module as
// '*.md.js?type=frontmatter'. Without the extra path guard here, this JS rule
// runs again and page-loader overwrites markdown frontmatter with filename-based
// fallbacks like "Docs" / "C Md".
// - Excluding '*.md.js' keeps the markdown frontmatter result intact while still
// allowing real JS/TS page components to use page-loader.
"*.{js,jsx,ts,tsx}": {
condition: {
all: [
{ query: /^\?type=frontmatter$/ },
{ not: { path: /\.md\.js$/ } }
]
},
loaders: [require.resolve("../../loaders/page")],
as: "*.js"
},
// handle markdown files with different modes based on query type
"*.md": [
{
condition: { query: /^\?type=frontmatter$/ },
loaders: [
{
loader: mdLoaderPath,
options: { ...serializableBaseOpts, mode: "frontmatter" }
}
],
as: "*.js"
},
// extract plain text for full-text search
{
condition: { query: /^\?type=text$/ },
loaders: [
{
loader: mdLoaderPath,
options: { ...serializableBaseOpts, mode: "text" }
}
],
as: "*.js"
},
// extract demo index metadata from markdown
{
condition: { query: /^\?type=demo-index$/ },
loaders: [
{
loader: mdLoaderPath,
options: { ...serializableBaseOpts, mode: "demo-index" }
}
],
as: "*.js"
},
// compile inline demo code blocks
{
condition: { query: /^\?type=demo$/ },
loaders: [
{
loader: mdLoaderPath,
options: { ...serializableBaseOpts, mode: "demo" }
}
],
as: "*.js"
},
// default: transform markdown into a React page component
{
loaders: [
{
loader: mdLoaderPath,
options: serializableBaseOpts
}
],
as: "*.js"
}
]
};
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
LOADER_CTX_FILENAME,
UTOOPACK_DEMO_ASSETS_FILENAME,
UTOOPACK_LOADER_CTX_KEY,
buildLoaderContextContent,
getUtoopackRules
});