UNPKG

storybook-react-rsbuild

Version:

Storybook for React and Rsbuild: Develop React components in isolation with Hot Reloading.

493 lines (482 loc) 18.4 kB
"use strict"; 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 });