storybook-react-rsbuild
Version:
Storybook for React and Rsbuild: Develop React components in isolation with Hot Reloading.
493 lines (482 loc) • 18.4 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 __esm = (fn, res) => function __init() {
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
};
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/plugins/react-docgen-typescript/utils/filter.ts
var defaultPropFilter;
var init_filter = __esm({
"src/plugins/react-docgen-typescript/utils/filter.ts"() {
"use strict";
defaultPropFilter = (prop) => {
return !prop.parent?.fileName.includes("node_modules");
};
}
});
// src/plugins/react-docgen-typescript/utils/typescript.ts
var typescript_exports = {};
__export(typescript_exports, {
getTSConfigFile: () => getTSConfigFile
});
function getTSConfigFile(tsconfigPath) {
try {
const basePath = (0, import_node_path.dirname)(tsconfigPath);
const configFile = import_typescript.default.readConfigFile(tsconfigPath, import_typescript.default.sys.readFile);
return import_typescript.default.parseJsonConfigFileContent(
configFile.config,
import_typescript.default.sys,
basePath,
{},
tsconfigPath
);
} catch (error) {
return {};
}
}
var import_node_path, import_typescript;
var init_typescript = __esm({
"src/plugins/react-docgen-typescript/utils/typescript.ts"() {
"use strict";
import_node_path = require("path");
import_typescript = __toESM(require("typescript"));
}
});
// src/plugins/react-docgen-typescript/utils/options.ts
var options_exports = {};
__export(options_exports, {
getGenerateOptions: () => getGenerateOptions
});
function getGenerateOptions(options) {
const { setDisplayName: setDisplayName2 = true, typePropName = "type" } = options;
return {
setDisplayName: setDisplayName2,
typePropName
};
}
var init_options = __esm({
"src/plugins/react-docgen-typescript/utils/options.ts"() {
"use strict";
}
});
// src/plugins/react-docgen-typescript/utils/generate.ts
var generate_exports = {};
__export(generate_exports, {
generateDocgenCodeBlock: () => generateDocgenCodeBlock
});
function createLiteral(value) {
switch (typeof value) {
case "string":
return import_typescript2.default.factory.createStringLiteral(value);
case "number":
return import_typescript2.default.factory.createNumericLiteral(value);
case "boolean":
return value ? import_typescript2.default.factory.createTrue() : import_typescript2.default.factory.createFalse();
}
}
function insertTsIgnoreBeforeStatement(statement) {
import_typescript2.default.setSyntheticLeadingComments(statement, [
{
text: " @ts-ignore",
// Leading space is important here
kind: import_typescript2.default.SyntaxKind.SingleLineCommentTrivia,
pos: -1,
end: -1
}
]);
return statement;
}
function setDisplayName(d) {
return insertTsIgnoreBeforeStatement(
import_typescript2.default.factory.createExpressionStatement(
import_typescript2.default.factory.createBinaryExpression(
import_typescript2.default.factory.createPropertyAccessExpression(
import_typescript2.default.factory.createIdentifier(d.displayName),
import_typescript2.default.factory.createIdentifier("displayName")
),
import_typescript2.default.SyntaxKind.EqualsToken,
import_typescript2.default.factory.createStringLiteral(d.displayName)
)
)
);
}
function createPropDefinition(propName, prop, options) {
const setDefaultValue = (defaultValue) => import_typescript2.default.factory.createPropertyAssignment(
import_typescript2.default.factory.createStringLiteral("defaultValue"),
// Use a more extensive check on defaultValue. Sometimes the parser
// returns an empty object.
defaultValue?.value !== void 0 && (typeof defaultValue.value === "string" || typeof defaultValue.value === "number" || typeof defaultValue.value === "boolean") ? import_typescript2.default.factory.createObjectLiteralExpression([
import_typescript2.default.factory.createPropertyAssignment(
import_typescript2.default.factory.createIdentifier("value"),
createLiteral(defaultValue.value)
)
]) : import_typescript2.default.factory.createNull()
);
const setStringLiteralField = (fieldName, fieldValue) => import_typescript2.default.factory.createPropertyAssignment(
import_typescript2.default.factory.createStringLiteral(fieldName),
import_typescript2.default.factory.createStringLiteral(fieldValue)
);
const setDescription = (description) => setStringLiteralField("description", description);
const setName = (name) => setStringLiteralField("name", name);
const setRequired = (required) => import_typescript2.default.factory.createPropertyAssignment(
import_typescript2.default.factory.createStringLiteral("required"),
required ? import_typescript2.default.factory.createTrue() : import_typescript2.default.factory.createFalse()
);
const setValue = (typeValue) => Array.isArray(typeValue) && typeValue.every((value) => typeof value.value === "string") ? import_typescript2.default.factory.createPropertyAssignment(
import_typescript2.default.factory.createStringLiteral("value"),
import_typescript2.default.factory.createArrayLiteralExpression(
typeValue.map(
(value) => import_typescript2.default.factory.createObjectLiteralExpression([
setStringLiteralField("value", value.value)
])
)
)
) : void 0;
const setType = (typeName, typeValue) => {
const objectFields = [setStringLiteralField("name", typeName)];
const valueField = setValue(typeValue);
if (valueField) {
objectFields.push(valueField);
}
return import_typescript2.default.factory.createPropertyAssignment(
import_typescript2.default.factory.createStringLiteral(options.typePropName),
import_typescript2.default.factory.createObjectLiteralExpression(objectFields)
);
};
return import_typescript2.default.factory.createPropertyAssignment(
import_typescript2.default.factory.createStringLiteral(propName),
import_typescript2.default.factory.createObjectLiteralExpression([
setDefaultValue(prop.defaultValue),
setDescription(prop.description),
setName(prop.name),
setRequired(prop.required),
setType(prop.type.name, prop.type.value)
])
);
}
function setComponentDocGen(d, options) {
return insertTsIgnoreBeforeStatement(
import_typescript2.default.factory.createExpressionStatement(
import_typescript2.default.factory.createBinaryExpression(
// SimpleComponent.__docgenInfo
import_typescript2.default.factory.createPropertyAccessExpression(
import_typescript2.default.factory.createIdentifier(d.displayName),
import_typescript2.default.factory.createIdentifier("__docgenInfo")
),
import_typescript2.default.SyntaxKind.EqualsToken,
import_typescript2.default.factory.createObjectLiteralExpression([
// SimpleComponent.__docgenInfo.description
import_typescript2.default.factory.createPropertyAssignment(
import_typescript2.default.factory.createStringLiteral("description"),
import_typescript2.default.factory.createStringLiteral(d.description)
),
// SimpleComponent.__docgenInfo.displayName
import_typescript2.default.factory.createPropertyAssignment(
import_typescript2.default.factory.createStringLiteral("displayName"),
import_typescript2.default.factory.createStringLiteral(d.displayName)
),
// SimpleComponent.__docgenInfo.props
import_typescript2.default.factory.createPropertyAssignment(
import_typescript2.default.factory.createStringLiteral("props"),
import_typescript2.default.factory.createObjectLiteralExpression(
Object.entries(d.props).map(
([propName, prop]) => createPropDefinition(propName, prop, options)
)
)
)
])
)
)
);
}
function generateDocgenCodeBlock(options) {
const sourceFile = import_typescript2.default.createSourceFile(
options.filename,
options.source,
import_typescript2.default.ScriptTarget.ESNext
);
const wrapInTryStatement = (statements) => import_typescript2.default.factory.createTryStatement(
import_typescript2.default.factory.createBlock(statements, true),
import_typescript2.default.factory.createCatchClause(
import_typescript2.default.factory.createVariableDeclaration(
import_typescript2.default.factory.createIdentifier("__react_docgen_typescript_loader_error")
),
import_typescript2.default.factory.createBlock([])
),
void 0
);
const codeBlocks = options.componentDocs.map(
(d) => wrapInTryStatement(
[
options.setDisplayName ? setDisplayName(d) : null,
setComponentDocGen(d, options)
].filter((s2) => s2 !== null)
)
);
const printer = import_typescript2.default.createPrinter({ newLine: import_typescript2.default.NewLineKind.LineFeed });
const printNode = (sourceNode) => printer.printNode(import_typescript2.default.EmitHint.Unspecified, sourceNode, sourceFile);
const s = new import_magic_string.default(options.source);
for (const node of codeBlocks) {
s.append(printNode(node));
}
return {
code: s.toString(),
map: s.generateMap()
};
}
var import_magic_string, import_typescript2;
var init_generate = __esm({
"src/plugins/react-docgen-typescript/utils/generate.ts"() {
"use strict";
import_magic_string = __toESM(require("magic-string"));
import_typescript2 = __toESM(require("typescript"));
}
});
// src/plugins/react-docgen-typescript/index.ts
var react_docgen_typescript_exports = {};
__export(react_docgen_typescript_exports, {
default: () => react_docgen_typescript_default
});
var import_pluginutils, getDocgen, startWatch, react_docgen_typescript_default;
var init_react_docgen_typescript = __esm({
"src/plugins/react-docgen-typescript/index.ts"() {
"use strict";
import_pluginutils = require("@rollup/pluginutils");
init_filter();
getDocgen = async (config) => {
const docGen = await import("react-docgen-typescript");
const {
tsconfigPath,
compilerOptions,
propFilter = defaultPropFilter,
setDisplayName: setDisplayName2,
typePropName,
...rest
} = config;
const docgenOptions = {
propFilter,
...rest
};
return docGen.withCompilerOptions(
// Compiler Options are passed in to the custom program.
{},
docgenOptions
);
};
startWatch = async (config, onProgramCreatedOrUpdated) => {
const { default: ts3 } = await import("typescript");
const { getTSConfigFile: getTSConfigFile2 } = await Promise.resolve().then(() => (init_typescript(), typescript_exports));
let compilerOptions = {
jsx: ts3.JsxEmit.React,
module: ts3.ModuleKind.CommonJS,
target: ts3.ScriptTarget.Latest
};
const tsconfigPath = config.tsconfigPath ?? "./tsconfig.json";
if (config.compilerOptions) {
compilerOptions = {
...compilerOptions,
...config.compilerOptions
};
} else {
const { options: tsOptions } = getTSConfigFile2(tsconfigPath);
compilerOptions = { ...compilerOptions, ...tsOptions };
}
const host = ts3.createWatchCompilerHost(
tsconfigPath,
compilerOptions,
ts3.sys,
ts3.createSemanticDiagnosticsBuilderProgram,
void 0,
() => {
}
);
host.afterProgramCreate = (program) => {
onProgramCreatedOrUpdated(program.getProgram());
};
return new Promise((resolve) => {
const watch = ts3.createWatchProgram(host);
resolve([watch.getProgram().getProgram(), watch.close]);
});
};
react_docgen_typescript_default = (config = {}) => {
let tsProgram;
let docGenParser;
let generateDocgenCodeBlock2;
let generateOptions;
let filter;
const moduleInvalidationQueue = /* @__PURE__ */ new Map();
let closeWatch;
return {
name: "rsbuild-plugin-react-docgen-typescript",
setup(api) {
api.modifyRsbuildConfig(async () => {
const { getGenerateOptions: getGenerateOptions2 } = await Promise.resolve().then(() => (init_options(), options_exports));
generateDocgenCodeBlock2 = (await Promise.resolve().then(() => (init_generate(), generate_exports))).generateDocgenCodeBlock;
docGenParser = await getDocgen(config);
generateOptions = getGenerateOptions2(config);
[tsProgram, closeWatch] = await startWatch(config, (program) => {
tsProgram = program;
for (const [
filepath,
invalidateModule
] of moduleInvalidationQueue.entries()) {
invalidateModule();
moduleInvalidationQueue.delete(filepath);
}
});
filter = (0, import_pluginutils.createFilter)(
config.include ?? ["**/**.tsx"],
config.exclude ?? ["**/**.stories.tsx"]
);
});
api.transform(
{
test: (id) => {
return filter(id);
}
},
async ({ code: src, resource: id }) => {
try {
const componentDocs = docGenParser.parseWithProgramProvider(
id,
() => tsProgram
);
if (!componentDocs.length) {
return { code: src };
}
const res = generateDocgenCodeBlock2({
filename: id,
source: src,
componentDocs,
...generateOptions
});
return res;
} catch (e) {
return src;
}
}
);
api.onCloseBuild(() => {
closeWatch();
});
}
};
};
}
});
// src/preset.ts
var preset_exports = {};
__export(preset_exports, {
core: () => core,
rsbuildFinal: () => rsbuildFinal
});
module.exports = __toCommonJS(preset_exports);
var import_node_path2 = require("path");
// src/react-docs.ts
var import_core = require("@rsbuild/core");
var import_docs_tools = require("storybook/internal/docs-tools");
// src/requirer.ts
function requirer(resolver, path) {
return resolver(path);
}
// src/react-docs.ts
var rsbuildFinalDocs = async (config, options) => {
if (!(0, import_docs_tools.hasDocsOrControls)(options))
return config;
const typescriptOptions = await options.presets.apply("typescript", {});
const debug = options.loglevel === "debug";
const { reactDocgen, reactDocgenTypescriptOptions } = typescriptOptions || {};
if (typeof reactDocgen !== "string") {
return config;
}
if (reactDocgen !== "react-docgen-typescript") {
return (0, import_core.mergeRsbuildConfig)(config, {
tools: {
rspack: {
module: {
rules: [
{
test: /\.(cjs|mjs|tsx?|jsx?)$/,
enforce: "pre",
loader: requirer(
require.resolve,
"storybook-react-rsbuild/loaders/react-docgen-loader"
),
options: {
debug
},
exclude: /(\.(stories|story)\.(js|jsx|ts|tsx))|(node_modules)/
}
]
}
}
}
});
}
let typescriptPresent;
try {
require.resolve("typescript");
typescriptPresent = true;
} catch (e) {
typescriptPresent = false;
}
if (reactDocgen === "react-docgen-typescript" && typescriptPresent) {
}
const reactDocGenTsPlugin = await Promise.resolve().then(() => (init_react_docgen_typescript(), react_docgen_typescript_exports));
return (0, import_core.mergeRsbuildConfig)(config, {
plugins: [
await reactDocGenTsPlugin.default({
...reactDocgenTypescriptOptions,
// We *need* this set so that RDT returns default values in the same format as react-docgen
savePropValueAsString: true
})
]
});
};
// src/preset.ts
var getAbsolutePath = (input) => (0, import_node_path2.dirname)(require.resolve((0, import_node_path2.join)(input, "package.json")));
var rsbuildFinal = async (config, options) => {
const finalConfig = rsbuildFinalDocs(config, options);
return finalConfig;
};
var core = async (config, options) => {
const framework = await options.presets.apply("framework");
return {
...config,
builder: {
name: getAbsolutePath("storybook-builder-rsbuild"),
options: typeof framework === "string" ? {} : framework.options.builder || {}
},
renderer: getAbsolutePath("@storybook/react")
};
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
core,
rsbuildFinal
});
;