@storybook/react 10.5.0-alpha.4 → 10.5.0-alpha.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/preset.js CHANGED
@@ -1,10 +1,10 @@
1
- import CJS_COMPAT_NODE_URL_wrq8d81c1df from 'node:url';
2
- import CJS_COMPAT_NODE_PATH_wrq8d81c1df from 'node:path';
3
- import CJS_COMPAT_NODE_MODULE_wrq8d81c1df from "node:module";
1
+ import CJS_COMPAT_NODE_URL_swx3ow7zp9i from 'node:url';
2
+ import CJS_COMPAT_NODE_PATH_swx3ow7zp9i from 'node:path';
3
+ import CJS_COMPAT_NODE_MODULE_swx3ow7zp9i from "node:module";
4
4
 
5
- var __filename = CJS_COMPAT_NODE_URL_wrq8d81c1df.fileURLToPath(import.meta.url);
6
- var __dirname = CJS_COMPAT_NODE_PATH_wrq8d81c1df.dirname(__filename);
7
- var require = CJS_COMPAT_NODE_MODULE_wrq8d81c1df.createRequire(import.meta.url);
5
+ var __filename = CJS_COMPAT_NODE_URL_swx3ow7zp9i.fileURLToPath(import.meta.url);
6
+ var __dirname = CJS_COMPAT_NODE_PATH_swx3ow7zp9i.dirname(__filename);
7
+ var require = CJS_COMPAT_NODE_MODULE_swx3ow7zp9i.createRequire(import.meta.url);
8
8
 
9
9
  // ------------------------------------------------------------
10
10
  // end of CJS compatibility banner, injected by Storybook's esbuild configuration
@@ -15314,2323 +15314,2427 @@ var extractArgTypesFromDocgenTypescript = async ({
15314
15314
  };
15315
15315
 
15316
15316
  // src/componentManifest/generator.ts
15317
- import { recast as recast2 } from "storybook/internal/babel";
15318
- import { Tag } from "storybook/internal/core-server";
15319
- import { storyNameFromExport } from "storybook/internal/csf";
15320
- import { extractDescription, loadCsf } from "storybook/internal/csf-tools";
15321
- import { logger as logger8 } from "storybook/internal/node-logger";
15322
-
15323
- // src/componentManifest/componentMeta/ComponentMetaManager.ts
15324
- import { logger as logger5 } from "storybook/internal/node-logger";
15325
- import { existsSync as existsSync3, watch } from "fs";
15326
- import * as path3 from "path";
15317
+ import {
15318
+ getStoryImportPathFromEntry,
15319
+ selectComponentEntriesByComponentId
15320
+ } from "storybook/internal/common";
15327
15321
 
15328
- // src/componentManifest/componentMeta/ComponentMetaProject.ts
15329
- var import_language_core = __toESM(require_language_core(), 1), import_typescript = __toESM(require_typescript(), 1);
15330
- import * as path2 from "path";
15322
+ // src/componentManifest/buildReactComponentDocgen.ts
15323
+ import { getComponentIdFromEntry } from "storybook/internal/common";
15324
+ import { extractDescription as extractDescription2 } from "storybook/internal/csf-tools";
15331
15325
 
15332
- // src/componentManifest/componentMeta/componentMetaExtractor.ts
15333
- var LARGE_SOURCE_THRESHOLD = 30, MAX_UNWRAP_DEPTH = 5, MAX_SERIALIZATION_DEPTH = 5;
15334
- function isLiteralType(type) {
15335
- return type.isStringLiteral() || type.isNumberLiteral();
15336
- }
15337
- function isUnionType(type) {
15338
- return type.isUnion();
15339
- }
15340
- function isWrappedExpression(typescript, expression) {
15341
- return typescript.isParenthesizedExpression(expression) || typescript.isAsExpression(expression) || typescript.isNonNullExpression(expression) || (typescript.isSatisfiesExpression?.(expression) ?? !1);
15342
- }
15343
- function resolveAliasedSymbol(typescript, checker, symbol) {
15344
- return symbol.flags & typescript.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
15345
- }
15346
- function getSymbolContextNode(symbol) {
15347
- return symbol.valueDeclaration ?? symbol.getDeclarations()?.[0];
15348
- }
15349
- function resolveComponentSymbolFromNode(typescript, checker, node) {
15350
- if (!node)
15351
- return;
15352
- let symbol = checker.getSymbolAtLocation(node);
15353
- return symbol ? resolveComponentSymbol(typescript, checker, symbol, node) : void 0;
15326
+ // src/componentManifest/extractComponentDescription.ts
15327
+ function extractComponentDescription(metaJsDoc, docgenDescription, docgenJsDocTags) {
15328
+ let jsdocComment = metaJsDoc || docgenDescription, extracted = jsdocComment ? extractJSDocInfo(jsdocComment) : void 0, tags = docgenJsDocTags ?? extracted?.tags ?? {}, description = extracted?.description;
15329
+ return {
15330
+ description: ((tags?.describe?.[0] || tags?.desc?.[0]) ?? description)?.trim(),
15331
+ summary: tags.summary?.[0],
15332
+ jsDocTags: tags
15333
+ };
15354
15334
  }
15355
- function resolveComponentSymbol(typescript, checker, symbol, contextNode, depth = 0) {
15356
- let resolved = resolveAliasedSymbol(typescript, checker, symbol);
15357
- if (depth > MAX_UNWRAP_DEPTH)
15358
- return resolved;
15359
- let declarationForPromotion = getSymbolContextNode(resolved);
15360
- if (declarationForPromotion && (typescript.isArrowFunction(declarationForPromotion) || typescript.isFunctionExpression(declarationForPromotion)) && declarationForPromotion.parent && typescript.isVariableDeclaration(declarationForPromotion.parent) && typescript.isIdentifier(declarationForPromotion.parent.name)) {
15361
- let variableSymbol = checker.getSymbolAtLocation(declarationForPromotion.parent.name);
15362
- variableSymbol && (resolved = resolveAliasedSymbol(typescript, checker, variableSymbol));
15363
- }
15364
- let declaration = getSymbolContextNode(resolved);
15365
- if (declaration) {
15366
- if (typescript.isShorthandPropertyAssignment(declaration)) {
15367
- let valueSymbol = checker.getShorthandAssignmentValueSymbol(declaration);
15368
- if (valueSymbol)
15369
- return resolveComponentSymbol(
15370
- typescript,
15371
- checker,
15372
- valueSymbol,
15373
- declaration.name,
15374
- depth + 1
15375
- );
15376
- }
15377
- if (typescript.isPropertyAssignment(declaration)) {
15378
- let next = resolveComponentSymbolFromNode(typescript, checker, declaration.initializer);
15379
- if (next)
15380
- return next;
15381
- }
15382
- if (typescript.isBinaryExpression(declaration) && declaration.operatorToken.kind === typescript.SyntaxKind.EqualsToken) {
15383
- let next = resolveComponentSymbolFromNode(typescript, checker, declaration.right);
15384
- if (next)
15385
- return next;
15386
- }
15335
+
15336
+ // src/componentManifest/getComponentImports.ts
15337
+ import { dirname as dirname6 } from "node:path";
15338
+ import { babelParse as babelParse2, recast, types as t2 } from "storybook/internal/babel";
15339
+ import { logger as logger6 } from "storybook/internal/node-logger";
15340
+
15341
+ // src/componentManifest/reactDocgenTypescript.ts
15342
+ import { dirname as dirname5 } from "node:path";
15343
+ import { logger as logger5 } from "storybook/internal/node-logger";
15344
+ var typeScriptPromise, reactDocgenTypescriptPromise, loadTypeScript = () => typeScriptPromise ??= import("typescript"), loadReactDocgenTypescript = () => reactDocgenTypescriptPromise ??= import("react-docgen-typescript"), LARGE_NON_USER_SOURCE_THRESHOLD = 30, getPropSource = (prop) => prop.parent?.fileName ?? prop.declarations?.[0]?.fileName, getLargeNonUserPropSources = (props) => {
15345
+ let countBySource = /* @__PURE__ */ new Map();
15346
+ for (let prop of Object.values(props)) {
15347
+ let source = getPropSource(prop);
15348
+ (source?.includes("node_modules") || source?.endsWith(".d.ts")) && countBySource.set(source, (countBySource.get(source) ?? 0) + 1);
15387
15349
  }
15388
- let typeSymbol = (!!(resolved.flags & typescript.SymbolFlags.Property) || declaration !== void 0 && (typescript.isPropertyAssignment(declaration) || typescript.isShorthandPropertyAssignment(declaration) || typescript.isPropertySignature(declaration) || typescript.isPropertyDeclaration(declaration) || typescript.isBinaryExpression(declaration) && declaration.operatorToken.kind === typescript.SyntaxKind.EqualsToken)) && checker.getTypeOfSymbolAtLocation(resolved, contextNode).getSymbol?.();
15389
- if (typeSymbol) {
15390
- let resolvedTypeSymbol = resolveAliasedSymbol(typescript, checker, typeSymbol), typeDeclaration = getSymbolContextNode(resolvedTypeSymbol);
15391
- if (resolvedTypeSymbol !== resolved && typeDeclaration)
15392
- return resolveComponentSymbol(
15393
- typescript,
15394
- checker,
15395
- resolvedTypeSymbol,
15396
- typeDeclaration,
15397
- depth + 1
15398
- );
15350
+ let largeNonUserSources = /* @__PURE__ */ new Set();
15351
+ for (let [source, count] of countBySource)
15352
+ count > LARGE_NON_USER_SOURCE_THRESHOLD && largeNonUserSources.add(source);
15353
+ return largeNonUserSources;
15354
+ };
15355
+ function findDisplayNameAssignment(typescript, sourceFile, identifierName) {
15356
+ for (let statement of sourceFile.statements) {
15357
+ if (!typescript.isExpressionStatement(statement))
15358
+ continue;
15359
+ let expr = statement.expression;
15360
+ if (typescript.isBinaryExpression(expr) && expr.operatorToken.kind === typescript.SyntaxKind.EqualsToken && typescript.isPropertyAccessExpression(expr.left) && expr.left.name.text === "displayName" && typescript.isIdentifier(expr.left.expression) && expr.left.expression.text === identifierName && typescript.isStringLiteral(expr.right))
15361
+ return expr.right.text;
15399
15362
  }
15400
- return resolved;
15401
15363
  }
15402
- function resolvePropsFromStoryFile(typescript, checker, storySourceFile, componentRef) {
15403
- let importSpecifier = componentRef.importId, importName = componentRef.importName, memberAccess = componentRef.member;
15404
- if (!importSpecifier)
15405
- return;
15406
- let importSymbol;
15407
- for (let stmt of storySourceFile.statements) {
15408
- if (!typescript.isImportDeclaration(stmt))
15409
- continue;
15410
- let moduleSpec = stmt.moduleSpecifier;
15411
- if (!typescript.isStringLiteral(moduleSpec) || moduleSpec.text !== importSpecifier)
15364
+ function getExportNameMap(typescript, checker, sourceFile) {
15365
+ let moduleSymbol = checker.getSymbolAtLocation(sourceFile);
15366
+ if (!moduleSymbol)
15367
+ return /* @__PURE__ */ new Map();
15368
+ let result = /* @__PURE__ */ new Map(), fileName = sourceFile.fileName.replace(/.*\//, "").replace(/\.[^.]+$/, "");
15369
+ for (let exportSymbol of checker.getExportsOfModule(moduleSymbol)) {
15370
+ let resolved = exportSymbol.flags & typescript.SymbolFlags.Alias ? checker.getAliasedSymbol(exportSymbol) : exportSymbol, declaration = resolved.valueDeclaration ?? resolved.getDeclarations()?.[0];
15371
+ if (!declaration)
15412
15372
  continue;
15413
- let clause = stmt.importClause;
15414
- if (clause) {
15415
- if (importName === "default") {
15416
- if (clause.name && (importSymbol = checker.getSymbolAtLocation(clause.name)), !importSymbol && clause.namedBindings && typescript.isNamedImports(clause.namedBindings)) {
15417
- for (let spec of clause.namedBindings.elements)
15418
- if ((spec.propertyName ?? spec.name).text === "default") {
15419
- importSymbol = checker.getSymbolAtLocation(spec.name);
15420
- break;
15421
- }
15422
- }
15423
- } else if (clause.namedBindings && typescript.isNamedImports(clause.namedBindings)) {
15424
- for (let spec of clause.namedBindings.elements)
15425
- if ((spec.propertyName ?? spec.name).text === importName) {
15426
- importSymbol = checker.getSymbolAtLocation(spec.name);
15427
- break;
15428
- }
15429
- }
15430
- if (!importSymbol && memberAccess && clause.namedBindings && typescript.isNamespaceImport(clause.namedBindings) && (importSymbol = checker.getSymbolAtLocation(clause.namedBindings.name)), importSymbol)
15431
- break;
15432
- }
15433
- }
15434
- if (!importSymbol)
15435
- return;
15436
- let result;
15437
- function extractPropsFromJsx(node) {
15438
- let sig = checker.getResolvedSignature(node);
15439
- if (!sig)
15440
- return;
15441
- let params = sig.getParameters();
15442
- return params.length === 0 ? checker.getTypeFromTypeNode(typescript.factory.createTypeLiteralNode([])) : checker.getTypeOfSymbolAtLocation(params[0], node);
15443
- }
15444
- function visit(node) {
15445
- if (!result) {
15446
- if (typescript.isJsxSelfClosingElement(node) || typescript.isJsxOpeningElement(node)) {
15447
- let tagName = node.tagName;
15448
- if (memberAccess) {
15449
- if (typescript.isPropertyAccessExpression(tagName) && tagName.name.text === memberAccess) {
15450
- let leftSym = checker.getSymbolAtLocation(tagName.expression);
15451
- if (leftSym && importSymbol && leftSym === importSymbol) {
15452
- let propsType = extractPropsFromJsx(node);
15453
- if (propsType) {
15454
- let memberSymbol = checker.getSymbolAtLocation(tagName.name) ?? checker.getTypeAtLocation(tagName.expression).getProperty(tagName.name.text) ?? resolveComponentSymbolFromNode(typescript, checker, tagName);
15455
- result = {
15456
- componentRef,
15457
- propsType,
15458
- symbol: memberSymbol ? resolveComponentSymbol(typescript, checker, memberSymbol, tagName.name) : resolveAliasedSymbol(typescript, checker, importSymbol)
15459
- };
15460
- return;
15461
- }
15462
- }
15463
- }
15464
- } else if (typescript.isIdentifier(tagName)) {
15465
- let sym = checker.getSymbolAtLocation(tagName);
15466
- if (sym && importSymbol && sym === importSymbol) {
15467
- let propsType = extractPropsFromJsx(node);
15468
- if (propsType) {
15469
- result = {
15470
- componentRef,
15471
- propsType,
15472
- symbol: resolveAliasedSymbol(typescript, checker, sym)
15473
- };
15474
- return;
15475
- }
15476
- }
15477
- }
15478
- }
15479
- typescript.forEachChild(node, visit);
15373
+ let type = checker.getTypeOfSymbolAtLocation(resolved, declaration), isStateless = type.getCallSignatures().some((sig) => {
15374
+ let params = sig.getParameters();
15375
+ return params.length === 1 || params.length > 0 && params[0].getName() === "props";
15376
+ }), isStateful = type.getConstructSignatures().some(
15377
+ (sig) => sig.getReturnType().getProperty("props") !== void 0
15378
+ );
15379
+ if (isStateless || isStateful) {
15380
+ let exportName = exportSymbol.getName(), resolvedName = resolved.getName();
15381
+ result.set(resolvedName, exportName), exportName === "default" && result.set(fileName, "default");
15382
+ let displayNameValue = findDisplayNameAssignment(typescript, sourceFile, resolvedName);
15383
+ displayNameValue && result.set(displayNameValue, exportName);
15480
15384
  }
15481
15385
  }
15482
- return visit(storySourceFile), result;
15386
+ return result;
15483
15387
  }
15484
- function resolvePropsFromComponentType(typescript, checker, componentType) {
15485
- let callSigs = componentType.getCallSignatures();
15486
- if (callSigs.length > 0) {
15487
- let sig = callSigs[0];
15488
- if (sig.parameters.length === 0)
15489
- return checker.getVoidType();
15490
- let propsType = checker.getTypeOfSymbol(sig.parameters[0]);
15491
- if (!(propsType.flags & typescript.TypeFlags.Any))
15492
- return propsType;
15493
- }
15494
- let ctorSigs = componentType.getConstructSignatures();
15495
- for (let sig of ctorSigs) {
15496
- let propsSym = sig.getReturnType().getProperty("props");
15497
- if (propsSym) {
15498
- let propsType = checker.getTypeOfSymbol(propsSym);
15499
- if (!(propsType.flags & typescript.TypeFlags.Any))
15500
- return propsType;
15501
- }
15388
+ var cachedCompilerOptions, cachedFileNames, previousProgram, parser, cachedParserOptionsKey;
15389
+ function invalidateParser() {
15390
+ parser = void 0, cachedCompilerOptions = void 0, cachedFileNames = void 0, cachedParserOptionsKey = void 0;
15391
+ }
15392
+ async function getParser5(userOptions) {
15393
+ let [typescript, reactDocgenTypescript] = await Promise.all([
15394
+ loadTypeScript(),
15395
+ loadReactDocgenTypescript()
15396
+ ]), optionsKey = JSON.stringify(userOptions ?? {});
15397
+ if (parser && cachedParserOptionsKey !== optionsKey && (parser = void 0), !parser) {
15398
+ let configPath = findTsconfigPath(process.cwd());
15399
+ if (cachedCompilerOptions = { noErrorTruncation: !0, strict: !0 }, configPath) {
15400
+ let { config } = typescript.readConfigFile(configPath, typescript.sys.readFile), parsed = typescript.parseJsonConfigFileContent(
15401
+ config,
15402
+ typescript.sys,
15403
+ dirname5(configPath)
15404
+ );
15405
+ cachedCompilerOptions = { ...parsed.options, noErrorTruncation: !0 }, cachedFileNames = parsed.fileNames;
15406
+ } else
15407
+ logger5.warn(
15408
+ "No tsconfig.json (or tsconfig.base.json / tsconfig.app.json) found. TypeScript component props will not be documented by react-docgen-typescript. Create a tsconfig.json in your project root to enable automatic controls."
15409
+ );
15410
+ let program = typescript.createProgram(
15411
+ cachedFileNames ?? [],
15412
+ cachedCompilerOptions,
15413
+ void 0,
15414
+ previousProgram
15415
+ );
15416
+ previousProgram = program;
15417
+ let parserOptions = {
15418
+ shouldExtractLiteralValuesFromEnum: !0,
15419
+ shouldRemoveUndefinedFromOptional: !0,
15420
+ ...userOptions,
15421
+ // Always force savePropValueAsString so default values are in a consistent format
15422
+ savePropValueAsString: !0
15423
+ };
15424
+ parser = {
15425
+ program,
15426
+ fileParser: reactDocgenTypescript.withCompilerOptions(cachedCompilerOptions, parserOptions)
15427
+ }, cachedParserOptionsKey = optionsKey;
15502
15428
  }
15429
+ return { ...parser, typescript };
15503
15430
  }
15504
- function getPropSourceFile(prop) {
15505
- let declarations = prop.getDeclarations();
15506
- if (declarations?.length) {
15507
- for (let decl of declarations) {
15508
- let fileName = decl.getSourceFile().fileName;
15509
- if (!fileName.includes("node_modules") && !fileName.endsWith(".d.ts"))
15510
- return fileName;
15511
- }
15512
- return declarations[0].getSourceFile().fileName;
15513
- }
15514
- }
15515
- function getParentType(typescript, prop) {
15516
- let declarations = prop.getDeclarations();
15517
- if (!declarations?.length)
15518
- return;
15519
- let node = declarations[0].parent;
15520
- for (; node; ) {
15521
- if (typescript.isInterfaceDeclaration(node) || typescript.isTypeAliasDeclaration(node))
15522
- return {
15523
- name: node.name.getText(),
15524
- fileName: node.getSourceFile().fileName
15525
- };
15526
- node = node.parent;
15527
- }
15431
+ function matchComponentDoc(docs, {
15432
+ importName,
15433
+ localImportName,
15434
+ componentName
15435
+ }) {
15436
+ if (docs.length !== 0)
15437
+ return docs.length === 1 ? docs[0] : docs.find(
15438
+ (doc) => doc.exportName === importName || doc.exportName === localImportName || doc.displayName === importName || doc.displayName === localImportName || doc.displayName === componentName
15439
+ );
15528
15440
  }
15529
- function getAllDeclarationParents(typescript, prop) {
15530
- let declarations = prop.getDeclarations();
15531
- if (!declarations?.length)
15532
- return;
15533
- let parents = [];
15534
- for (let declaration of declarations) {
15535
- let { parent } = declaration;
15536
- parent && (typescript.isInterfaceDeclaration(parent) || typescript.isTypeAliasDeclaration(parent) ? parents.push({
15537
- name: parent.name.getText(),
15538
- fileName: parent.getSourceFile().fileName
15539
- }) : typescript.isTypeLiteralNode(parent) && parents.push({
15540
- name: "TypeLiteral",
15541
- fileName: parent.getSourceFile().fileName
15542
- }));
15543
- }
15544
- return parents.length > 0 ? parents : void 0;
15441
+ function getReactDocgenTypescriptError(path5, {
15442
+ importName,
15443
+ localImportName,
15444
+ componentName
15445
+ }, docs) {
15446
+ return docs.length === 0 ? {
15447
+ name: "react-docgen-typescript found no component docs",
15448
+ message: [
15449
+ `File: ${path5}`,
15450
+ "react-docgen-typescript did not return any component docs for this file."
15451
+ ].join(`
15452
+ `)
15453
+ } : {
15454
+ name: "react-docgen-typescript could not match component docs",
15455
+ message: [
15456
+ `File: ${path5}`,
15457
+ "react-docgen-typescript returned component docs for this file, but none matched the story's component import.",
15458
+ `Looked for: componentName=${componentName}, localImportName=${localImportName ?? "<none>"}, importName=${importName ?? "<none>"}.`
15459
+ ].join(`
15460
+ `)
15461
+ };
15545
15462
  }
15546
- function serializeType(typescript, checker, type, isRequired, depth = 0) {
15547
- if (depth > MAX_SERIALIZATION_DEPTH)
15548
- return { name: checker.typeToString(type) };
15549
- if (type.isUnion()) {
15550
- let nonUndefinedTypes = type.types.filter(
15551
- (t6) => !(t6.getFlags() & typescript.TypeFlags.Undefined)
15552
- ), literalMembers = nonUndefinedTypes.filter(isLiteralType);
15553
- if (literalMembers.length > 0 && literalMembers.length === nonUndefinedTypes.length)
15463
+ var parseWithReactDocgenTypescript = asyncCache(
15464
+ async (filePath, userOptions) => {
15465
+ let { program, fileParser, typescript } = await getParser5(userOptions), checker = program.getTypeChecker(), sourceFile = program.getSourceFile(filePath), docs = fileParser.parseWithProgramProvider(filePath, () => program), exportNameMap = sourceFile ? getExportNameMap(typescript, checker, sourceFile) : /* @__PURE__ */ new Map();
15466
+ return docs.map((doc) => {
15467
+ let largeNonUserSources = getLargeNonUserPropSources(doc.props);
15554
15468
  return {
15555
- name: "enum",
15556
- raw: literalMembers.map((m) => checker.typeToString(m)).join(" | "),
15557
- value: literalMembers.map((m) => ({
15558
- value: JSON.stringify(m.value)
15559
- }))
15469
+ ...doc,
15470
+ // Use name-based lookup: displayName is the resolved symbol name, so look it up in the
15471
+ // export map to get the public export name. Falls back to displayName when not aliased.
15472
+ exportName: exportNameMap.get(doc.displayName) ?? doc.displayName,
15473
+ // Filter out bulk props from non-user sources (React built-ins, DOM, CSS-in-JS system props)
15474
+ props: Object.fromEntries(
15475
+ Object.entries(doc.props).filter(([, prop]) => {
15476
+ let source = getPropSource(prop);
15477
+ return !source || !largeNonUserSources.has(source);
15478
+ })
15479
+ )
15560
15480
  };
15561
- if (!isRequired && nonUndefinedTypes.length === 1 && nonUndefinedTypes.length < type.types.length)
15562
- return { name: checker.typeToString(nonUndefinedTypes[0]) };
15563
- }
15564
- let constraint = type.getConstraint?.();
15565
- return constraint && constraint !== type ? serializeType(typescript, checker, constraint, isRequired, depth + 1) : { name: checker.typeToString(type) };
15566
- }
15567
- function unwrapToFunction(typescript, node, depth = 0, checker) {
15568
- if (!(depth > MAX_UNWRAP_DEPTH)) {
15569
- if (typescript.isArrowFunction(node) || typescript.isFunctionExpression(node) || typescript.isFunctionDeclaration(node))
15570
- return node;
15571
- if (typescript.isCallExpression(node))
15572
- for (let arg of node.arguments) {
15573
- let fn = unwrapToFunction(typescript, arg, depth + 1, checker);
15574
- if (fn)
15575
- return fn;
15481
+ });
15482
+ },
15483
+ { name: "parseWithReactDocgenTypescript" }
15484
+ );
15485
+
15486
+ // src/componentManifest/getComponentImports.ts
15487
+ var baseIdentifier = (component) => component.split(".")[0] ?? component, isTypeSpecifier = (s) => t2.isImportSpecifier(s) && s.importKind === "type", importedName = (im) => t2.isIdentifier(im) ? im.name : im.value, addUniqueBy = (arr, item, eq2) => {
15488
+ arr.find(eq2) || arr.push(item);
15489
+ }, getComponents = async ({
15490
+ csf,
15491
+ storyFilePath,
15492
+ typescriptOptions = {},
15493
+ docgenEngine,
15494
+ additionalComponentNames = []
15495
+ }) => {
15496
+ let { reactDocgenTypescriptOptions } = typescriptOptions, program = csf._file.path, componentSet = /* @__PURE__ */ new Set(), componentDepth = /* @__PURE__ */ new Map(), localToImport = /* @__PURE__ */ new Map(), jsxDepth = 0;
15497
+ program.traverse({
15498
+ JSXElement: {
15499
+ enter() {
15500
+ jsxDepth++;
15501
+ },
15502
+ exit() {
15503
+ jsxDepth--;
15576
15504
  }
15577
- if (typescript.isParenthesizedExpression(node) || typescript.isAsExpression(node))
15578
- return unwrapToFunction(typescript, node.expression, depth + 1, checker);
15579
- if (typescript.isIdentifier(node) && checker) {
15580
- let symbol = checker.getSymbolAtLocation(node);
15581
- if (symbol) {
15582
- let decl = (symbol.flags & typescript.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol).valueDeclaration;
15583
- if (decl && typescript.isVariableDeclaration(decl) && decl.initializer)
15584
- return unwrapToFunction(typescript, decl.initializer, depth + 1, checker);
15585
- if (decl && typescript.isFunctionDeclaration(decl))
15586
- return decl;
15505
+ },
15506
+ JSXOpeningElement(p) {
15507
+ let n = p.node.name, name;
15508
+ if (t2.isJSXIdentifier(n))
15509
+ name = n.name, name && /[A-Z]/.test(name.charAt(0)) && componentSet.add(name);
15510
+ else if (t2.isJSXMemberExpression(n)) {
15511
+ let jsxNameToString = (nm) => t2.isJSXIdentifier(nm) ? nm.name : `${jsxNameToString(nm.object)}.${jsxNameToString(nm.property)}`;
15512
+ name = jsxNameToString(n), componentSet.add(name);
15513
+ }
15514
+ if (name) {
15515
+ let depth = jsxDepth - 1, existing = componentDepth.get(name);
15516
+ (existing === void 0 || depth < existing) && componentDepth.set(name, depth);
15587
15517
  }
15588
15518
  }
15589
- }
15590
- }
15591
- function resolveLiteralValue(typescript, checker, node, depth = 0) {
15592
- if (depth > MAX_UNWRAP_DEPTH || typescript.isStringLiteral(node) || typescript.isNumericLiteral(node) || typescript.isNoSubstitutionTemplateLiteral(node) || node.kind === typescript.SyntaxKind.TrueKeyword || node.kind === typescript.SyntaxKind.FalseKeyword || node.kind === typescript.SyntaxKind.NullKeyword)
15593
- return node.getText();
15594
- if (typescript.isIdentifier(node)) {
15595
- if (node.text === "undefined")
15596
- return "undefined";
15597
- let symbol = checker.getSymbolAtLocation(node);
15598
- if (!symbol)
15599
- return node.getText();
15600
- let decl = (symbol.flags & typescript.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol).valueDeclaration;
15601
- return decl && typescript.isVariableDeclaration(decl) && decl.initializer || decl && typescript.isEnumMember(decl) && decl.initializer || decl && typescript.isBindingElement(decl) && decl.initializer ? resolveLiteralValue(typescript, checker, decl.initializer, depth + 1) : node.getText();
15602
- }
15603
- if (typescript.isPropertyAccessExpression(node)) {
15604
- let symbol = checker.getSymbolAtLocation(node);
15605
- if (symbol) {
15606
- let decl = symbol.valueDeclaration;
15607
- if (decl && typescript.isEnumMember(decl) && decl.initializer || decl && typescript.isPropertyAssignment(decl) && decl.initializer || decl && typescript.isVariableDeclaration(decl) && decl.initializer)
15608
- return resolveLiteralValue(typescript, checker, decl.initializer, depth + 1);
15609
- }
15610
- return node.getText();
15611
- }
15612
- return node.getText();
15613
- }
15614
- function collectBindingDefaults(typescript, pattern, defaults, checker) {
15615
- for (let element of pattern.elements)
15616
- if (element.initializer) {
15617
- let propName = element.propertyName ? element.propertyName.getText() : element.name.getText();
15618
- defaults.set(
15619
- propName,
15620
- checker ? resolveLiteralValue(typescript, checker, element.initializer) : element.initializer.getText()
15621
- );
15622
- }
15623
- }
15624
- function unwrapExpression(typescript, expression) {
15625
- let current2 = expression;
15626
- for (; isWrappedExpression(typescript, current2); )
15627
- current2 = current2.expression;
15628
- return current2;
15629
- }
15630
- function isPropsIdentifier(typescript, node, paramName, checker) {
15631
- if (!typescript.isIdentifier(node))
15632
- return !1;
15633
- if (!checker)
15634
- return node.text === paramName.text;
15635
- let symbol = checker.getSymbolAtLocation(node), paramSymbol = checker.getSymbolAtLocation(paramName);
15636
- return symbol !== void 0 && symbol === paramSymbol;
15637
- }
15638
- function isPropsDerivedInitializer(typescript, initializer, paramName, checker) {
15639
- let expr = unwrapExpression(typescript, initializer);
15640
- return isPropsIdentifier(typescript, expr, paramName, checker) ? !0 : typescript.isAwaitExpression(expr) ? isPropsDerivedInitializer(typescript, expr.expression, paramName, checker) : typescript.isBinaryExpression(expr) && [
15641
- typescript.SyntaxKind.BarBarToken,
15642
- typescript.SyntaxKind.QuestionQuestionToken,
15643
- typescript.SyntaxKind.AmpersandAmpersandToken
15644
- ].includes(expr.operatorToken.kind) ? isPropsDerivedInitializer(typescript, expr.left, paramName, checker) || isPropsDerivedInitializer(typescript, expr.right, paramName, checker) : typescript.isConditionalExpression(expr) ? isPropsDerivedInitializer(typescript, expr.whenTrue, paramName, checker) || isPropsDerivedInitializer(typescript, expr.whenFalse, paramName, checker) : typescript.isCallExpression(expr) || typescript.isNewExpression(expr) ? expr.arguments?.some(
15645
- (arg) => isPropsDerivedInitializer(typescript, arg, paramName, checker)
15646
- ) ?? !1 : !1;
15647
- }
15648
- function extractDestructuringDefaults(typescript, resolved, checker) {
15649
- let defaults = /* @__PURE__ */ new Map(), decl = resolved.valueDeclaration;
15650
- if (!decl)
15651
- return defaults;
15652
- let fn;
15653
- if (typescript.isFunctionDeclaration(decl)) {
15654
- if (fn = decl, !fn.body) {
15655
- let allDecls = resolved.getDeclarations?.() ?? [];
15656
- for (let d of allDecls)
15657
- if (typescript.isFunctionDeclaration(d) && d.body) {
15658
- fn = d;
15659
- break;
15519
+ });
15520
+ let metaComp = csf._meta?.component;
15521
+ metaComp && componentSet.add(metaComp);
15522
+ for (let componentName of additionalComponentNames)
15523
+ componentSet.add(componentName);
15524
+ let components = Array.from(componentSet).sort((a, b) => a.localeCompare(b)), body = program.get("body");
15525
+ for (let stmt of body) {
15526
+ if (!stmt.isImportDeclaration())
15527
+ continue;
15528
+ let decl = stmt.node;
15529
+ if (decl.importKind === "type")
15530
+ continue;
15531
+ let specifiers = decl.specifiers ?? [];
15532
+ if (specifiers.length !== 0)
15533
+ for (let s of specifiers) {
15534
+ if (!("local" in s) || !s.local || isTypeSpecifier(s))
15535
+ continue;
15536
+ let importId = decl.source.value;
15537
+ if (t2.isImportDefaultSpecifier(s))
15538
+ localToImport.set(s.local.name, { importId, importName: "default" });
15539
+ else if (t2.isImportNamespaceSpecifier(s))
15540
+ localToImport.set(s.local.name, { importId, importName: "*" });
15541
+ else if (t2.isImportSpecifier(s)) {
15542
+ let imported = importedName(s.imported);
15543
+ localToImport.set(s.local.name, { importId, importName: imported });
15660
15544
  }
15661
- }
15662
- } else typescript.isVariableDeclaration(decl) && decl.initializer ? fn = unwrapToFunction(typescript, decl.initializer, 0, checker) : typescript.isExportAssignment(decl) && decl.expression && (fn = unwrapToFunction(typescript, decl.expression, 0, checker));
15663
- if (!fn)
15664
- return defaults;
15665
- let firstParam = fn.parameters[0];
15666
- if (!firstParam)
15667
- return defaults;
15668
- if (typescript.isObjectBindingPattern(firstParam.name))
15669
- return collectBindingDefaults(typescript, firstParam.name, defaults, checker), defaults;
15670
- let propsParamName = typescript.isIdentifier(firstParam.name) ? firstParam.name : void 0;
15671
- if (fn.body && propsParamName) {
15672
- let body = typescript.isBlock(fn.body) ? fn.body : void 0;
15673
- if (body) {
15674
- for (let stmt of body.statements)
15675
- if (typescript.isVariableStatement(stmt))
15676
- for (let varDecl of stmt.declarationList.declarations)
15677
- typescript.isObjectBindingPattern(varDecl.name) && varDecl.initializer && isPropsDerivedInitializer(typescript, varDecl.initializer, propsParamName, checker) && collectBindingDefaults(typescript, varDecl.name, defaults, checker);
15678
- }
15545
+ }
15679
15546
  }
15680
- return defaults;
15681
- }
15682
- function collectObjectLiteralDefaults(typescript, checker, obj, defaults) {
15683
- for (let prop of obj.properties)
15684
- if (typescript.isPropertyAssignment(prop) && prop.name) {
15685
- let name = prop.name.getText();
15686
- defaults.set(name, resolveLiteralValue(typescript, checker, prop.initializer));
15687
- } else if (typescript.isShorthandPropertyAssignment(prop)) {
15688
- let name = prop.name.getText(), symbol = checker.getShorthandAssignmentValueSymbol(prop);
15689
- symbol?.valueDeclaration && typescript.isVariableDeclaration(symbol.valueDeclaration) && symbol.valueDeclaration.initializer ? defaults.set(
15690
- name,
15691
- resolveLiteralValue(typescript, checker, symbol.valueDeclaration.initializer)
15692
- ) : defaults.set(name, name);
15693
- }
15694
- }
15695
- function extractStaticDefaultProps(typescript, checker, resolved) {
15696
- let defaults = /* @__PURE__ */ new Map(), decl = resolved.valueDeclaration ?? resolved.getDeclarations()?.[0];
15697
- if (!decl)
15698
- return defaults;
15699
- let componentSourceFile = decl.getSourceFile();
15700
- for (let stmt of componentSourceFile.statements) {
15701
- if (typescript.isClassDeclaration(stmt) && stmt.name) {
15702
- if (checker.getSymbolAtLocation(stmt.name) !== resolved)
15547
+ let isLocallyDefinedWithoutImport = (base2) => {
15548
+ let binding = program.scope.getBinding(base2);
15549
+ return binding ? !!!(binding.path.isImportSpecifier?.() || binding.path.isImportDefaultSpecifier?.() || binding.path.isImportNamespaceSpecifier?.()) : !1;
15550
+ }, filteredComponents = components.filter(
15551
+ (c) => !isLocallyDefinedWithoutImport(baseIdentifier(c))
15552
+ );
15553
+ return (await Promise.all(
15554
+ filteredComponents.map(async (c) => {
15555
+ let depth = componentDepth.get(c), dot = c.indexOf("."), component = dot !== -1 ? (() => {
15556
+ let ns = c.slice(0, dot), mem = c.slice(dot + 1), direct = localToImport.get(ns);
15557
+ return direct ? direct.importName === "*" ? {
15558
+ componentName: c,
15559
+ localImportName: ns,
15560
+ importId: direct.importId,
15561
+ importName: mem,
15562
+ namespace: ns,
15563
+ member: mem,
15564
+ jsxDepth: depth
15565
+ } : {
15566
+ componentName: c,
15567
+ localImportName: ns,
15568
+ importId: direct.importId,
15569
+ importName: direct.importName,
15570
+ member: mem,
15571
+ jsxDepth: depth
15572
+ } : { componentName: c, member: mem, jsxDepth: depth };
15573
+ })() : (() => {
15574
+ let direct = localToImport.get(c);
15575
+ return direct ? {
15576
+ componentName: c,
15577
+ localImportName: c,
15578
+ importId: direct.importId,
15579
+ importName: direct.importName,
15580
+ jsxDepth: depth
15581
+ } : { componentName: c, jsxDepth: depth };
15582
+ })(), path5, isPackage = !1;
15583
+ try {
15584
+ component.importId && storyFilePath && (path5 = cachedResolveImport(matchPath(component.importId, dirname6(storyFilePath)), {
15585
+ basedir: dirname6(storyFilePath)
15586
+ }));
15587
+ } catch (e) {
15588
+ logger6.debug(e);
15589
+ }
15590
+ try {
15591
+ component.importId && !component.importId.startsWith(".") && storyFilePath && (cachedResolveImport(component.importId, { basedir: dirname6(storyFilePath) }), isPackage = !0);
15592
+ } catch {
15593
+ }
15594
+ let componentWithPackage = { ...component, isPackage };
15595
+ if (path5) {
15596
+ if (docgenEngine === "react-docgen-typescript") {
15597
+ let reactDocgenTypescript, reactDocgenTypescriptError;
15598
+ try {
15599
+ let docs = await parseWithReactDocgenTypescript(path5, reactDocgenTypescriptOptions);
15600
+ reactDocgenTypescript = matchComponentDoc(docs, component), reactDocgenTypescript || (reactDocgenTypescriptError = getReactDocgenTypescriptError(path5, component, docs));
15601
+ } catch (e) {
15602
+ let message = e instanceof Error ? e.message : String(e);
15603
+ logger6.debug(`react-docgen-typescript failed for ${path5}: ${message}`), reactDocgenTypescriptError = {
15604
+ name: "react-docgen-typescript parse error",
15605
+ message: `File: ${path5}
15606
+ ${message}`
15607
+ };
15608
+ }
15609
+ let importOverride = reactDocgenTypescript ? getImportTag(reactDocgenTypescript) : void 0;
15610
+ return {
15611
+ ...componentWithPackage,
15612
+ path: path5,
15613
+ ...reactDocgenTypescript ? { reactDocgenTypescript } : {},
15614
+ ...reactDocgenTypescriptError ? { reactDocgenTypescriptError } : {},
15615
+ importOverride
15616
+ };
15617
+ }
15618
+ if (docgenEngine === "react-docgen") {
15619
+ let reactDocgen = getReactDocgen(path5, componentWithPackage);
15620
+ return {
15621
+ ...componentWithPackage,
15622
+ path: path5,
15623
+ reactDocgen,
15624
+ importOverride: reactDocgen.type === "success" ? getImportTag(reactDocgen.data) : void 0
15625
+ };
15626
+ }
15627
+ if (docgenEngine === "react-component-meta")
15628
+ return {
15629
+ ...componentWithPackage,
15630
+ path: path5
15631
+ };
15632
+ }
15633
+ return componentWithPackage;
15634
+ })
15635
+ )).sort((a, b) => a.componentName.localeCompare(b.componentName));
15636
+ }, getImports = ({
15637
+ components,
15638
+ packageName
15639
+ }) => {
15640
+ let withSource = components.filter((c) => !!c.importId).map((c, idx) => {
15641
+ let importId = c.importId, overrideSource = (() => {
15642
+ if (c.importOverride)
15643
+ try {
15644
+ let src = babelParse2(c.importOverride).program.body.find((n) => t2.isImportDeclaration(n))?.source?.value;
15645
+ return typeof src == "string" ? src : void 0;
15646
+ } catch {
15647
+ return;
15648
+ }
15649
+ })(), rewritten = overrideSource !== void 0 ? overrideSource : (
15650
+ // only rewrite to the package name it the import id is not already a valid package
15651
+ // tsconfig paths such as ~/components/Button and components/Button are not seen as packages
15652
+ packageName && !c.isPackage ? packageName : importId
15653
+ );
15654
+ return { c, src: t2.stringLiteral(rewritten), key: rewritten, ord: idx };
15655
+ }), orderOfSource = {};
15656
+ for (let w of withSource)
15657
+ orderOfSource[w.key] === void 0 && (orderOfSource[w.key] = w.ord);
15658
+ let buckets = /* @__PURE__ */ new Map(), ensureBucket = (key, src) => {
15659
+ let prev = buckets.get(key);
15660
+ if (prev)
15661
+ return prev;
15662
+ let b = {
15663
+ source: src,
15664
+ defaults: [],
15665
+ namespaces: [],
15666
+ named: [],
15667
+ order: orderOfSource[key] ?? 0
15668
+ };
15669
+ return buckets.set(key, b), b;
15670
+ };
15671
+ for (let { c, src, key } of withSource) {
15672
+ let b = ensureBucket(key, src), rewritten = src.value !== c.importId, overrideSpec = (() => {
15673
+ if (c.importOverride)
15674
+ try {
15675
+ let decl = babelParse2(c.importOverride).program.body.find((n) => t2.isImportDeclaration(n));
15676
+ if (!decl)
15677
+ return;
15678
+ let spec = (decl.specifiers ?? []).find((s) => !isTypeSpecifier(s));
15679
+ return spec ? t2.isImportNamespaceSpecifier(spec) ? { kind: "namespace", local: spec.local.name } : t2.isImportDefaultSpecifier(spec) ? { kind: "default" } : t2.isImportSpecifier(spec) ? { kind: "named", imported: t2.isIdentifier(spec.imported) ? spec.imported.name : spec.imported.value } : void 0 : void 0;
15680
+ } catch {
15681
+ return;
15682
+ }
15683
+ })();
15684
+ if (overrideSpec) {
15685
+ if (overrideSpec.kind === "namespace") {
15686
+ let ns = t2.identifier(overrideSpec.local);
15687
+ addUniqueBy(b.namespaces, ns, (n) => n.name === ns.name);
15703
15688
  continue;
15704
- for (let member of stmt.members) {
15705
- if (!typescript.isPropertyDeclaration(member) || !member.name || member.name.getText() !== "defaultProps" || !member.initializer)
15689
+ }
15690
+ if (!c.localImportName)
15691
+ continue;
15692
+ if (overrideSpec.kind === "default") {
15693
+ let id = t2.identifier(c.localImportName);
15694
+ addUniqueBy(b.defaults, id, (d) => d.name === id.name);
15695
+ continue;
15696
+ }
15697
+ if (overrideSpec.kind === "named") {
15698
+ let local = t2.identifier(c.localImportName), imported = t2.identifier(overrideSpec.imported);
15699
+ addUniqueBy(
15700
+ b.named,
15701
+ t2.importSpecifier(local, imported),
15702
+ (n) => n.local.name === local.name && importedName(n.imported) === imported.name
15703
+ );
15704
+ continue;
15705
+ }
15706
+ }
15707
+ if (c.namespace) {
15708
+ if (rewritten) {
15709
+ if (!c.importName)
15706
15710
  continue;
15707
- let initializer = member.initializer;
15708
- if (typescript.isIdentifier(initializer)) {
15709
- let symDecl = checker.getSymbolAtLocation(initializer)?.valueDeclaration;
15710
- symDecl && typescript.isVariableDeclaration(symDecl) && symDecl.initializer && (initializer = symDecl.initializer);
15711
- }
15712
- typescript.isObjectLiteralExpression(initializer) && collectObjectLiteralDefaults(typescript, checker, initializer, defaults);
15711
+ let member = c.importName, id = t2.identifier(member);
15712
+ addUniqueBy(
15713
+ b.named,
15714
+ t2.importSpecifier(id, id),
15715
+ (n) => n.local.name === member && importedName(n.imported) === member
15716
+ );
15717
+ } else {
15718
+ let ns = t2.identifier(c.namespace);
15719
+ addUniqueBy(b.namespaces, ns, (n) => n.name === ns.name);
15713
15720
  }
15721
+ continue;
15714
15722
  }
15715
- if (typescript.isExpressionStatement(stmt) && typescript.isBinaryExpression(stmt.expression) && stmt.expression.operatorToken.kind === typescript.SyntaxKind.EqualsToken) {
15716
- let left = stmt.expression.left;
15717
- if (!typescript.isPropertyAccessExpression(left) || left.name.text !== "defaultProps")
15718
- continue;
15719
- let targetSymbol = checker.getSymbolAtLocation(left.expression);
15720
- if (!targetSymbol || (targetSymbol.flags & typescript.SymbolFlags.Alias ? checker.getAliasedSymbol(targetSymbol) : targetSymbol) !== resolved)
15723
+ if (c.importName === "default") {
15724
+ if (!c.localImportName)
15721
15725
  continue;
15722
- let right = stmt.expression.right;
15723
- if (typescript.isIdentifier(right)) {
15724
- let symDecl = checker.getSymbolAtLocation(right)?.valueDeclaration;
15725
- symDecl && typescript.isVariableDeclaration(symDecl) && symDecl.initializer && (right = symDecl.initializer);
15726
+ if (rewritten) {
15727
+ let id = t2.identifier(c.localImportName);
15728
+ addUniqueBy(
15729
+ b.named,
15730
+ t2.importSpecifier(id, id),
15731
+ (n) => n.local.name === id.name && importedName(n.imported) === id.name
15732
+ );
15733
+ } else {
15734
+ let id = t2.identifier(c.localImportName);
15735
+ addUniqueBy(b.defaults, id, (d) => d.name === id.name);
15726
15736
  }
15727
- typescript.isObjectLiteralExpression(right) && collectObjectLiteralDefaults(typescript, checker, right, defaults);
15737
+ continue;
15738
+ }
15739
+ if (c.importName) {
15740
+ if (!c.localImportName)
15741
+ continue;
15742
+ let local = t2.identifier(c.localImportName), imported = t2.identifier(c.importName);
15743
+ addUniqueBy(
15744
+ b.named,
15745
+ t2.importSpecifier(local, imported),
15746
+ (n) => n.local.name === local.name && importedName(n.imported) === imported.name
15747
+ );
15748
+ continue;
15728
15749
  }
15729
15750
  }
15730
- return defaults;
15731
- }
15732
- function getJSDocDefault(typescript, prop, checker) {
15733
- let tags = prop.getJsDocTags(checker);
15734
- for (let tag of tags)
15735
- if (tag.name === "default" || tag.name === "defaultValue")
15736
- return typescript.displayPartsToString(tag.text) || void 0;
15737
- }
15738
- function extractPropItem(typescript, checker, prop, contextNode, defaultsMap) {
15739
- let isRequired = !!!(prop.flags & typescript.SymbolFlags.Optional), propType = checker.getTypeOfSymbolAtLocation(prop, contextNode), type = serializeType(typescript, checker, propType, isRequired), description = typescript.displayPartsToString(prop.getDocumentationComment(checker)), parent = getParentType(typescript, prop), declarations = getAllDeclarationParents(typescript, prop), propName = prop.getName(), destructuringDefault = defaultsMap?.get(propName), jsDocDefault = getJSDocDefault(typescript, prop, checker), defaultStr = destructuringDefault ?? jsDocDefault;
15740
- return {
15741
- name: propName,
15742
- required: isRequired,
15743
- type,
15744
- description,
15745
- defaultValue: defaultStr !== void 0 ? { value: defaultStr } : null,
15746
- parent,
15747
- declarations
15748
- };
15749
- }
15750
- function getBulkSourceExclusions(properties) {
15751
- let propSourceCache = /* @__PURE__ */ new Map(), getSource = (prop) => {
15752
- let cached2 = propSourceCache.get(prop);
15753
- return cached2 === void 0 && !propSourceCache.has(prop) && (cached2 = getPropSourceFile(prop), propSourceCache.set(prop, cached2)), cached2;
15754
- }, sourceCount = /* @__PURE__ */ new Map();
15755
- for (let prop of properties) {
15756
- let source = getSource(prop);
15757
- source && (source.includes("node_modules") || source.endsWith(".d.ts")) && sourceCount.set(source, (sourceCount.get(source) ?? 0) + 1);
15751
+ let merged = [], printDecl = (specs, src) => {
15752
+ let node = t2.importDeclaration(specs, src), code = recast.print(node, {}).code;
15753
+ merged.push(code);
15754
+ }, sortedBuckets = Array.from(buckets.values()).sort((a, b) => a.order - b.order);
15755
+ for (let bucket of sortedBuckets) {
15756
+ let { source, defaults, namespaces, named } = bucket;
15757
+ if (!(defaults.length === 0 && namespaces.length === 0 && named.length === 0))
15758
+ if (namespaces.length > 0) {
15759
+ let firstSpecs = [];
15760
+ defaults[0] && firstSpecs.push(t2.importDefaultSpecifier(defaults[0])), firstSpecs.push(t2.importNamespaceSpecifier(namespaces[0])), printDecl(firstSpecs, source), named.length > 0 && printDecl(named, source);
15761
+ for (let d of defaults.slice(1))
15762
+ printDecl([t2.importDefaultSpecifier(d)], source);
15763
+ for (let ns of namespaces.slice(1))
15764
+ printDecl([t2.importNamespaceSpecifier(ns)], source);
15765
+ } else {
15766
+ if (defaults.length > 0 || named.length > 0) {
15767
+ let specs = [];
15768
+ defaults[0] && specs.push(t2.importDefaultSpecifier(defaults[0])), specs.push(...named), printDecl(specs, source);
15769
+ }
15770
+ for (let d of defaults.slice(1))
15771
+ printDecl([t2.importDefaultSpecifier(d)], source);
15772
+ }
15758
15773
  }
15759
- let bulkSources = new Set(
15760
- [...sourceCount.entries()].filter(([, count]) => count > LARGE_SOURCE_THRESHOLD).map(([source]) => source)
15761
- ), excluded = /* @__PURE__ */ new Set();
15762
- for (let prop of properties) {
15763
- let source = getSource(prop);
15764
- source && bulkSources.has(source) && excluded.add(prop.getName());
15774
+ return merged;
15775
+ };
15776
+
15777
+ // src/componentManifest/resolveComponents.ts
15778
+ import { recast as recast2 } from "storybook/internal/babel";
15779
+ import { storyNameFromExport } from "storybook/internal/csf";
15780
+ import { extractDescription, loadCsf } from "storybook/internal/csf-tools";
15781
+
15782
+ // src/componentManifest/generateCodeSnippet.ts
15783
+ import { types as t3 } from "storybook/internal/babel";
15784
+ function getCodeSnippet(csf, storyName, componentName) {
15785
+ let storyDeclaration = csf._storyDeclarationPath[storyName], metaObj = csf._metaNode;
15786
+ if (!storyDeclaration) {
15787
+ let message = "Expected story to be a function or variable declaration";
15788
+ throw csf._storyPaths[storyName]?.buildCodeFrameError(message) ?? message;
15765
15789
  }
15766
- return excluded;
15767
- }
15768
- function computeDisplayName({
15769
- exportSymbol,
15770
- resolvedSymbol
15771
- }) {
15772
- let resolvedName = resolvedSymbol.getName();
15773
- if (!exportSymbol)
15774
- return resolvedName && resolvedName !== "default" && resolvedName !== "__function" ? resolvedName : void 0;
15775
- let exportName = exportSymbol.getName();
15776
- return exportName === "default" ? resolvedName && resolvedName !== "default" && resolvedName !== "__function" ? resolvedName : void 0 : exportName;
15790
+ let storyPath;
15791
+ if (storyDeclaration.isFunctionDeclaration())
15792
+ storyPath = storyDeclaration;
15793
+ else if (storyDeclaration.isVariableDeclarator()) {
15794
+ let init = storyDeclaration.get("init");
15795
+ invariant(
15796
+ init.isExpression(),
15797
+ () => storyDeclaration.buildCodeFrameError("Expected story initializer to be an expression").message
15798
+ ), storyPath = init;
15799
+ } else
15800
+ throw storyDeclaration.buildCodeFrameError(
15801
+ "Expected story to be a function or variable declaration"
15802
+ );
15803
+ let normalizedPath = storyPath;
15804
+ if (storyPath.isCallExpression()) {
15805
+ let callee = storyPath.get("callee");
15806
+ if (callee.isMemberExpression()) {
15807
+ let obj = callee.get("object"), prop = callee.get("property"), isBind = prop.isIdentifier() && prop.node.name === "bind" || t3.isStringLiteral(prop.node) && prop.node.value === "bind";
15808
+ if (obj.isIdentifier() && isBind) {
15809
+ let resolved = resolveIdentifierInit(storyDeclaration, obj);
15810
+ resolved && (normalizedPath = resolved);
15811
+ }
15812
+ }
15813
+ if (storyPath === normalizedPath) {
15814
+ let args = storyPath.get("arguments");
15815
+ if (args.length !== 0) {
15816
+ invariant(
15817
+ args.length === 1,
15818
+ () => storyPath.buildCodeFrameError("Could not evaluate story expression").message
15819
+ );
15820
+ let storyArg = args[0];
15821
+ invariant(
15822
+ storyArg.isExpression(),
15823
+ () => storyPath.buildCodeFrameError("Could not evaluate story expression").message
15824
+ ), normalizedPath = storyArg;
15825
+ }
15826
+ }
15827
+ }
15828
+ normalizedPath = normalizedPath.isTSSatisfiesExpression() || normalizedPath.isTSAsExpression() ? normalizedPath.get("expression") : normalizedPath;
15829
+ let storyFn;
15830
+ if (normalizedPath.isArrowFunctionExpression() || normalizedPath.isFunctionExpression() || normalizedPath.isFunctionDeclaration())
15831
+ storyFn = normalizedPath;
15832
+ else if (!normalizedPath.isObjectExpression() && !(normalizedPath.isCallExpression() && Array.isArray(normalizedPath.node.arguments) && normalizedPath.node.arguments.length === 0))
15833
+ throw normalizedPath.buildCodeFrameError(
15834
+ "Expected story to be csf factory, function or an object expression"
15835
+ );
15836
+ let storyProps = normalizedPath.isObjectExpression() ? normalizedPath.get("properties").filter((p) => p.isObjectProperty()) : [], metaPath = pathForNode(csf._file.path, metaObj), metaProps = metaPath?.isObjectExpression() ? metaPath.get("properties").filter((p) => p.isObjectProperty()) : [], getRenderPath = (object) => {
15837
+ let renderPath = object.find((p) => keyOf(p.node) === "render")?.get("value");
15838
+ if (!renderPath)
15839
+ return { kind: "missing" };
15840
+ if (renderPath.isIdentifier()) {
15841
+ let resolved = resolveIdentifierInit(storyDeclaration, renderPath);
15842
+ return resolved && (resolved.isArrowFunctionExpression() || resolved.isFunctionExpression() || resolved.isFunctionDeclaration()) ? { kind: "resolved", path: resolved } : { kind: "unresolved" };
15843
+ }
15844
+ if (!(renderPath.isArrowFunctionExpression() || renderPath.isFunctionExpression()))
15845
+ throw renderPath.buildCodeFrameError(
15846
+ "Expected render to be an arrow function or function expression"
15847
+ );
15848
+ return { kind: "resolved", path: renderPath };
15849
+ }, metaRender = getRenderPath(metaProps), storyRender = getRenderPath(storyProps);
15850
+ storyFn || (storyFn = storyRender.kind === "resolved" ? storyRender.path : storyRender.kind === "missing" && metaRender.kind === "resolved" ? metaRender.path : void 0);
15851
+ let metaArgs = metaArgsRecord(metaObj ?? null), storyArgsPath = storyProps.filter((p) => keyOf(p.node) === "args").map((p) => p.get("value")).find((v) => v.isObjectExpression()), storyArgs = argsRecordFromObjectPath(storyArgsPath), storyAssignedArgsPath = storyArgsAssignmentPath(csf._file.path, storyName), storyAssignedArgs = argsRecordFromObjectPath(storyAssignedArgsPath), merged = { ...metaArgs, ...storyArgs, ...storyAssignedArgs }, entries = Object.entries(merged).filter(([k]) => k !== "children"), validEntries = entries.filter(([k, v]) => isValidJsxAttrName(k) && v != null), invalidEntries = entries.filter(([k, v]) => !isValidJsxAttrName(k) && v != null), injectedAttrs = validEntries.map(([k, v]) => toAttr(k, v)).filter((a) => a != null);
15852
+ if (storyFn) {
15853
+ let fn = storyFn.node;
15854
+ if (t3.isArrowFunctionExpression(fn) && (t3.isJSXElement(fn.body) || t3.isJSXFragment(fn.body))) {
15855
+ let spreadRes = transformArgsSpreadsInJsx(fn.body, merged), inlineRes = inlineArgsInJsx(spreadRes.node, merged);
15856
+ if (spreadRes.changed || inlineRes.changed) {
15857
+ let newFn = t3.arrowFunctionExpression([], inlineRes.node, fn.async);
15858
+ return t3.variableDeclaration("const", [
15859
+ t3.variableDeclarator(t3.identifier(storyName), newFn)
15860
+ ]);
15861
+ }
15862
+ }
15863
+ let stmts = t3.isFunctionDeclaration(fn) || t3.isArrowFunctionExpression(fn) && t3.isBlockStatement(fn.body) || t3.isFunctionExpression(fn) && t3.isBlockStatement(fn.body) ? fn.body.body : void 0;
15864
+ if (stmts) {
15865
+ let changed = !1, newBody = stmts.map((stmt) => {
15866
+ if (t3.isReturnStatement(stmt) && stmt.argument && (t3.isJSXElement(stmt.argument) || t3.isJSXFragment(stmt.argument))) {
15867
+ let spreadRes = transformArgsSpreadsInJsx(stmt.argument, merged), inlineRes = inlineArgsInJsx(spreadRes.node, merged);
15868
+ if (spreadRes.changed || inlineRes.changed)
15869
+ return changed = !0, t3.returnStatement(inlineRes.node);
15870
+ }
15871
+ return stmt;
15872
+ });
15873
+ if (changed)
15874
+ return t3.isFunctionDeclaration(fn) ? t3.functionDeclaration(
15875
+ t3.identifier(storyName),
15876
+ [],
15877
+ t3.blockStatement(newBody),
15878
+ fn.generator,
15879
+ fn.async
15880
+ ) : t3.variableDeclaration("const", [
15881
+ t3.variableDeclarator(
15882
+ t3.identifier(storyName),
15883
+ t3.arrowFunctionExpression([], t3.blockStatement(newBody), fn.async)
15884
+ )
15885
+ ]);
15886
+ }
15887
+ return t3.isFunctionDeclaration(fn) ? t3.functionDeclaration(t3.identifier(storyName), fn.params, fn.body, fn.generator, fn.async) : t3.variableDeclaration("const", [t3.variableDeclarator(t3.identifier(storyName), fn)]);
15888
+ }
15889
+ invariant(componentName, "Could not generate snippet without component name.");
15890
+ let invalidSpread = buildInvalidSpread(invalidEntries), name = t3.jsxIdentifier(componentName), openingElAttrs = invalidSpread ? [...injectedAttrs, invalidSpread] : injectedAttrs, children = toJsxChildren(merged.children), selfClosing = children.length === 0, arrow = t3.arrowFunctionExpression(
15891
+ [],
15892
+ t3.jsxElement(
15893
+ t3.jsxOpeningElement(name, openingElAttrs, selfClosing),
15894
+ selfClosing ? null : t3.jsxClosingElement(name),
15895
+ children,
15896
+ selfClosing
15897
+ )
15898
+ );
15899
+ return t3.variableDeclaration("const", [t3.variableDeclarator(t3.identifier(storyName), arrow)]);
15777
15900
  }
15778
- function extractComponentJsDocTags(typescript, checker, symbol) {
15779
- let tags = symbol.getJsDocTags(checker);
15780
- if (tags.length === 0)
15781
- return;
15782
- let groupedTags = groupBy(tags, (tag) => tag.name);
15783
- return Object.fromEntries(
15784
- Object.entries(groupedTags).map(([name, grouped]) => [
15785
- name,
15786
- (grouped ?? []).map((tag) => typescript.displayPartsToString(tag.text ?? []).trim())
15787
- ])
15901
+ function buildInvalidSpread(entries) {
15902
+ if (entries.length === 0)
15903
+ return null;
15904
+ let objectProps = entries.map(
15905
+ ([k, v]) => t3.objectProperty(t3.stringLiteral(k), t3.isExpression(v) ? v : t3.identifier("undefined"))
15788
15906
  );
15907
+ return t3.jsxSpreadAttribute(t3.objectExpression(objectProps));
15789
15908
  }
15790
- function serializeComponentDoc(typescript, checker, {
15791
- sourceFile,
15792
- resolvedComponent,
15793
- defaultsSourcePath
15794
- }) {
15795
- let { componentRef, propsType, symbol } = resolvedComponent, exportName = componentRef.importName;
15796
- if (!exportName)
15797
- return;
15798
- let displayNameOverride = componentRef.componentName, isMemberSelection = !!componentRef.member, filePath = componentRef.path ?? sourceFile.fileName, resolved = resolveAliasedSymbol(typescript, checker, symbol), contextNode = resolved.valueDeclaration ?? resolved.getDeclarations()?.[0];
15799
- if (!contextNode)
15800
- return;
15801
- let moduleSymbol = checker.getSymbolAtLocation(sourceFile), exportSymbol = moduleSymbol ? checker.getExportsOfModule(moduleSymbol).find((candidate) => candidate.getName() === exportName) : void 0, allProperties, unionForceOptional;
15802
- if (isUnionType(propsType)) {
15803
- let seen = /* @__PURE__ */ new Map(), forceOptional = /* @__PURE__ */ new Set(), unionMembers = propsType.types, allMemberPropSets = [];
15804
- for (let member of unionMembers) {
15805
- let memberPropNames = /* @__PURE__ */ new Set();
15806
- for (let prop of member.getApparentProperties()) {
15807
- let name = prop.getName();
15808
- memberPropNames.add(name);
15809
- let propType = checker.getTypeOfSymbolAtLocation(prop, contextNode), isOptional = !!(prop.flags & typescript.SymbolFlags.Optional), isDegraded = !!(propType.getFlags() & typescript.TypeFlags.Never) || !!(propType.getFlags() & typescript.TypeFlags.Undefined);
15810
- (isOptional || isDegraded) && forceOptional.add(name);
15811
- let existing = seen.get(name);
15812
- if (!existing)
15813
- seen.set(name, prop);
15814
- else if (!isDegraded) {
15815
- let existingType = checker.getTypeOfSymbolAtLocation(existing, contextNode);
15816
- (!!(existingType.getFlags() & typescript.TypeFlags.Never) || !!(existingType.getFlags() & typescript.TypeFlags.Undefined)) && seen.set(name, prop);
15817
- }
15909
+ var keyOf = (p) => t3.isIdentifier(p.key) ? p.key.name : t3.isStringLiteral(p.key) ? p.key.value : null, isValidJsxAttrName = (n) => /^[A-Za-z_][A-Za-z0-9_:-]*$/.test(n), argsRecordFromObjectPath = (objPath) => objPath ? Object.fromEntries(
15910
+ objPath.get("properties").filter((p) => p.isObjectProperty()).map((p) => [keyOf(p.node), p.get("value").node]).filter((e) => !!e[0])
15911
+ ) : {};
15912
+ function storyArgsAssignmentPath(program, storyName) {
15913
+ let found = null;
15914
+ return program.traverse({
15915
+ AssignmentExpression(p) {
15916
+ let left = p.get("left"), right = p.get("right");
15917
+ if (left.isMemberExpression()) {
15918
+ let obj = left.get("object"), prop = left.get("property"), isStoryIdent = obj.isIdentifier() && obj.node.name === storyName, isArgsProp = prop.isIdentifier() && prop.node.name === "args" && !left.node.computed || t3.isStringLiteral(prop.node) && left.node.computed && prop.node.value === "args";
15919
+ isStoryIdent && isArgsProp && right.isObjectExpression() && (found = right);
15818
15920
  }
15819
- allMemberPropSets.push(memberPropNames);
15820
15921
  }
15821
- for (let name of seen.keys())
15822
- allMemberPropSets.every((s) => s.has(name)) || forceOptional.add(name);
15823
- allProperties = Array.from(seen.values()), unionForceOptional = forceOptional;
15824
- } else
15825
- allProperties = propsType.getApparentProperties();
15826
- let excluded = getBulkSourceExclusions(allProperties), defaultsMap = extractDestructuringDefaults(typescript, resolved, checker);
15827
- if (defaultsMap.size === 0 && defaultsSourcePath) {
15828
- let fallbackDefaults = extractDefaultsFromSourceFile(typescript, defaultsSourcePath, {
15829
- exportName,
15830
- localName: resolved.getName(),
15831
- preferLocalName: isMemberSelection
15832
- });
15833
- for (let [key, value] of fallbackDefaults)
15834
- defaultsMap.set(key, value);
15922
+ }), found;
15923
+ }
15924
+ var argsRecordFromObjectNode = (obj) => obj ? Object.fromEntries(
15925
+ obj.properties.filter((p) => t3.isObjectProperty(p)).map((p) => [keyOf(p), p.value]).filter((e) => !!e[0])
15926
+ ) : {}, metaArgsRecord = (meta) => {
15927
+ if (!meta)
15928
+ return {};
15929
+ let argsProp = meta.properties.find(
15930
+ (p) => t3.isObjectProperty(p) && keyOf(p) === "args"
15931
+ );
15932
+ return argsProp && t3.isObjectExpression(argsProp.value) ? argsRecordFromObjectNode(argsProp.value) : {};
15933
+ }, toAttr = (key, value) => t3.isBooleanLiteral(value) ? value.value ? t3.jsxAttribute(t3.jsxIdentifier(key), null) : t3.jsxAttribute(t3.jsxIdentifier(key), t3.jsxExpressionContainer(value)) : t3.isStringLiteral(value) ? t3.jsxAttribute(t3.jsxIdentifier(key), t3.stringLiteral(value.value)) : t3.isExpression(value) ? t3.jsxAttribute(t3.jsxIdentifier(key), t3.jsxExpressionContainer(value)) : null, toJsxChildren = (node) => node ? t3.isStringLiteral(node) ? [t3.jsxText(node.value)] : t3.isJSXElement(node) || t3.isJSXFragment(node) ? [node] : t3.isExpression(node) ? [t3.jsxExpressionContainer(node)] : [] : [];
15934
+ function getArgsMemberKey(expr) {
15935
+ if (t3.isMemberExpression(expr) && t3.isIdentifier(expr.object) && expr.object.name === "args") {
15936
+ if (t3.isIdentifier(expr.property) && !expr.computed)
15937
+ return expr.property.name;
15938
+ if (t3.isStringLiteral(expr.property) && expr.computed)
15939
+ return expr.property.value;
15835
15940
  }
15836
- let staticDefaults = extractStaticDefaultProps(typescript, checker, resolved);
15837
- for (let [key, value] of staticDefaults)
15838
- defaultsMap.has(key) || defaultsMap.set(key, value);
15839
- let props = {};
15840
- for (let prop of allProperties) {
15841
- if (excluded.has(prop.getName()))
15842
- continue;
15843
- let item = extractPropItem(typescript, checker, prop, contextNode, defaultsMap);
15844
- unionForceOptional?.has(prop.getName()) && (item.required = !1), props[prop.getName()] = item;
15941
+ if (t3.isOptionalMemberExpression?.(expr) && t3.isIdentifier(expr.object) && expr.object.name === "args") {
15942
+ let prop = expr.property;
15943
+ if (t3.isIdentifier(prop) && !expr.computed)
15944
+ return prop.name;
15945
+ if (t3.isStringLiteral(prop) && expr.computed)
15946
+ return prop.value;
15845
15947
  }
15846
- let displayName = (isMemberSelection ? displayNameOverride : void 0) ?? computeDisplayName({
15847
- exportSymbol,
15848
- resolvedSymbol: resolved
15849
- }) ?? displayNameOverride, description = typescript.displayPartsToString(resolved.getDocumentationComment(checker)), selectedJsDocTags = extractComponentJsDocTags(typescript, checker, resolved), exportResolved = exportSymbol && exportSymbol !== resolved ? resolveAliasedSymbol(typescript, checker, exportSymbol) : void 0, exportJsDocTags = exportResolved ? extractComponentJsDocTags(typescript, checker, exportResolved) : void 0, jsDocTags = selectedJsDocTags?.import || !exportJsDocTags?.import ? selectedJsDocTags : {
15850
- ...selectedJsDocTags ?? {},
15851
- import: exportJsDocTags.import
15852
- };
15853
- return {
15854
- displayName,
15855
- exportName,
15856
- filePath,
15857
- description,
15858
- jsDocTags,
15859
- props
15860
- };
15948
+ return null;
15861
15949
  }
15862
- function extractDefaultsFromSourceFile(typescript, filePath, {
15863
- exportName,
15864
- localName,
15865
- preferLocalName = !1
15866
- }) {
15867
- let defaults = /* @__PURE__ */ new Map(), content = typescript.sys.readFile(filePath);
15868
- if (!content)
15869
- return defaults;
15870
- let sf = typescript.createSourceFile(
15871
- filePath,
15872
- content,
15873
- typescript.ScriptTarget.Latest,
15874
- /* setParentNodes */
15875
- !0
15876
- ), varMap = /* @__PURE__ */ new Map();
15877
- for (let stmt of sf.statements) {
15878
- if (typescript.isVariableStatement(stmt))
15879
- for (let decl of stmt.declarationList.declarations)
15880
- typescript.isIdentifier(decl.name) && decl.initializer && varMap.set(decl.name.text, decl.initializer);
15881
- typescript.isFunctionDeclaration(stmt) && stmt.name && varMap.set(stmt.name.text, stmt);
15950
+ function inlineArgsInJsx(node, merged) {
15951
+ let changed = !1;
15952
+ if (t3.isJSXElement(node)) {
15953
+ let opening = node.openingElement, newAttrs = opening.attributes.flatMap((a) => {
15954
+ if (!t3.isJSXAttribute(a))
15955
+ return [a];
15956
+ let name = t3.isJSXIdentifier(a.name) ? a.name.name : null;
15957
+ if (!(name && a.value && t3.isJSXExpressionContainer(a.value)))
15958
+ return [a];
15959
+ let key = getArgsMemberKey(a.value.expression);
15960
+ if (!(key && key in merged))
15961
+ return [a];
15962
+ let repl = toAttr(name, merged[key]);
15963
+ return changed = !0, repl ? [repl] : [];
15964
+ }), newChildren = node.children.flatMap((c) => {
15965
+ if (t3.isJSXElement(c) || t3.isJSXFragment(c)) {
15966
+ let res = inlineArgsInJsx(c, merged);
15967
+ return changed ||= res.changed, [res.node];
15968
+ }
15969
+ return t3.isJSXExpressionContainer(c) && getArgsMemberKey(c.expression) === "children" && merged.children ? (changed = !0, toJsxChildren(merged.children)) : [c];
15970
+ }), selfClosing = opening.selfClosing && newChildren.length === 0;
15971
+ return {
15972
+ node: t3.jsxElement(
15973
+ t3.jsxOpeningElement(opening.name, newAttrs, selfClosing),
15974
+ selfClosing ? null : node.closingElement ?? t3.jsxClosingElement(opening.name),
15975
+ newChildren,
15976
+ selfClosing
15977
+ ),
15978
+ changed
15979
+ };
15882
15980
  }
15883
- let fn = preferLocalName ? findLocalFunction(typescript, sf, localName, varMap) ?? findExportedFunction(typescript, sf, exportName, varMap) : findExportedFunction(typescript, sf, exportName, varMap) ?? findLocalFunction(typescript, sf, localName, varMap);
15884
- if (!fn)
15885
- return defaults;
15886
- let firstParam = fn.parameters[0];
15887
- if (!firstParam)
15888
- return defaults;
15889
- if (typescript.isObjectBindingPattern(firstParam.name))
15890
- collectBindingDefaults(typescript, firstParam.name, defaults);
15891
- else if (fn.body) {
15892
- let propsParamName = typescript.isIdentifier(firstParam.name) ? firstParam.name : void 0, body = typescript.isBlock(fn.body) ? fn.body : void 0;
15893
- if (body && propsParamName) {
15894
- for (let stmt of body.statements)
15895
- if (typescript.isVariableStatement(stmt))
15896
- for (let varDecl of stmt.declarationList.declarations)
15897
- typescript.isObjectBindingPattern(varDecl.name) && varDecl.initializer && isPropsDerivedInitializer(typescript, varDecl.initializer, propsParamName) && collectBindingDefaults(typescript, varDecl.name, defaults);
15981
+ let fragChildren = node.children.flatMap((c) => {
15982
+ if (t3.isJSXElement(c) || t3.isJSXFragment(c)) {
15983
+ let res = inlineArgsInJsx(c, merged);
15984
+ return changed ||= res.changed, [res.node];
15898
15985
  }
15899
- }
15900
- return defaults;
15986
+ return t3.isJSXExpressionContainer(c) && getArgsMemberKey(c.expression) === "children" && "children" in merged ? (changed = !0, toJsxChildren(merged.children)) : [c];
15987
+ });
15988
+ return { node: t3.jsxFragment(node.openingFragment, node.closingFragment, fragChildren), changed };
15901
15989
  }
15902
- function findLocalFunction(typescript, sf, localName, varMap) {
15903
- if (!localName)
15904
- return;
15905
- let targetExpr = varMap.get(localName);
15906
- if (targetExpr)
15907
- return unwrapToFunctionAST(typescript, targetExpr, varMap, 0);
15990
+ function transformArgsSpreadsInJsx(node, merged) {
15991
+ let changed = !1, makeInjectedPieces = (existing) => {
15992
+ let entries = Object.entries(merged).filter(([k, v]) => v != null && k !== "children"), validEntries = entries.filter(([k]) => isValidJsxAttrName(k)), invalidEntries = entries.filter(([k]) => !isValidJsxAttrName(k)), injectedAttrs = validEntries.map(([k, v]) => toAttr(k, v)).filter((a) => !!a).filter((a) => t3.isJSXIdentifier(a.name) && !existing.has(a.name.name)), invalidSpread = buildInvalidSpread(invalidEntries.filter(([k]) => !existing.has(k)));
15993
+ return invalidSpread ? [...injectedAttrs, invalidSpread] : injectedAttrs;
15994
+ };
15995
+ if (t3.isJSXElement(node)) {
15996
+ let opening = node.openingElement, attrs = opening.attributes, isArgsSpread = (a) => t3.isJSXSpreadAttribute(a) && t3.isIdentifier(a.argument) && a.argument.name === "args", sawArgsSpread = attrs.some(isArgsSpread), firstIdx = attrs.findIndex(isArgsSpread), nonArgsAttrs = attrs.filter((a) => !isArgsSpread(a)), insertionIndex = sawArgsSpread ? attrs.slice(0, firstIdx).filter((a) => !isArgsSpread(a)).length : 0, newAttrs = sawArgsSpread ? (() => {
15997
+ let existing = new Set(
15998
+ nonArgsAttrs.filter((a) => t3.isJSXAttribute(a)).flatMap((a) => t3.isJSXIdentifier(a.name) ? [a.name.name] : [])
15999
+ ), pieces = makeInjectedPieces(existing);
16000
+ return changed = !0, [
16001
+ ...nonArgsAttrs.slice(0, insertionIndex),
16002
+ ...pieces,
16003
+ ...nonArgsAttrs.slice(insertionIndex)
16004
+ ];
16005
+ })() : nonArgsAttrs, newChildren = node.children.flatMap((c) => {
16006
+ if (t3.isJSXElement(c) || t3.isJSXFragment(c)) {
16007
+ let res = transformArgsSpreadsInJsx(c, merged);
16008
+ return changed ||= res.changed, [res.node];
16009
+ }
16010
+ return [c];
16011
+ }), children = sawArgsSpread && newChildren.length === 0 && merged.children ? (changed = !0, toJsxChildren(merged.children)) : newChildren, selfClosing = children.length === 0;
16012
+ return {
16013
+ node: t3.jsxElement(
16014
+ t3.jsxOpeningElement(opening.name, newAttrs, selfClosing),
16015
+ selfClosing ? null : node.closingElement ?? t3.jsxClosingElement(opening.name),
16016
+ children,
16017
+ selfClosing
16018
+ ),
16019
+ changed
16020
+ };
16021
+ }
16022
+ let fragChildren = node.children.flatMap((c) => {
16023
+ if (t3.isJSXElement(c) || t3.isJSXFragment(c)) {
16024
+ let res = transformArgsSpreadsInJsx(c, merged);
16025
+ return changed ||= res.changed, [res.node];
16026
+ }
16027
+ return [c];
16028
+ });
16029
+ return { node: t3.jsxFragment(node.openingFragment, node.closingFragment, fragChildren), changed };
15908
16030
  }
15909
- function findExportedFunction(typescript, sf, exportName, varMap) {
15910
- let targetExpr;
15911
- for (let stmt of sf.statements) {
15912
- if (exportName === "default" && typescript.isExportAssignment(stmt) && !stmt.isExportEquals) {
15913
- targetExpr = stmt.expression;
15914
- break;
16031
+ function resolveIdentifierInit(storyPath, identifier) {
16032
+ let programPath = storyPath.findParent((p) => p.isProgram());
16033
+ if (!programPath)
16034
+ return null;
16035
+ for (let stmt of programPath.get("body")) {
16036
+ if (stmt.isFunctionDeclaration() && stmt.node.id?.name === identifier.node.name)
16037
+ return stmt;
16038
+ if (stmt.isExportNamedDeclaration()) {
16039
+ let decl = stmt.get("declaration");
16040
+ if (decl.isFunctionDeclaration() && decl.node.id?.name === identifier.node.name)
16041
+ return decl;
15915
16042
  }
15916
- if (typescript.isVariableStatement(stmt) && hasExportModifier(typescript, stmt)) {
15917
- for (let decl of stmt.declarationList.declarations)
15918
- if (typescript.isIdentifier(decl.name) && decl.name.text === exportName && decl.initializer) {
15919
- targetExpr = decl.initializer;
15920
- break;
15921
- }
15922
- if (targetExpr)
15923
- break;
16043
+ }
16044
+ let match = programPath.get("body").flatMap((stmt) => {
16045
+ if (stmt.isVariableDeclaration())
16046
+ return stmt.get("declarations");
16047
+ if (stmt.isExportNamedDeclaration()) {
16048
+ let decl = stmt.get("declaration");
16049
+ if (decl && decl.isVariableDeclaration())
16050
+ return decl.get("declarations");
15924
16051
  }
15925
- if (typescript.isFunctionDeclaration(stmt) && hasExportModifier(typescript, stmt) && stmt.name?.text === exportName)
15926
- return findFunctionImpl(typescript, sf, stmt.name.text) ?? stmt;
15927
- if (typescript.isExportDeclaration(stmt) && stmt.exportClause && typescript.isNamedExports(stmt.exportClause)) {
15928
- for (let spec of stmt.exportClause.elements) {
15929
- let exported = spec.name.text, local = spec.propertyName ? spec.propertyName.text : spec.name.text;
15930
- if (exported === exportName) {
15931
- targetExpr = varMap.get(local);
15932
- break;
15933
- }
15934
- }
15935
- if (targetExpr)
15936
- break;
16052
+ return [];
16053
+ }).find((d) => {
16054
+ let id = d.get("id");
16055
+ return id.isIdentifier() && id.node.name === identifier.node.name;
16056
+ });
16057
+ if (!match)
16058
+ return null;
16059
+ let init = match.get("init");
16060
+ return init && init.isExpression() ? init : null;
16061
+ }
16062
+ function pathForNode(program, target) {
16063
+ if (!target)
16064
+ return;
16065
+ let found;
16066
+ return program.traverse({
16067
+ enter(p) {
16068
+ p.node && p.node === target && (found = p, p.stop());
15937
16069
  }
16070
+ }), found;
16071
+ }
16072
+
16073
+ // src/componentManifest/subcomponents.ts
16074
+ import { types as t4 } from "storybook/internal/babel";
16075
+ function findExactComponentMatch(components, componentName) {
16076
+ if (componentName)
16077
+ return components.find((component) => component.componentName === componentName);
16078
+ }
16079
+ function extractDeclaredSubcomponents(csf) {
16080
+ let rawSubcomponents = unwrapSubcomponentNode(
16081
+ csf._metaAnnotations.subcomponents,
16082
+ csf._ast.program
16083
+ );
16084
+ return !rawSubcomponents || !t4.isObjectExpression(rawSubcomponents) ? [] : rawSubcomponents.properties.flatMap((property) => {
16085
+ if (!t4.isObjectProperty(property))
16086
+ return [];
16087
+ let name = getObjectKeyName(property.key), directComponentName = getComponentExpressionName(property.value), componentExpression = unwrapSubcomponentNode(property.value, csf._ast.program), componentName = getComponentExpressionName(componentExpression) ?? directComponentName;
16088
+ return name && componentName ? [{ name, componentName }] : [];
16089
+ });
16090
+ }
16091
+ function findVariableInitialization(identifier, program) {
16092
+ for (let node of program.body) {
16093
+ let declaration = (t4.isVariableDeclaration(node) ? node.declarations : t4.isExportNamedDeclaration(node) && t4.isVariableDeclaration(node.declaration) ? node.declaration.declarations : void 0)?.find(
16094
+ (decl) => t4.isVariableDeclarator(decl) && t4.isIdentifier(decl.id) && decl.id.name === identifier
16095
+ );
16096
+ if (declaration?.init && t4.isExpression(declaration.init))
16097
+ return declaration.init;
15938
16098
  }
15939
- if (targetExpr || (targetExpr = varMap.get(exportName)), !!targetExpr)
15940
- return unwrapToFunctionAST(typescript, targetExpr, varMap, 0);
15941
16099
  }
15942
- function unwrapToFunctionAST(typescript, node, varMap, depth) {
15943
- if (!(depth > MAX_UNWRAP_DEPTH)) {
15944
- if (typescript.isFunctionExpression(node) || typescript.isArrowFunction(node) || typescript.isFunctionDeclaration(node))
15945
- return node;
15946
- if (typescript.isParenthesizedExpression(node) || typescript.isAsExpression(node) || typescript.isTypeAssertionExpression && typescript.isTypeAssertionExpression(node))
15947
- return unwrapToFunctionAST(typescript, node.expression, varMap, depth + 1);
15948
- if (typescript.isCallExpression(node)) {
15949
- let callee = node.expression;
15950
- if (typescript.isPropertyAccessExpression(callee) && typescript.isIdentifier(callee.expression) && callee.expression.text === "Object" && callee.name.text === "assign" && node.arguments.length >= 1 || node.arguments.length >= 1)
15951
- return unwrapToFunctionAST(typescript, node.arguments[0], varMap, depth + 1);
16100
+ function unwrapSubcomponentNode(node, program, visitedIdentifiers = /* @__PURE__ */ new Set()) {
16101
+ let current2 = node;
16102
+ for (; current2; ) {
16103
+ if (t4.isIdentifier(current2)) {
16104
+ if (visitedIdentifiers.has(current2.name))
16105
+ return;
16106
+ visitedIdentifiers.add(current2.name), current2 = findVariableInitialization(current2.name, program);
16107
+ continue;
15952
16108
  }
15953
- if (typescript.isIdentifier(node)) {
15954
- let init = varMap.get(node.text);
15955
- if (init)
15956
- return unwrapToFunctionAST(typescript, init, varMap, depth + 1);
16109
+ if (t4.isParenthesizedExpression(current2) || t4.isTSAsExpression(current2) || t4.isTSSatisfiesExpression(current2) || t4.isTSNonNullExpression(current2)) {
16110
+ current2 = current2.expression;
16111
+ continue;
15957
16112
  }
16113
+ return current2;
15958
16114
  }
15959
16115
  }
15960
- function findFunctionImpl(typescript, sf, name) {
15961
- for (let stmt of sf.statements)
15962
- if (typescript.isFunctionDeclaration(stmt) && stmt.name?.text === name && stmt.body)
15963
- return stmt;
16116
+ function getObjectKeyName(key) {
16117
+ if (t4.isIdentifier(key))
16118
+ return key.name;
16119
+ if (t4.isStringLiteral(key))
16120
+ return key.value;
15964
16121
  }
15965
- function hasExportModifier(typescript, node) {
15966
- return typescript.canHaveModifiers(node) && typescript.getModifiers(node)?.some((m) => m.kind === typescript.SyntaxKind.ExportKeyword) === !0;
16122
+ function getComponentExpressionName(node) {
16123
+ if (node) {
16124
+ if (t4.isIdentifier(node))
16125
+ return node.name;
16126
+ if (t4.isMemberExpression(node) && !node.computed) {
16127
+ let objectName = getComponentExpressionName(node.object), propertyName = getComponentExpressionName(node.property);
16128
+ return objectName && propertyName ? `${objectName}.${propertyName}` : void 0;
16129
+ }
16130
+ }
15967
16131
  }
15968
16132
 
15969
- // src/componentManifest/componentMeta/ComponentMetaProject.ts
15970
- var ComponentMetaProject = class {
15971
- constructor(typescript, commandLine, configFileName, fsFileSnapshots = /* @__PURE__ */ new Map(), getCommandLineFn) {
15972
- this.typescript = typescript;
15973
- this.commandLine = commandLine;
15974
- this.configFileName = configFileName;
15975
- this.fsFileSnapshots = fsFileSnapshots;
15976
- this.getCommandLineFn = getCommandLineFn;
15977
- this.projectVersion = 0;
15978
- this.shouldCheckRootFiles = !1;
15979
- /** Entries to extract — set by the generator, replayed during warmup for targeted type resolution. */
15980
- this.entries = [];
15981
- let language = (0, import_language_core.createLanguage)(
15982
- [{ getLanguageId: (fileName) => (0, import_typescript.resolveFileLanguageId)(fileName) }],
15983
- new import_language_core.FileMap(typescript.sys.useCaseSensitiveFileNames),
15984
- (fileName, includeFsFiles) => {
15985
- if (!includeFsFiles)
15986
- return;
15987
- let cache = fsFileSnapshots.get(fileName), modifiedTime = typescript.sys.getModifiedTime?.(fileName)?.valueOf();
15988
- if (!cache || cache[0] !== modifiedTime)
15989
- if (typescript.sys.fileExists(fileName)) {
15990
- let text = typescript.sys.readFile(fileName), snapshot2 = text !== void 0 ? typescript.ScriptSnapshot.fromString(text) : void 0;
15991
- fsFileSnapshots.set(fileName, [modifiedTime, snapshot2]);
15992
- } else
15993
- fsFileSnapshots.set(fileName, [modifiedTime, void 0]);
15994
- let snapshot = fsFileSnapshots.get(fileName)?.[1];
15995
- snapshot ? language.scripts.set(fileName, snapshot) : language.scripts.delete(fileName);
15996
- }
15997
- ), projectHost = {
15998
- getCurrentDirectory: () => configFileName ? path2.dirname(configFileName) : commandLine.options.rootDir ?? process.cwd(),
15999
- getCompilationSettings: () => this.commandLine.options,
16000
- getProjectReferences: () => this.commandLine.projectReferences,
16001
- getProjectVersion: () => (this.checkRootFilesUpdate(), this.projectVersion.toString()),
16002
- getScriptFileNames: () => (this.checkRootFilesUpdate(), this.commandLine.fileNames)
16003
- }, { languageServiceHost } = (0, import_typescript.createLanguageServiceHost)(
16004
- typescript,
16005
- typescript.sys,
16006
- language,
16007
- (s) => s,
16008
- // asScriptId — identity for React (no URI mapping needed)
16009
- projectHost
16010
- );
16011
- this.ls = typescript.createLanguageService(languageServiceHost);
16012
- }
16013
- getCommandLine() {
16014
- return this.commandLine;
16015
- }
16016
- dispose() {
16017
- clearTimeout(this.warmupTimer), this.ls.dispose();
16018
- }
16019
- // ---------------------------------------------------------------------------
16020
- // Project management
16021
- // ---------------------------------------------------------------------------
16022
- /**
16023
- * Batch-add multiple files to the project in one go. Only bumps projectVersion once, avoiding
16024
- * repeated program rebuilds.
16025
- */
16026
- ensureFiles(fileNames) {
16027
- let added = !1;
16028
- for (let fileName of fileNames)
16029
- this.commandLine.fileNames.includes(fileName) || (this.commandLine.fileNames.push(fileName), added = !0);
16030
- added && this.projectVersion++;
16031
- }
16032
- /**
16033
- * Adapted from:
16034
- * https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/kit/lib/createChecker.ts#L436-L447
16035
- */
16036
- checkRootFilesUpdate() {
16037
- if (!this.shouldCheckRootFiles || (this.shouldCheckRootFiles = !1, !this.getCommandLineFn))
16038
- return;
16039
- let newCommandLine = this.getCommandLineFn();
16040
- arrayItemsEqual(newCommandLine.fileNames, this.commandLine.fileNames) || (this.commandLine.fileNames = newCommandLine.fileNames, this.projectVersion++);
16041
- }
16042
- hasSourceFile(fileName) {
16043
- return !!this.ls.getProgram()?.getSourceFile(fileName);
16044
- }
16045
- /**
16046
- * Get all non-node_modules source file paths from the TS program. Used by ComponentMetaManager to
16047
- * watch directories for file changes.
16048
- */
16049
- getSourceFilePaths() {
16050
- let program = this.ls.getProgram();
16051
- return program ? program.getSourceFiles().map((sf) => sf.fileName.replace(/\\/g, "/")).filter((f) => !f.includes("node_modules")) : [];
16052
- }
16053
- /**
16054
- * Adapted from:
16055
- * https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/kit/lib/createChecker.ts#L409-L432
16056
- *
16057
- * Created events only set shouldCheckRootFiles (version bump happens in checkRootFilesUpdate if
16058
- * the file list actually changed). Deleted/created break early since they trigger a full config
16059
- * reparse — processing remaining changes is unnecessary.
16060
- */
16061
- onFilesChanged(changes) {
16062
- for (let { filePath } of changes)
16063
- this.fsFileSnapshots.delete(filePath);
16064
- let oldVersion = this.projectVersion, program = this.ls.getProgram();
16065
- for (let { filePath, type } of changes)
16066
- if (type === "changed")
16067
- program?.getSourceFile(filePath) && this.projectVersion++;
16068
- else if (type === "deleted") {
16069
- program?.getSourceFile(filePath) && this.projectVersion++, this.shouldCheckRootFiles = !0;
16070
- break;
16071
- } else if (type === "created") {
16072
- this.shouldCheckRootFiles = !0;
16073
- break;
16074
- }
16075
- this.projectVersion !== oldVersion && this.entries.length > 0 && (clearTimeout(this.warmupTimer), this.warmupTimer = setTimeout(() => {
16076
- try {
16077
- this.extractPropsFromStories(this.entries);
16078
- } catch {
16079
- }
16080
- }, 100), this.warmupTimer?.unref?.());
16081
- }
16082
- // ---------------------------------------------------------------------------
16083
- // Primary extraction method — probe-free
16084
- // ---------------------------------------------------------------------------
16085
- extractPropsFromStories(entries) {
16086
- this.entries = entries;
16087
- let allFiles = entries.flatMap(
16088
- (entry) => entry.component?.path ? [entry.storyPath, entry.component.path] : [entry.storyPath]
16089
- );
16090
- this.ensureFiles(allFiles), this.ensureFresh(allFiles);
16091
- let program = this.ls.getProgram();
16092
- if (!program)
16093
- return;
16094
- let checker = program.getTypeChecker(), serializationContextByComponentPath = /* @__PURE__ */ new Map();
16095
- for (let entry of entries)
16096
- try {
16097
- let storySourceFile = program.getSourceFile(entry.storyPath), entryComponent = entry.component, componentPath = entryComponent?.path, exportName = entryComponent?.importName;
16098
- if (!storySourceFile || !componentPath || !exportName || !entryComponent)
16099
- continue;
16100
- let importId = entryComponent.importId, isPackageImport = importId && !importId.startsWith("."), componentSourceFile;
16101
- if (isPackageImport) {
16102
- let resolved = this.typescript.resolveModuleName(
16103
- importId,
16104
- entry.storyPath,
16105
- this.commandLine.options,
16106
- this.typescript.sys
16107
- );
16108
- componentSourceFile = resolved.resolvedModule ? program.getSourceFile(resolved.resolvedModule.resolvedFileName) : program.getSourceFile(componentPath);
16109
- } else
16110
- componentSourceFile = program.getSourceFile(componentPath);
16111
- if (!componentSourceFile)
16112
- continue;
16113
- let resolvedComponent;
16114
- if (importId && (resolvedComponent = resolvePropsFromStoryFile(
16115
- this.typescript,
16116
- checker,
16117
- storySourceFile,
16118
- entryComponent
16119
- )), resolvedComponent || (resolvedComponent = this.resolveFromMetaComponent(
16120
- checker,
16121
- storySourceFile,
16122
- entryComponent
16123
- )), !resolvedComponent)
16124
- continue;
16125
- let serializationContext = serializationContextByComponentPath.get(componentPath);
16126
- if (serializationContext === void 0) {
16127
- let resolvedFileName = componentSourceFile.fileName;
16128
- serializationContext = {
16129
- sourceFile: componentSourceFile,
16130
- defaultsSourcePath: resolvedFileName.endsWith(".d.ts") || resolvedFileName.endsWith(".d.mts") || resolvedFileName.endsWith(".d.cts") ? componentPath : void 0
16131
- }, serializationContextByComponentPath.set(componentPath, serializationContext);
16132
- }
16133
- let doc = serializeComponentDoc(this.typescript, checker, {
16134
- sourceFile: serializationContext.sourceFile,
16135
- resolvedComponent,
16136
- defaultsSourcePath: serializationContext.defaultsSourcePath
16137
- });
16138
- doc && (entryComponent.reactComponentMeta = doc, entryComponent.componentJsDocTags = doc.jsDocTags, entryComponent.importOverride = entryComponent.componentJsDocTags?.import?.[0]?.trim());
16139
- } catch {
16140
- continue;
16141
- }
16142
- }
16143
- /**
16144
- * Check mtime for specific files and bump projectVersion if any changed.
16145
- *
16146
- * This bypasses the sync() gate in createLanguageServiceHost — sync() only runs when
16147
- * projectVersion changes, so mtime-based cache alone can't detect stale files. We do a targeted
16148
- * mtime check for the files we're about to extract from, ensuring freshness even when the
16149
- * fs.watch event hasn't arrived yet (race with HMR) or was missed entirely.
16150
- */
16151
- ensureFresh(fileNames) {
16152
- let stale = !1;
16153
- for (let fileName of fileNames) {
16154
- let cache = this.fsFileSnapshots.get(fileName);
16155
- if (!cache)
16156
- continue;
16157
- let currentMtime = this.typescript.sys.getModifiedTime?.(fileName)?.valueOf();
16158
- cache[0] !== currentMtime && (this.fsFileSnapshots.delete(fileName), stale = !0);
16159
- }
16160
- stale && this.projectVersion++;
16133
+ // src/componentManifest/resolveComponents.ts
16134
+ function findMatchingComponent(components, componentName, title) {
16135
+ let exactMatch = findExactComponentMatch(components, componentName);
16136
+ if (exactMatch)
16137
+ return exactMatch;
16138
+ let trimmedTitle = title.replace(/\s+/g, ""), matches = components.filter(
16139
+ (it) => trimmedTitle.includes(it.componentName) || it.localImportName && trimmedTitle.includes(it.localImportName) || it.importName && trimmedTitle.includes(it.importName)
16140
+ );
16141
+ if (matches.length <= 1)
16142
+ return matches[0];
16143
+ let best = matches[0];
16144
+ for (let cur of matches) {
16145
+ if (cur.jsxDepth === 0)
16146
+ return cur;
16147
+ (cur.jsxDepth ?? 1 / 0) < (best.jsxDepth ?? 1 / 0) && (best = cur);
16161
16148
  }
16162
- // ---------------------------------------------------------------------------
16163
- // Internal helpers
16164
- // ---------------------------------------------------------------------------
16165
- /**
16166
- * Path 2 fallback: resolve the component type from the story file's `meta.component` property.
16167
- * Only works when the user explicitly set `component:` in the meta — no node means no
16168
- * extraction.
16169
- */
16170
- resolveFromMetaComponent(checker, storySourceFile, componentRef) {
16171
- let { member: memberAccess } = componentRef, moduleSymbol = checker.getSymbolAtLocation(storySourceFile);
16172
- if (!moduleSymbol)
16173
- return;
16174
- let defaultExport = checker.getExportsOfModule(moduleSymbol).find((e) => e.getName() === "default");
16175
- if (!defaultExport)
16176
- return;
16177
- let componentProp = checker.getTypeOfSymbol(defaultExport).getProperty("component");
16178
- if (!componentProp)
16179
- return;
16180
- let componentType = checker.getTypeOfSymbol(componentProp), selectedSymbol = componentProp.valueDeclaration && this.typescript.isPropertyAssignment(componentProp.valueDeclaration) ? checker.getSymbolAtLocation(componentProp.valueDeclaration.initializer) : componentType.getSymbol?.();
16181
- if (memberAccess) {
16182
- let prop = componentType.getProperty(memberAccess);
16183
- if (prop)
16184
- componentType = checker.getTypeOfSymbol(prop), selectedSymbol = prop;
16185
- else
16186
- return;
16187
- }
16188
- let propsType = resolvePropsFromComponentType(this.typescript, checker, componentType);
16189
- if (!(!propsType || !selectedSymbol))
16149
+ return best;
16150
+ }
16151
+ async function resolveStoryFileComponents(options) {
16152
+ let { storyPath, title, typescriptOptions, docgenEngine } = options, storyFile = cachedReadTextFileSync(storyPath), csf = loadCsf(storyFile, { makeTitle: () => title }).parse(), componentName = csf._meta?.component, declaredSubcomponents = extractDeclaredSubcomponents(csf), allComponents = await getComponents({
16153
+ additionalComponentNames: declaredSubcomponents.map(
16154
+ (subcomponent) => subcomponent.componentName
16155
+ ),
16156
+ csf,
16157
+ storyFilePath: storyPath,
16158
+ typescriptOptions,
16159
+ docgenEngine
16160
+ }), component = findMatchingComponent(allComponents, componentName, title), subcomponents = declaredSubcomponents.map((declared) => ({
16161
+ name: declared.name,
16162
+ component: findExactComponentMatch(allComponents, declared.componentName)
16163
+ }));
16164
+ return { storyPath, storyFile, csf, componentName, allComponents, component, subcomponents };
16165
+ }
16166
+ function extractStorySnippets(csf, componentName, filterStoryIds) {
16167
+ return Object.entries(csf._stories).filter(([, story]) => !filterStoryIds || filterStoryIds.has(story.id)).map(([storyExport, story]) => {
16168
+ let name = story.name ?? storyNameFromExport(storyExport);
16169
+ try {
16170
+ let jsdocComment = extractDescription(csf._storyStatements[storyExport]), { tags = {}, description } = jsdocComment ? extractJSDocInfo(jsdocComment) : {}, finalDescription = (tags?.describe?.[0] || tags?.desc?.[0]) ?? description;
16190
16171
  return {
16191
- componentRef,
16192
- propsType,
16193
- symbol: selectedSymbol
16172
+ id: story.id,
16173
+ name,
16174
+ snippet: recast2.print(getCodeSnippet(csf, storyExport, componentName)).code,
16175
+ description: finalDescription?.trim(),
16176
+ summary: tags.summary?.[0]
16194
16177
  };
16195
- }
16196
- };
16197
- function arrayItemsEqual(a, b) {
16198
- if (a.length !== b.length)
16199
- return !1;
16200
- let set = new Set(a);
16201
- for (let file of b)
16202
- if (!set.has(file))
16203
- return !1;
16204
- return !0;
16178
+ } catch (e) {
16179
+ let err = e instanceof Error ? e : new Error(String(e));
16180
+ return { id: story.id, name, error: { name: err.name, message: err.message } };
16181
+ }
16182
+ });
16205
16183
  }
16206
16184
 
16207
- // src/componentManifest/componentMeta/ComponentMetaManager.ts
16208
- var rootTsConfigNames = ["tsconfig.json", "jsconfig.json"], DEFAULT_INFERRED_OPTIONS = {
16209
- strict: !0,
16210
- esModuleInterop: !0,
16211
- allowJs: !0,
16212
- skipLibCheck: !0
16213
- }, ComponentMetaManager = class {
16214
- constructor(typescript) {
16215
- this.typescript = typescript;
16216
- // Adapted from:
16217
- // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L34-L37
16218
- this.configProjects = /* @__PURE__ */ new Map();
16219
- this.rootTsConfigs = /* @__PURE__ */ new Set();
16220
- this.searchedDirs = /* @__PURE__ */ new Set();
16221
- // Our own file watching layer
16222
- this.watching = !1;
16223
- this.watchersByDir = /* @__PURE__ */ new Map();
16224
- this.pendingEvents = /* @__PURE__ */ new Map();
16225
- // Adapted from:
16226
- // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/kit/lib/createChecker.ts#L83
16227
- this.fsFileSnapshots = /* @__PURE__ */ new Map();
16185
+ // src/componentManifest/buildReactComponentDocgen.ts
16186
+ function getPackageInfo(componentPath, fallbackPath) {
16187
+ let nearestPkg = cachedFindUp("package.json", {
16188
+ cwd: path.dirname(componentPath ?? fallbackPath)
16189
+ });
16190
+ try {
16191
+ if (!nearestPkg)
16192
+ return;
16193
+ let parsed = JSON.parse(cachedReadTextFileSync(nearestPkg));
16194
+ return typeof parsed == "object" && parsed && "name" in parsed && typeof parsed.name == "string" ? parsed.name : void 0;
16195
+ } catch {
16196
+ return;
16228
16197
  }
16229
- // ---------------------------------------------------------------------------
16230
- // Adapted from:
16231
- // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L70-L79
16232
- // ---------------------------------------------------------------------------
16233
- getProjectForFile(fileName) {
16234
- let tsconfig = this.findMatchTSConfig(fileName);
16235
- return tsconfig ? this.getOrCreateConfiguredProject(tsconfig) ?? this.getOrCreateInferredProject(fileName) : this.getOrCreateInferredProject(fileName);
16236
- }
16237
- /**
16238
- * Batch-extract component props across all entries, grouping by tsconfig project so each project
16239
- * builds its TS program only once.
16240
- */
16241
- batchExtract(entries) {
16242
- let extractableEntries = entries.filter(
16243
- (storyRef) => storyRef.component?.path && storyRef.component.importName
16244
- ), byProject = groupByToMap(
16245
- extractableEntries,
16246
- (storyRef) => this.getProjectForFile(storyRef.storyPath)
16247
- );
16248
- for (let [project, projectEntries] of byProject)
16249
- try {
16250
- project.extractPropsFromStories(projectEntries);
16251
- } catch (err) {
16252
- logger5.debug(`[reactComponentMeta] Batch extraction failed: ${err}`);
16198
+ }
16199
+ function getFallbackImport(packageName, componentName) {
16200
+ let exportName = componentName?.split(".").at(-1);
16201
+ return packageName && exportName ? `import { ${exportName} } from "${packageName}";` : "";
16202
+ }
16203
+ function relativizeComponentMetaPaths(doc) {
16204
+ let relativize = (fileName) => path.relative(process.cwd(), fileName), relativizeProp = (prop) => ({
16205
+ ...prop,
16206
+ parent: prop.parent ? { ...prop.parent, fileName: relativize(prop.parent.fileName) } : prop.parent,
16207
+ declarations: prop.declarations?.map((declaration) => ({
16208
+ ...declaration,
16209
+ fileName: relativize(declaration.fileName)
16210
+ }))
16211
+ });
16212
+ return {
16213
+ ...doc,
16214
+ props: Object.fromEntries(
16215
+ Object.entries(doc.props).map(([name, prop]) => [name, relativizeProp(prop)])
16216
+ )
16217
+ };
16218
+ }
16219
+ function getComponentDocgenData(component, docgenEngine) {
16220
+ let reactDocgen, reactDocgenTypescript, reactComponentMeta, docgenDescription, docgenJsDocTags, docgenError;
16221
+ if (docgenEngine === "react-docgen") {
16222
+ let result = component?.reactDocgen;
16223
+ reactDocgen = result?.type === "success" ? result.data : void 0, docgenDescription = reactDocgen?.description, docgenError = result?.type === "error" ? result.error : void 0;
16224
+ } else docgenEngine === "react-docgen-typescript" ? (reactDocgenTypescript = component?.reactDocgenTypescript, docgenDescription = reactDocgenTypescript?.description, docgenError = component?.reactDocgenTypescriptError) : (reactComponentMeta = component?.reactComponentMeta ? relativizeComponentMetaPaths(component.reactComponentMeta) : void 0, docgenDescription = reactComponentMeta?.description, docgenJsDocTags = component?.componentJsDocTags);
16225
+ return {
16226
+ docgenDescription,
16227
+ docgenError,
16228
+ docgenJsDocTags,
16229
+ reactComponentMeta,
16230
+ reactDocgen,
16231
+ reactDocgenTypescript
16232
+ };
16233
+ }
16234
+ function createSubcomponentDocgen({
16235
+ component,
16236
+ declaredName,
16237
+ docgenEngine,
16238
+ packageName,
16239
+ storyFilePath
16240
+ }) {
16241
+ let imports = getImports({ components: component ? [component] : [], packageName }).join(`
16242
+ `).trim() || getFallbackImport(packageName, component?.componentName), {
16243
+ reactDocgen,
16244
+ reactDocgenTypescript,
16245
+ reactComponentMeta,
16246
+ docgenDescription,
16247
+ docgenJsDocTags,
16248
+ docgenError
16249
+ } = getComponentDocgenData(component, docgenEngine), { description, summary, jsDocTags } = extractComponentDescription(
16250
+ void 0,
16251
+ docgenDescription,
16252
+ docgenJsDocTags
16253
+ );
16254
+ return {
16255
+ name: declaredName,
16256
+ path: component?.path ?? storyFilePath,
16257
+ description,
16258
+ summary,
16259
+ import: imports || void 0,
16260
+ jsDocTags,
16261
+ reactDocgen,
16262
+ reactDocgenTypescript,
16263
+ reactComponentMeta,
16264
+ error: docgenError ?? (component ? void 0 : {
16265
+ name: "No component import found",
16266
+ message: `No component file found for the "${declaredName}" subcomponent.`
16267
+ })
16268
+ };
16269
+ }
16270
+ function buildReactComponentDocgenFromResolved({
16271
+ entry,
16272
+ storyPath,
16273
+ storyFilePath,
16274
+ storyFile,
16275
+ csf,
16276
+ componentName,
16277
+ component,
16278
+ allComponents,
16279
+ subcomponents,
16280
+ docgenEngine,
16281
+ filterStoryIds
16282
+ }) {
16283
+ let id = getComponentIdFromEntry(entry), title = entry.title.split("/").at(-1).replace(/\s+/g, ""), packageName = getPackageInfo(component?.path, storyPath), fallbackImport = getFallbackImport(packageName, componentName), imports = getImports({ components: allComponents, packageName }).join(`
16284
+ `).trim() || fallbackImport, stories = extractStorySnippets(csf, component?.componentName, filterStoryIds), base2 = {
16285
+ id,
16286
+ name: componentName ?? title,
16287
+ path: storyFilePath,
16288
+ stories,
16289
+ import: imports || void 0,
16290
+ jsDocTags: {}
16291
+ }, {
16292
+ reactDocgen,
16293
+ reactDocgenTypescript,
16294
+ reactComponentMeta,
16295
+ docgenDescription,
16296
+ docgenJsDocTags,
16297
+ docgenError
16298
+ } = getComponentDocgenData(component, docgenEngine);
16299
+ if (!reactDocgen && !reactDocgenTypescript && !reactComponentMeta) {
16300
+ let error = csf._meta?.component ? {
16301
+ name: "No component import found",
16302
+ message: `No component file found for the "${csf.meta.component}" component.`
16303
+ } : {
16304
+ name: "No component found",
16305
+ message: "We could not detect the component from your story file. Specify meta.component."
16306
+ };
16307
+ return {
16308
+ ...base2,
16309
+ jsDocTags: base2.jsDocTags ?? {},
16310
+ error: docgenError ?? {
16311
+ name: error.name,
16312
+ message: (csf._metaStatementPath?.buildCodeFrameError(error.message).message ?? error.message) + `
16313
+
16314
+ ${entry.importPath}:
16315
+ ${storyFile}`
16253
16316
  }
16317
+ };
16254
16318
  }
16255
- // ---------------------------------------------------------------------------
16256
- // Adapted from:
16257
- // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L101-L234
16258
- // ---------------------------------------------------------------------------
16259
- findMatchTSConfig(filePath) {
16260
- let fileName = filePath.replace(/\\/g, "/"), dir = path3.dirname(fileName);
16261
- for (; !this.searchedDirs.has(dir); ) {
16262
- this.searchedDirs.add(dir);
16263
- for (let tsConfigName of rootTsConfigNames) {
16264
- let tsconfigPath = path3.join(dir, tsConfigName).replace(/\\/g, "/");
16265
- this.typescript.sys.fileExists(tsconfigPath) && this.rootTsConfigs.add(tsconfigPath);
16266
- }
16267
- let parent = path3.dirname(dir);
16268
- if (parent === dir)
16269
- break;
16270
- dir = parent;
16319
+ let metaJsDoc = extractDescription2(csf._metaStatement) || void 0, { description, summary, jsDocTags } = extractComponentDescription(
16320
+ metaJsDoc,
16321
+ docgenDescription,
16322
+ docgenJsDocTags
16323
+ ), subcomponentEntries = Object.fromEntries(
16324
+ subcomponents.map((subcomponent) => [
16325
+ subcomponent.name,
16326
+ createSubcomponentDocgen({
16327
+ component: subcomponent.component,
16328
+ declaredName: subcomponent.name,
16329
+ docgenEngine,
16330
+ packageName,
16331
+ storyFilePath
16332
+ })
16333
+ ])
16334
+ );
16335
+ return {
16336
+ ...base2,
16337
+ description,
16338
+ summary,
16339
+ import: imports || void 0,
16340
+ reactDocgen,
16341
+ reactDocgenTypescript,
16342
+ reactComponentMeta,
16343
+ jsDocTags,
16344
+ ...Object.keys(subcomponentEntries).length > 0 ? { subcomponents: subcomponentEntries } : {},
16345
+ error: docgenError
16346
+ };
16347
+ }
16348
+
16349
+ // src/componentManifest/componentMetaManagerSingleton.ts
16350
+ import { logger as logger8 } from "storybook/internal/node-logger";
16351
+
16352
+ // src/componentManifest/componentMeta/ComponentMetaManager.ts
16353
+ import { logger as logger7 } from "storybook/internal/node-logger";
16354
+ import { existsSync as existsSync3, watch } from "fs";
16355
+ import * as path3 from "path";
16356
+
16357
+ // src/componentManifest/componentMeta/ComponentMetaProject.ts
16358
+ var import_language_core = __toESM(require_language_core(), 1), import_typescript = __toESM(require_typescript(), 1);
16359
+ import * as path2 from "path";
16360
+
16361
+ // src/componentManifest/componentMeta/componentMetaExtractor.ts
16362
+ var LARGE_SOURCE_THRESHOLD = 30, MAX_UNWRAP_DEPTH = 5, MAX_SERIALIZATION_DEPTH = 5;
16363
+ function isLiteralType(type) {
16364
+ return type.isStringLiteral() || type.isNumberLiteral();
16365
+ }
16366
+ function isUnionType(type) {
16367
+ return type.isUnion();
16368
+ }
16369
+ function isWrappedExpression(typescript, expression) {
16370
+ return typescript.isParenthesizedExpression(expression) || typescript.isAsExpression(expression) || typescript.isNonNullExpression(expression) || (typescript.isSatisfiesExpression?.(expression) ?? !1);
16371
+ }
16372
+ function resolveAliasedSymbol(typescript, checker, symbol) {
16373
+ return symbol.flags & typescript.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
16374
+ }
16375
+ function getSymbolContextNode(symbol) {
16376
+ return symbol.valueDeclaration ?? symbol.getDeclarations()?.[0];
16377
+ }
16378
+ function resolveComponentSymbolFromNode(typescript, checker, node) {
16379
+ if (!node)
16380
+ return;
16381
+ let symbol = checker.getSymbolAtLocation(node);
16382
+ return symbol ? resolveComponentSymbol(typescript, checker, symbol, node) : void 0;
16383
+ }
16384
+ function resolveComponentSymbol(typescript, checker, symbol, contextNode, depth = 0) {
16385
+ let resolved = resolveAliasedSymbol(typescript, checker, symbol);
16386
+ if (depth > MAX_UNWRAP_DEPTH)
16387
+ return resolved;
16388
+ let declarationForPromotion = getSymbolContextNode(resolved);
16389
+ if (declarationForPromotion && (typescript.isArrowFunction(declarationForPromotion) || typescript.isFunctionExpression(declarationForPromotion)) && declarationForPromotion.parent && typescript.isVariableDeclaration(declarationForPromotion.parent) && typescript.isIdentifier(declarationForPromotion.parent.name)) {
16390
+ let variableSymbol = checker.getSymbolAtLocation(declarationForPromotion.parent.name);
16391
+ variableSymbol && (resolved = resolveAliasedSymbol(typescript, checker, variableSymbol));
16392
+ }
16393
+ let declaration = getSymbolContextNode(resolved);
16394
+ if (declaration) {
16395
+ if (typescript.isShorthandPropertyAssignment(declaration)) {
16396
+ let valueSymbol = checker.getShorthandAssignmentValueSymbol(declaration);
16397
+ if (valueSymbol)
16398
+ return resolveComponentSymbol(
16399
+ typescript,
16400
+ checker,
16401
+ valueSymbol,
16402
+ declaration.name,
16403
+ depth + 1
16404
+ );
16271
16405
  }
16272
- if (this.rootTsConfigs.size === 0)
16273
- return null;
16274
- let prepareClosestRootCommandLine = () => {
16275
- let matches = [];
16276
- for (let rootTsConfig of this.rootTsConfigs)
16277
- isFileInDir(fileName, path3.dirname(rootTsConfig)) && matches.push(rootTsConfig);
16278
- matches = matches.sort((a, b) => sortTSConfigs(fileName, a, b)), matches.length && getCommandLine(matches[0]);
16279
- }, findIndirectReferenceTsconfig = () => findTSConfig((tsconfig) => !!this.configProjects.get(tsconfig)?.hasSourceFile(fileName)), findDirectIncludeTsconfig = () => findTSConfig((tsconfig) => {
16280
- let commandLine = getCommandLine(tsconfig);
16281
- return new Set(commandLine?.fileNames ?? []).has(fileName);
16282
- }), findTSConfig = (match) => {
16283
- let checked = /* @__PURE__ */ new Set();
16284
- for (let rootTsConfig of [...this.rootTsConfigs].sort(
16285
- (a, b) => sortTSConfigs(fileName, a, b)
16286
- )) {
16287
- let project = this.configProjects.get(rootTsConfig);
16288
- if (project) {
16289
- let chains = getReferencesChains(project.getCommandLine(), rootTsConfig, []);
16290
- chains = chains.reverse();
16291
- for (let chain of chains)
16292
- for (let i = chain.length - 1; i >= 0; i--) {
16293
- let tsconfig = chain[i];
16294
- if (!checked.has(tsconfig) && (checked.add(tsconfig), match(tsconfig)))
16295
- return tsconfig;
16406
+ if (typescript.isPropertyAssignment(declaration)) {
16407
+ let next = resolveComponentSymbolFromNode(typescript, checker, declaration.initializer);
16408
+ if (next)
16409
+ return next;
16410
+ }
16411
+ if (typescript.isBinaryExpression(declaration) && declaration.operatorToken.kind === typescript.SyntaxKind.EqualsToken) {
16412
+ let next = resolveComponentSymbolFromNode(typescript, checker, declaration.right);
16413
+ if (next)
16414
+ return next;
16415
+ }
16416
+ }
16417
+ let typeSymbol = (!!(resolved.flags & typescript.SymbolFlags.Property) || declaration !== void 0 && (typescript.isPropertyAssignment(declaration) || typescript.isShorthandPropertyAssignment(declaration) || typescript.isPropertySignature(declaration) || typescript.isPropertyDeclaration(declaration) || typescript.isBinaryExpression(declaration) && declaration.operatorToken.kind === typescript.SyntaxKind.EqualsToken)) && checker.getTypeOfSymbolAtLocation(resolved, contextNode).getSymbol?.();
16418
+ if (typeSymbol) {
16419
+ let resolvedTypeSymbol = resolveAliasedSymbol(typescript, checker, typeSymbol), typeDeclaration = getSymbolContextNode(resolvedTypeSymbol);
16420
+ if (resolvedTypeSymbol !== resolved && typeDeclaration)
16421
+ return resolveComponentSymbol(
16422
+ typescript,
16423
+ checker,
16424
+ resolvedTypeSymbol,
16425
+ typeDeclaration,
16426
+ depth + 1
16427
+ );
16428
+ }
16429
+ return resolved;
16430
+ }
16431
+ function findImportSymbolInStoryFile(typescript, checker, storySourceFile, componentRef) {
16432
+ let importSpecifier = componentRef.importId, importName = componentRef.importName, memberAccess = componentRef.member;
16433
+ if (importSpecifier)
16434
+ for (let stmt of storySourceFile.statements) {
16435
+ if (!typescript.isImportDeclaration(stmt))
16436
+ continue;
16437
+ let moduleSpec = stmt.moduleSpecifier;
16438
+ if (!typescript.isStringLiteral(moduleSpec) || moduleSpec.text !== importSpecifier)
16439
+ continue;
16440
+ let clause = stmt.importClause;
16441
+ if (!clause)
16442
+ continue;
16443
+ let importSymbol;
16444
+ if (importName === "default") {
16445
+ if (clause.name && (importSymbol = checker.getSymbolAtLocation(clause.name)), !importSymbol && clause.namedBindings && typescript.isNamedImports(clause.namedBindings)) {
16446
+ for (let spec of clause.namedBindings.elements)
16447
+ if ((spec.propertyName ?? spec.name).text === "default") {
16448
+ importSymbol = checker.getSymbolAtLocation(spec.name);
16449
+ break;
16296
16450
  }
16297
16451
  }
16452
+ } else if (clause.namedBindings && typescript.isNamedImports(clause.namedBindings)) {
16453
+ for (let spec of clause.namedBindings.elements)
16454
+ if ((spec.propertyName ?? spec.name).text === importName) {
16455
+ importSymbol = checker.getSymbolAtLocation(spec.name);
16456
+ break;
16457
+ }
16298
16458
  }
16299
- return null;
16300
- }, getReferencesChains = (commandLine, tsConfig, before) => {
16301
- if (commandLine.projectReferences?.length) {
16302
- let newChains = [];
16303
- for (let projectReference of commandLine.projectReferences) {
16304
- let tsConfigPath = projectReference.path.replace(/\\/g, "/");
16305
- if (this.typescript.sys.directoryExists(tsConfigPath)) {
16306
- let newTsConfigPath = path3.join(tsConfigPath, "tsconfig.json"), newJsConfigPath = path3.join(tsConfigPath, "jsconfig.json");
16307
- this.typescript.sys.fileExists(newTsConfigPath) ? tsConfigPath = newTsConfigPath : this.typescript.sys.fileExists(newJsConfigPath) && (tsConfigPath = newJsConfigPath);
16459
+ if (!importSymbol && memberAccess && clause.namedBindings && typescript.isNamespaceImport(clause.namedBindings) && (importSymbol = checker.getSymbolAtLocation(clause.namedBindings.name)), importSymbol)
16460
+ return importSymbol;
16461
+ }
16462
+ }
16463
+ function metaComponentMatchesRef(typescript, checker, storySourceFile, componentRef, metaComponentInitializer) {
16464
+ let refSymbol = findImportSymbolInStoryFile(typescript, checker, storySourceFile, componentRef), metaSymbol = resolveComponentSymbolFromNode(typescript, checker, metaComponentInitializer);
16465
+ if (refSymbol && metaSymbol && !componentRef.member)
16466
+ return resolveAliasedSymbol(typescript, checker, refSymbol) === resolveAliasedSymbol(typescript, checker, metaSymbol);
16467
+ if (typescript.isIdentifier(metaComponentInitializer))
16468
+ return componentRef.componentName === metaComponentInitializer.text;
16469
+ if (typescript.isPropertyAccessExpression(metaComponentInitializer) && typescript.isIdentifier(metaComponentInitializer.expression)) {
16470
+ let metaName = `${metaComponentInitializer.expression.text}.${metaComponentInitializer.name.text}`;
16471
+ return componentRef.componentName === metaName;
16472
+ }
16473
+ return !1;
16474
+ }
16475
+ function resolvePropsFromStoryFile(typescript, checker, storySourceFile, componentRef) {
16476
+ let memberAccess = componentRef.member, importSymbol = findImportSymbolInStoryFile(
16477
+ typescript,
16478
+ checker,
16479
+ storySourceFile,
16480
+ componentRef
16481
+ );
16482
+ if (!importSymbol)
16483
+ return;
16484
+ let result;
16485
+ function extractPropsFromJsx(node) {
16486
+ let sig = checker.getResolvedSignature(node);
16487
+ if (!sig)
16488
+ return;
16489
+ let params = sig.getParameters();
16490
+ return params.length === 0 ? checker.getTypeFromTypeNode(typescript.factory.createTypeLiteralNode([])) : checker.getTypeOfSymbolAtLocation(params[0], node);
16491
+ }
16492
+ function visit(node) {
16493
+ if (!result) {
16494
+ if (typescript.isJsxSelfClosingElement(node) || typescript.isJsxOpeningElement(node)) {
16495
+ let tagName = node.tagName;
16496
+ if (memberAccess) {
16497
+ if (typescript.isPropertyAccessExpression(tagName) && tagName.name.text === memberAccess) {
16498
+ let leftSym = checker.getSymbolAtLocation(tagName.expression);
16499
+ if (leftSym && importSymbol && leftSym === importSymbol) {
16500
+ let propsType = extractPropsFromJsx(node);
16501
+ if (propsType) {
16502
+ let memberSymbol = checker.getSymbolAtLocation(tagName.name) ?? checker.getTypeAtLocation(tagName.expression).getProperty(tagName.name.text) ?? resolveComponentSymbolFromNode(typescript, checker, tagName);
16503
+ result = {
16504
+ componentRef,
16505
+ propsType,
16506
+ symbol: memberSymbol ? resolveComponentSymbol(typescript, checker, memberSymbol, tagName.name) : resolveAliasedSymbol(typescript, checker, importSymbol)
16507
+ };
16508
+ return;
16509
+ }
16510
+ }
16308
16511
  }
16309
- let beforeIndex = before.indexOf(tsConfigPath);
16310
- if (beforeIndex >= 0)
16311
- newChains.push(before.slice(0, Math.max(beforeIndex, 1)));
16312
- else {
16313
- let referenceCommandLine = getCommandLine(tsConfigPath);
16314
- if (referenceCommandLine)
16315
- for (let chain of getReferencesChains(referenceCommandLine, tsConfigPath, [
16316
- ...before,
16317
- tsConfig
16318
- ]))
16319
- newChains.push(chain);
16512
+ } else if (typescript.isIdentifier(tagName)) {
16513
+ let sym = checker.getSymbolAtLocation(tagName);
16514
+ if (sym && importSymbol && sym === importSymbol) {
16515
+ let propsType = extractPropsFromJsx(node);
16516
+ if (propsType) {
16517
+ result = {
16518
+ componentRef,
16519
+ propsType,
16520
+ symbol: resolveAliasedSymbol(typescript, checker, sym)
16521
+ };
16522
+ return;
16523
+ }
16320
16524
  }
16321
16525
  }
16322
- return newChains;
16323
- } else
16324
- return [[...before, tsConfig]];
16325
- }, getCommandLine = (tsConfig) => this.getOrCreateConfiguredProject(tsConfig)?.getCommandLine();
16326
- return prepareClosestRootCommandLine(), findDirectIncludeTsconfig() ?? findIndirectReferenceTsconfig();
16327
- }
16328
- // ---------------------------------------------------------------------------
16329
- // Adapted from:
16330
- // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L236-L256
16331
- // ---------------------------------------------------------------------------
16332
- getOrCreateConfiguredProject(tsconfig) {
16333
- tsconfig = tsconfig.replace(/\\/g, "/");
16334
- let project = this.configProjects.get(tsconfig);
16335
- if (!project)
16336
- try {
16337
- let getCommandLine = () => this.parseConfigWorker(tsconfig);
16338
- project = new ComponentMetaProject(
16339
- this.typescript,
16340
- getCommandLine(),
16341
- tsconfig,
16342
- this.fsFileSnapshots,
16343
- getCommandLine
16344
- ), this.configProjects.set(tsconfig, project), this.watching && (this.watchDirectory(path3.dirname(tsconfig)), this.watchProgramSourceDirs(project));
16345
- } catch (err) {
16346
- return logger5.debug(`[reactComponentMeta] Failed to parse tsconfig ${tsconfig}: ${err}`), null;
16347
16526
  }
16348
- return project;
16349
- }
16350
- // ---------------------------------------------------------------------------
16351
- // Adapted from:
16352
- // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L258-L284
16353
- // ---------------------------------------------------------------------------
16354
- getOrCreateInferredProject(fileName) {
16355
- return this.inferredProject || (this.inferredProject = new ComponentMetaProject(
16356
- this.typescript,
16357
- {
16358
- options: {
16359
- ...DEFAULT_INFERRED_OPTIONS,
16360
- target: this.typescript.ScriptTarget.Latest,
16361
- module: this.typescript.ModuleKind.ESNext,
16362
- moduleResolution: this.typescript.ModuleResolutionKind.Bundler,
16363
- jsx: this.typescript.JsxEmit.ReactJSX
16364
- },
16365
- fileNames: [],
16366
- errors: []
16367
- },
16368
- void 0,
16369
- this.fsFileSnapshots
16370
- )), this.inferredProject.ensureFiles([fileName]), this.inferredProject;
16371
- }
16372
- // ---------------------------------------------------------------------------
16373
- // Adapted from:
16374
- // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProjectLs.ts#L262-L353
16375
- // ---------------------------------------------------------------------------
16376
- parseConfigWorker(tsconfig) {
16377
- let config = this.typescript.readJsonConfigFile(tsconfig, this.typescript.sys.readFile), content = this.typescript.parseJsonSourceFileConfigFileContent(
16378
- config,
16379
- this.typescript.sys,
16380
- path3.dirname(tsconfig),
16381
- {},
16382
- tsconfig
16383
- );
16384
- return content.options.outDir = void 0, content.fileNames = content.fileNames.map((fileName) => fileName.replace(/\\/g, "/")), content;
16385
- }
16386
- // ---------------------------------------------------------------------------
16387
- // File events
16388
- // ---------------------------------------------------------------------------
16389
- /**
16390
- * Broadcast file changes to all projects. Each project selectively bumps projectVersion.
16391
- *
16392
- * Adapted from:
16393
- * https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/kit/lib/createChecker.ts#L409-L432
16394
- */
16395
- onFilesChanged(changes) {
16396
- for (let project of this.configProjects.values())
16397
- project.onFilesChanged(changes);
16398
- this.inferredProject?.onFilesChanged(changes);
16399
- }
16400
- /**
16401
- * Adapted from:
16402
- * https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L43-L68
16403
- */
16404
- onConfigChanged(configPath, type) {
16405
- if (configPath = configPath.replace(/\\/g, "/"), type === "created")
16406
- this.rootTsConfigs.add(configPath);
16407
- else if ((type === "changed" || type === "deleted") && this.configProjects.has(configPath)) {
16408
- type === "deleted" && this.rootTsConfigs.delete(configPath);
16409
- let project = this.configProjects.get(configPath);
16410
- this.configProjects.delete(configPath), project?.dispose();
16527
+ typescript.forEachChild(node, visit);
16411
16528
  }
16412
- this.searchedDirs.clear();
16413
16529
  }
16414
- // ---------------------------------------------------------------------------
16415
- // Our own file watching layer (no Volar equivalent — we're standalone)
16416
- // ---------------------------------------------------------------------------
16417
- startWatching() {
16418
- if (!this.watching) {
16419
- this.watching = !0;
16420
- for (let tsconfig of this.configProjects.keys())
16421
- this.watchDirectory(path3.dirname(tsconfig));
16422
- this.watchProgramSourceDirs();
16423
- }
16530
+ return visit(storySourceFile), result;
16531
+ }
16532
+ function resolvePropsFromComponentType(typescript, checker, componentType) {
16533
+ let callSigs = componentType.getCallSignatures();
16534
+ if (callSigs.length > 0) {
16535
+ let sig = callSigs[0];
16536
+ if (sig.parameters.length === 0)
16537
+ return checker.getVoidType();
16538
+ let propsType = checker.getTypeOfSymbol(sig.parameters[0]);
16539
+ if (!(propsType.flags & typescript.TypeFlags.Any))
16540
+ return propsType;
16424
16541
  }
16425
- /**
16426
- * Watch directories that contain source files from all TS programs. This covers monorepo setups
16427
- * where stories import components via path aliases (e.g. apps/storybook/ imports from
16428
- * packages/ui/ via tsconfig paths).
16429
- */
16430
- watchProgramSourceDirs(singleProject) {
16431
- let dirs = /* @__PURE__ */ new Set();
16432
- if (singleProject)
16433
- for (let filePath of singleProject.getSourceFilePaths())
16434
- dirs.add(path3.dirname(filePath));
16435
- else {
16436
- for (let project of this.configProjects.values())
16437
- for (let filePath of project.getSourceFilePaths())
16438
- dirs.add(path3.dirname(filePath));
16439
- if (this.inferredProject)
16440
- for (let filePath of this.inferredProject.getSourceFilePaths())
16441
- dirs.add(path3.dirname(filePath));
16442
- }
16443
- let roots = /* @__PURE__ */ new Set();
16444
- for (let dir of dirs) {
16445
- let candidate = dir;
16446
- for (; candidate !== path3.dirname(candidate); ) {
16447
- let normalized = candidate.replace(/\\/g, "/"), alreadyWatched = !1;
16448
- for (let watched of this.watchersByDir.keys())
16449
- if (normalized === watched || normalized.startsWith(watched + "/")) {
16450
- alreadyWatched = !0;
16451
- break;
16452
- }
16453
- if (alreadyWatched)
16454
- break;
16455
- if (this.typescript.sys.fileExists(path3.join(candidate, "package.json")) || this.typescript.sys.fileExists(path3.join(candidate, "tsconfig.json"))) {
16456
- roots.add(candidate);
16457
- break;
16458
- }
16459
- candidate = path3.dirname(candidate);
16460
- }
16542
+ let ctorSigs = componentType.getConstructSignatures();
16543
+ for (let sig of ctorSigs) {
16544
+ let propsSym = sig.getReturnType().getProperty("props");
16545
+ if (propsSym) {
16546
+ let propsType = checker.getTypeOfSymbol(propsSym);
16547
+ if (!(propsType.flags & typescript.TypeFlags.Any))
16548
+ return propsType;
16461
16549
  }
16462
- for (let root of roots)
16463
- this.watchDirectory(root);
16464
16550
  }
16465
- watchDirectory(dir) {
16466
- if (!this.watching)
16551
+ }
16552
+ function resolvePropsFromComponentExport(typescript, checker, componentSourceFile, componentRef) {
16553
+ let moduleSymbol = checker.getSymbolAtLocation(componentSourceFile);
16554
+ if (!moduleSymbol)
16555
+ return;
16556
+ let exports = checker.getExportsOfModule(checker.getMergedSymbol(moduleSymbol)), exportName = componentRef.importName ?? componentRef.componentName.split(".").at(-1);
16557
+ if (!exportName)
16558
+ return;
16559
+ let exportSymbol, componentType;
16560
+ if (componentRef.namespace && componentRef.member) {
16561
+ let namespaceExportName = componentRef.importName ?? componentRef.member;
16562
+ if (exportSymbol = namespaceExportName === "default" ? exports.find((symbol) => symbol.getName() === "default") : exports.find((symbol) => symbol.getName() === namespaceExportName), !exportSymbol)
16467
16563
  return;
16468
- let normalized = dir.replace(/\\/g, "/");
16469
- for (let watched of this.watchersByDir.keys())
16470
- if (normalized === watched || normalized.startsWith(watched + "/"))
16564
+ componentType = checker.getTypeOfSymbol(exportSymbol);
16565
+ } else {
16566
+ if (exportSymbol = exportName === "default" ? exports.find((symbol) => symbol.getName() === "default") : exports.find((symbol) => symbol.getName() === exportName), !exportSymbol)
16567
+ return;
16568
+ if (componentType = checker.getTypeOfSymbol(exportSymbol), componentRef.member) {
16569
+ let memberSymbol = componentType.getProperty(componentRef.member);
16570
+ if (!memberSymbol)
16471
16571
  return;
16472
- for (let [watched, watcher] of this.watchersByDir)
16473
- watched.startsWith(normalized + "/") && (watcher.close(), this.watchersByDir.delete(watched));
16474
- try {
16475
- let watcher = watch(dir, { recursive: !0 }, (eventType, filename) => {
16476
- if (!filename)
16477
- return;
16478
- let filePath = path3.resolve(dir, filename).replace(/\\/g, "/");
16479
- if (filePath.includes("/node_modules/") || filePath.includes("/.git/"))
16480
- return;
16481
- let existing = this.pendingEvents.get(filePath);
16482
- existing && clearTimeout(existing), this.pendingEvents.set(
16483
- filePath,
16484
- setTimeout(() => {
16485
- this.pendingEvents.delete(filePath), eventType === "rename" ? existsSync3(filePath) ? this.handleFileEvent(filePath, "created") : this.handleFileEvent(filePath, "deleted") : this.handleFileEvent(filePath, "changed");
16486
- }, 50)
16487
- );
16488
- });
16489
- watcher.unref(), this.watchersByDir.set(normalized, watcher);
16490
- } catch (err) {
16491
- logger5.debug(`[reactComponentMeta] Failed to watch directory ${normalized}: ${err}`);
16572
+ exportSymbol = memberSymbol, componentType = checker.getTypeOfSymbol(memberSymbol);
16492
16573
  }
16493
16574
  }
16494
- stopWatching() {
16495
- for (let timeout of this.pendingEvents.values())
16496
- clearTimeout(timeout);
16497
- this.pendingEvents.clear();
16498
- for (let watcher of this.watchersByDir.values())
16499
- watcher.close();
16500
- this.watchersByDir.clear(), this.watching = !1;
16501
- }
16502
- /**
16503
- * Map raw fs.watch events to LSP-style FileChangeType before broadcasting.
16504
- *
16505
- * Fs.watch reports atomic saves (sed -i, editors) as `rename` → we classify as `created` (file
16506
- * exists after rename). But an IDE/LSP would report an atomic save of an _existing_ file as
16507
- * `Changed`, not `Created`.
16508
- *
16509
- * We reclassify here so that onFilesChanged stays 1:1 with Volar Kit.
16510
- */
16511
- handleFileEvent(filePath, type) {
16512
- if (type === "created") {
16513
- for (let project of this.configProjects.values())
16514
- if (project.hasSourceFile(filePath)) {
16515
- type = "changed";
16516
- break;
16517
- }
16518
- type === "created" && this.inferredProject?.hasSourceFile(filePath) && (type = "changed");
16519
- }
16520
- let basename3 = path3.basename(filePath);
16521
- if (rootTsConfigNames.includes(basename3)) {
16522
- this.onConfigChanged(filePath, type);
16523
- return;
16575
+ let propsType = resolvePropsFromComponentType(typescript, checker, componentType), contextNode = exportSymbol ? getSymbolContextNode(exportSymbol) : void 0;
16576
+ if (!(!propsType || !exportSymbol || !contextNode))
16577
+ return {
16578
+ componentRef,
16579
+ propsType,
16580
+ symbol: resolveComponentSymbol(typescript, checker, exportSymbol, contextNode)
16581
+ };
16582
+ }
16583
+ function getPropSourceFile(prop) {
16584
+ let declarations = prop.getDeclarations();
16585
+ if (declarations?.length) {
16586
+ for (let decl of declarations) {
16587
+ let fileName = decl.getSourceFile().fileName;
16588
+ if (!fileName.includes("node_modules") && !fileName.endsWith(".d.ts"))
16589
+ return fileName;
16524
16590
  }
16525
- this.onFilesChanged([{ filePath, type }]);
16526
- }
16527
- dispose() {
16528
- this.stopWatching();
16529
- for (let project of this.configProjects.values())
16530
- project.dispose();
16531
- this.inferredProject?.dispose(), this.configProjects.clear(), this.inferredProject = void 0, this.fsFileSnapshots.clear(), this.searchedDirs.clear(), this.rootTsConfigs.clear();
16591
+ return declarations[0].getSourceFile().fileName;
16532
16592
  }
16533
- };
16534
- function sortTSConfigs(file, a, b) {
16535
- let inA = isFileInDir(file, path3.dirname(a)), inB = isFileInDir(file, path3.dirname(b));
16536
- if (inA !== inB)
16537
- return (inB ? 1 : 0) - (inA ? 1 : 0);
16538
- let aLength = a.split("/").length, bLength = b.split("/").length;
16539
- if (aLength === bLength) {
16540
- let aWeight = path3.basename(a) === "tsconfig.json" ? 1 : 0;
16541
- return (path3.basename(b) === "tsconfig.json" ? 1 : 0) - aWeight;
16593
+ }
16594
+ function getParentType(typescript, prop) {
16595
+ let declarations = prop.getDeclarations();
16596
+ if (!declarations?.length)
16597
+ return;
16598
+ let node = declarations[0].parent;
16599
+ for (; node; ) {
16600
+ if (typescript.isInterfaceDeclaration(node) || typescript.isTypeAliasDeclaration(node))
16601
+ return {
16602
+ name: node.name.getText(),
16603
+ fileName: node.getSourceFile().fileName
16604
+ };
16605
+ node = node.parent;
16542
16606
  }
16543
- return bLength - aLength;
16544
16607
  }
16545
- function isFileInDir(fileName, dir) {
16546
- let relative3 = path3.relative(dir, fileName);
16547
- return !!relative3 && !relative3.startsWith("..") && !path3.isAbsolute(relative3);
16608
+ function getAllDeclarationParents(typescript, prop) {
16609
+ let declarations = prop.getDeclarations();
16610
+ if (!declarations?.length)
16611
+ return;
16612
+ let parents = [];
16613
+ for (let declaration of declarations) {
16614
+ let { parent } = declaration;
16615
+ parent && (typescript.isInterfaceDeclaration(parent) || typescript.isTypeAliasDeclaration(parent) ? parents.push({
16616
+ name: parent.name.getText(),
16617
+ fileName: parent.getSourceFile().fileName
16618
+ }) : typescript.isTypeLiteralNode(parent) && parents.push({
16619
+ name: "TypeLiteral",
16620
+ fileName: parent.getSourceFile().fileName
16621
+ }));
16622
+ }
16623
+ return parents.length > 0 ? parents : void 0;
16548
16624
  }
16549
-
16550
- // src/componentManifest/generateCodeSnippet.ts
16551
- import { types as t2 } from "storybook/internal/babel";
16552
- function getCodeSnippet(csf, storyName, componentName) {
16553
- let storyDeclaration = csf._storyDeclarationPath[storyName], metaObj = csf._metaNode;
16554
- if (!storyDeclaration) {
16555
- let message = "Expected story to be a function or variable declaration";
16556
- throw csf._storyPaths[storyName]?.buildCodeFrameError(message) ?? message;
16625
+ function serializeType(typescript, checker, type, isRequired, depth = 0) {
16626
+ if (depth > MAX_SERIALIZATION_DEPTH)
16627
+ return { name: checker.typeToString(type) };
16628
+ if (type.isUnion()) {
16629
+ let nonUndefinedTypes = type.types.filter(
16630
+ (t6) => !(t6.getFlags() & typescript.TypeFlags.Undefined)
16631
+ ), literalMembers = nonUndefinedTypes.filter(isLiteralType);
16632
+ if (literalMembers.length > 0 && literalMembers.length === nonUndefinedTypes.length)
16633
+ return {
16634
+ name: "enum",
16635
+ raw: literalMembers.map((m) => checker.typeToString(m)).join(" | "),
16636
+ value: literalMembers.map((m) => ({
16637
+ value: JSON.stringify(m.value)
16638
+ }))
16639
+ };
16640
+ if (!isRequired && nonUndefinedTypes.length === 1 && nonUndefinedTypes.length < type.types.length)
16641
+ return { name: checker.typeToString(nonUndefinedTypes[0]) };
16557
16642
  }
16558
- let storyPath;
16559
- if (storyDeclaration.isFunctionDeclaration())
16560
- storyPath = storyDeclaration;
16561
- else if (storyDeclaration.isVariableDeclarator()) {
16562
- let init = storyDeclaration.get("init");
16563
- invariant(
16564
- init.isExpression(),
16565
- () => storyDeclaration.buildCodeFrameError("Expected story initializer to be an expression").message
16566
- ), storyPath = init;
16567
- } else
16568
- throw storyDeclaration.buildCodeFrameError(
16569
- "Expected story to be a function or variable declaration"
16570
- );
16571
- let normalizedPath = storyPath;
16572
- if (storyPath.isCallExpression()) {
16573
- let callee = storyPath.get("callee");
16574
- if (callee.isMemberExpression()) {
16575
- let obj = callee.get("object"), prop = callee.get("property"), isBind = prop.isIdentifier() && prop.node.name === "bind" || t2.isStringLiteral(prop.node) && prop.node.value === "bind";
16576
- if (obj.isIdentifier() && isBind) {
16577
- let resolved = resolveIdentifierInit(storyDeclaration, obj);
16578
- resolved && (normalizedPath = resolved);
16643
+ let constraint = type.getConstraint?.();
16644
+ return constraint && constraint !== type ? serializeType(typescript, checker, constraint, isRequired, depth + 1) : { name: checker.typeToString(type) };
16645
+ }
16646
+ function unwrapToFunction(typescript, node, depth = 0, checker) {
16647
+ if (!(depth > MAX_UNWRAP_DEPTH)) {
16648
+ if (typescript.isArrowFunction(node) || typescript.isFunctionExpression(node) || typescript.isFunctionDeclaration(node))
16649
+ return node;
16650
+ if (typescript.isCallExpression(node))
16651
+ for (let arg of node.arguments) {
16652
+ let fn = unwrapToFunction(typescript, arg, depth + 1, checker);
16653
+ if (fn)
16654
+ return fn;
16579
16655
  }
16580
- }
16581
- if (storyPath === normalizedPath) {
16582
- let args = storyPath.get("arguments");
16583
- if (args.length !== 0) {
16584
- invariant(
16585
- args.length === 1,
16586
- () => storyPath.buildCodeFrameError("Could not evaluate story expression").message
16587
- );
16588
- let storyArg = args[0];
16589
- invariant(
16590
- storyArg.isExpression(),
16591
- () => storyPath.buildCodeFrameError("Could not evaluate story expression").message
16592
- ), normalizedPath = storyArg;
16656
+ if (typescript.isParenthesizedExpression(node) || typescript.isAsExpression(node))
16657
+ return unwrapToFunction(typescript, node.expression, depth + 1, checker);
16658
+ if (typescript.isIdentifier(node) && checker) {
16659
+ let symbol = checker.getSymbolAtLocation(node);
16660
+ if (symbol) {
16661
+ let decl = (symbol.flags & typescript.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol).valueDeclaration;
16662
+ if (decl && typescript.isVariableDeclaration(decl) && decl.initializer)
16663
+ return unwrapToFunction(typescript, decl.initializer, depth + 1, checker);
16664
+ if (decl && typescript.isFunctionDeclaration(decl))
16665
+ return decl;
16593
16666
  }
16594
16667
  }
16595
16668
  }
16596
- normalizedPath = normalizedPath.isTSSatisfiesExpression() || normalizedPath.isTSAsExpression() ? normalizedPath.get("expression") : normalizedPath;
16597
- let storyFn;
16598
- if (normalizedPath.isArrowFunctionExpression() || normalizedPath.isFunctionExpression() || normalizedPath.isFunctionDeclaration())
16599
- storyFn = normalizedPath;
16600
- else if (!normalizedPath.isObjectExpression() && !(normalizedPath.isCallExpression() && Array.isArray(normalizedPath.node.arguments) && normalizedPath.node.arguments.length === 0))
16601
- throw normalizedPath.buildCodeFrameError(
16602
- "Expected story to be csf factory, function or an object expression"
16603
- );
16604
- let storyProps = normalizedPath.isObjectExpression() ? normalizedPath.get("properties").filter((p) => p.isObjectProperty()) : [], metaPath = pathForNode(csf._file.path, metaObj), metaProps = metaPath?.isObjectExpression() ? metaPath.get("properties").filter((p) => p.isObjectProperty()) : [], getRenderPath = (object) => {
16605
- let renderPath = object.find((p) => keyOf(p.node) === "render")?.get("value");
16606
- if (!renderPath)
16607
- return { kind: "missing" };
16608
- if (renderPath.isIdentifier()) {
16609
- let resolved = resolveIdentifierInit(storyDeclaration, renderPath);
16610
- return resolved && (resolved.isArrowFunctionExpression() || resolved.isFunctionExpression() || resolved.isFunctionDeclaration()) ? { kind: "resolved", path: resolved } : { kind: "unresolved" };
16669
+ }
16670
+ function resolveLiteralValue(typescript, checker, node, depth = 0) {
16671
+ if (depth > MAX_UNWRAP_DEPTH || typescript.isStringLiteral(node) || typescript.isNumericLiteral(node) || typescript.isNoSubstitutionTemplateLiteral(node) || node.kind === typescript.SyntaxKind.TrueKeyword || node.kind === typescript.SyntaxKind.FalseKeyword || node.kind === typescript.SyntaxKind.NullKeyword)
16672
+ return node.getText();
16673
+ if (typescript.isIdentifier(node)) {
16674
+ if (node.text === "undefined")
16675
+ return "undefined";
16676
+ let symbol = checker.getSymbolAtLocation(node);
16677
+ if (!symbol)
16678
+ return node.getText();
16679
+ let decl = (symbol.flags & typescript.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol).valueDeclaration;
16680
+ return decl && typescript.isVariableDeclaration(decl) && decl.initializer || decl && typescript.isEnumMember(decl) && decl.initializer || decl && typescript.isBindingElement(decl) && decl.initializer ? resolveLiteralValue(typescript, checker, decl.initializer, depth + 1) : node.getText();
16681
+ }
16682
+ if (typescript.isPropertyAccessExpression(node)) {
16683
+ let symbol = checker.getSymbolAtLocation(node);
16684
+ if (symbol) {
16685
+ let decl = symbol.valueDeclaration;
16686
+ if (decl && typescript.isEnumMember(decl) && decl.initializer || decl && typescript.isPropertyAssignment(decl) && decl.initializer || decl && typescript.isVariableDeclaration(decl) && decl.initializer)
16687
+ return resolveLiteralValue(typescript, checker, decl.initializer, depth + 1);
16611
16688
  }
16612
- if (!(renderPath.isArrowFunctionExpression() || renderPath.isFunctionExpression()))
16613
- throw renderPath.buildCodeFrameError(
16614
- "Expected render to be an arrow function or function expression"
16689
+ return node.getText();
16690
+ }
16691
+ return node.getText();
16692
+ }
16693
+ function collectBindingDefaults(typescript, pattern, defaults, checker) {
16694
+ for (let element of pattern.elements)
16695
+ if (element.initializer) {
16696
+ let propName = element.propertyName ? element.propertyName.getText() : element.name.getText();
16697
+ defaults.set(
16698
+ propName,
16699
+ checker ? resolveLiteralValue(typescript, checker, element.initializer) : element.initializer.getText()
16615
16700
  );
16616
- return { kind: "resolved", path: renderPath };
16617
- }, metaRender = getRenderPath(metaProps), storyRender = getRenderPath(storyProps);
16618
- storyFn || (storyFn = storyRender.kind === "resolved" ? storyRender.path : storyRender.kind === "missing" && metaRender.kind === "resolved" ? metaRender.path : void 0);
16619
- let metaArgs = metaArgsRecord(metaObj ?? null), storyArgsPath = storyProps.filter((p) => keyOf(p.node) === "args").map((p) => p.get("value")).find((v) => v.isObjectExpression()), storyArgs = argsRecordFromObjectPath(storyArgsPath), storyAssignedArgsPath = storyArgsAssignmentPath(csf._file.path, storyName), storyAssignedArgs = argsRecordFromObjectPath(storyAssignedArgsPath), merged = { ...metaArgs, ...storyArgs, ...storyAssignedArgs }, entries = Object.entries(merged).filter(([k]) => k !== "children"), validEntries = entries.filter(([k, v]) => isValidJsxAttrName(k) && v != null), invalidEntries = entries.filter(([k, v]) => !isValidJsxAttrName(k) && v != null), injectedAttrs = validEntries.map(([k, v]) => toAttr(k, v)).filter((a) => a != null);
16620
- if (storyFn) {
16621
- let fn = storyFn.node;
16622
- if (t2.isArrowFunctionExpression(fn) && (t2.isJSXElement(fn.body) || t2.isJSXFragment(fn.body))) {
16623
- let spreadRes = transformArgsSpreadsInJsx(fn.body, merged), inlineRes = inlineArgsInJsx(spreadRes.node, merged);
16624
- if (spreadRes.changed || inlineRes.changed) {
16625
- let newFn = t2.arrowFunctionExpression([], inlineRes.node, fn.async);
16626
- return t2.variableDeclaration("const", [
16627
- t2.variableDeclarator(t2.identifier(storyName), newFn)
16628
- ]);
16629
- }
16630
- }
16631
- let stmts = t2.isFunctionDeclaration(fn) || t2.isArrowFunctionExpression(fn) && t2.isBlockStatement(fn.body) || t2.isFunctionExpression(fn) && t2.isBlockStatement(fn.body) ? fn.body.body : void 0;
16632
- if (stmts) {
16633
- let changed = !1, newBody = stmts.map((stmt) => {
16634
- if (t2.isReturnStatement(stmt) && stmt.argument && (t2.isJSXElement(stmt.argument) || t2.isJSXFragment(stmt.argument))) {
16635
- let spreadRes = transformArgsSpreadsInJsx(stmt.argument, merged), inlineRes = inlineArgsInJsx(spreadRes.node, merged);
16636
- if (spreadRes.changed || inlineRes.changed)
16637
- return changed = !0, t2.returnStatement(inlineRes.node);
16638
- }
16639
- return stmt;
16640
- });
16641
- if (changed)
16642
- return t2.isFunctionDeclaration(fn) ? t2.functionDeclaration(
16643
- t2.identifier(storyName),
16644
- [],
16645
- t2.blockStatement(newBody),
16646
- fn.generator,
16647
- fn.async
16648
- ) : t2.variableDeclaration("const", [
16649
- t2.variableDeclarator(
16650
- t2.identifier(storyName),
16651
- t2.arrowFunctionExpression([], t2.blockStatement(newBody), fn.async)
16652
- )
16653
- ]);
16654
16701
  }
16655
- return t2.isFunctionDeclaration(fn) ? t2.functionDeclaration(t2.identifier(storyName), fn.params, fn.body, fn.generator, fn.async) : t2.variableDeclaration("const", [t2.variableDeclarator(t2.identifier(storyName), fn)]);
16656
- }
16657
- invariant(componentName, "Could not generate snippet without component name.");
16658
- let invalidSpread = buildInvalidSpread(invalidEntries), name = t2.jsxIdentifier(componentName), openingElAttrs = invalidSpread ? [...injectedAttrs, invalidSpread] : injectedAttrs, children = toJsxChildren(merged.children), selfClosing = children.length === 0, arrow = t2.arrowFunctionExpression(
16659
- [],
16660
- t2.jsxElement(
16661
- t2.jsxOpeningElement(name, openingElAttrs, selfClosing),
16662
- selfClosing ? null : t2.jsxClosingElement(name),
16663
- children,
16664
- selfClosing
16665
- )
16666
- );
16667
- return t2.variableDeclaration("const", [t2.variableDeclarator(t2.identifier(storyName), arrow)]);
16668
16702
  }
16669
- function buildInvalidSpread(entries) {
16670
- if (entries.length === 0)
16671
- return null;
16672
- let objectProps = entries.map(
16673
- ([k, v]) => t2.objectProperty(t2.stringLiteral(k), t2.isExpression(v) ? v : t2.identifier("undefined"))
16674
- );
16675
- return t2.jsxSpreadAttribute(t2.objectExpression(objectProps));
16703
+ function unwrapExpression(typescript, expression) {
16704
+ let current2 = expression;
16705
+ for (; isWrappedExpression(typescript, current2); )
16706
+ current2 = current2.expression;
16707
+ return current2;
16676
16708
  }
16677
- var keyOf = (p) => t2.isIdentifier(p.key) ? p.key.name : t2.isStringLiteral(p.key) ? p.key.value : null, isValidJsxAttrName = (n) => /^[A-Za-z_][A-Za-z0-9_:-]*$/.test(n), argsRecordFromObjectPath = (objPath) => objPath ? Object.fromEntries(
16678
- objPath.get("properties").filter((p) => p.isObjectProperty()).map((p) => [keyOf(p.node), p.get("value").node]).filter((e) => !!e[0])
16679
- ) : {};
16680
- function storyArgsAssignmentPath(program, storyName) {
16681
- let found = null;
16682
- return program.traverse({
16683
- AssignmentExpression(p) {
16684
- let left = p.get("left"), right = p.get("right");
16685
- if (left.isMemberExpression()) {
16686
- let obj = left.get("object"), prop = left.get("property"), isStoryIdent = obj.isIdentifier() && obj.node.name === storyName, isArgsProp = prop.isIdentifier() && prop.node.name === "args" && !left.node.computed || t2.isStringLiteral(prop.node) && left.node.computed && prop.node.value === "args";
16687
- isStoryIdent && isArgsProp && right.isObjectExpression() && (found = right);
16688
- }
16689
- }
16690
- }), found;
16709
+ function isPropsIdentifier(typescript, node, paramName, checker) {
16710
+ if (!typescript.isIdentifier(node))
16711
+ return !1;
16712
+ if (!checker)
16713
+ return node.text === paramName.text;
16714
+ let symbol = checker.getSymbolAtLocation(node), paramSymbol = checker.getSymbolAtLocation(paramName);
16715
+ return symbol !== void 0 && symbol === paramSymbol;
16691
16716
  }
16692
- var argsRecordFromObjectNode = (obj) => obj ? Object.fromEntries(
16693
- obj.properties.filter((p) => t2.isObjectProperty(p)).map((p) => [keyOf(p), p.value]).filter((e) => !!e[0])
16694
- ) : {}, metaArgsRecord = (meta) => {
16695
- if (!meta)
16696
- return {};
16697
- let argsProp = meta.properties.find(
16698
- (p) => t2.isObjectProperty(p) && keyOf(p) === "args"
16699
- );
16700
- return argsProp && t2.isObjectExpression(argsProp.value) ? argsRecordFromObjectNode(argsProp.value) : {};
16701
- }, toAttr = (key, value) => t2.isBooleanLiteral(value) ? value.value ? t2.jsxAttribute(t2.jsxIdentifier(key), null) : t2.jsxAttribute(t2.jsxIdentifier(key), t2.jsxExpressionContainer(value)) : t2.isStringLiteral(value) ? t2.jsxAttribute(t2.jsxIdentifier(key), t2.stringLiteral(value.value)) : t2.isExpression(value) ? t2.jsxAttribute(t2.jsxIdentifier(key), t2.jsxExpressionContainer(value)) : null, toJsxChildren = (node) => node ? t2.isStringLiteral(node) ? [t2.jsxText(node.value)] : t2.isJSXElement(node) || t2.isJSXFragment(node) ? [node] : t2.isExpression(node) ? [t2.jsxExpressionContainer(node)] : [] : [];
16702
- function getArgsMemberKey(expr) {
16703
- if (t2.isMemberExpression(expr) && t2.isIdentifier(expr.object) && expr.object.name === "args") {
16704
- if (t2.isIdentifier(expr.property) && !expr.computed)
16705
- return expr.property.name;
16706
- if (t2.isStringLiteral(expr.property) && expr.computed)
16707
- return expr.property.value;
16708
- }
16709
- if (t2.isOptionalMemberExpression?.(expr) && t2.isIdentifier(expr.object) && expr.object.name === "args") {
16710
- let prop = expr.property;
16711
- if (t2.isIdentifier(prop) && !expr.computed)
16712
- return prop.name;
16713
- if (t2.isStringLiteral(prop) && expr.computed)
16714
- return prop.value;
16715
- }
16716
- return null;
16717
+ function isPropsDerivedInitializer(typescript, initializer, paramName, checker) {
16718
+ let expr = unwrapExpression(typescript, initializer);
16719
+ return isPropsIdentifier(typescript, expr, paramName, checker) ? !0 : typescript.isAwaitExpression(expr) ? isPropsDerivedInitializer(typescript, expr.expression, paramName, checker) : typescript.isBinaryExpression(expr) && [
16720
+ typescript.SyntaxKind.BarBarToken,
16721
+ typescript.SyntaxKind.QuestionQuestionToken,
16722
+ typescript.SyntaxKind.AmpersandAmpersandToken
16723
+ ].includes(expr.operatorToken.kind) ? isPropsDerivedInitializer(typescript, expr.left, paramName, checker) || isPropsDerivedInitializer(typescript, expr.right, paramName, checker) : typescript.isConditionalExpression(expr) ? isPropsDerivedInitializer(typescript, expr.whenTrue, paramName, checker) || isPropsDerivedInitializer(typescript, expr.whenFalse, paramName, checker) : typescript.isCallExpression(expr) || typescript.isNewExpression(expr) ? expr.arguments?.some(
16724
+ (arg) => isPropsDerivedInitializer(typescript, arg, paramName, checker)
16725
+ ) ?? !1 : !1;
16717
16726
  }
16718
- function inlineArgsInJsx(node, merged) {
16719
- let changed = !1;
16720
- if (t2.isJSXElement(node)) {
16721
- let opening = node.openingElement, newAttrs = opening.attributes.flatMap((a) => {
16722
- if (!t2.isJSXAttribute(a))
16723
- return [a];
16724
- let name = t2.isJSXIdentifier(a.name) ? a.name.name : null;
16725
- if (!(name && a.value && t2.isJSXExpressionContainer(a.value)))
16726
- return [a];
16727
- let key = getArgsMemberKey(a.value.expression);
16728
- if (!(key && key in merged))
16729
- return [a];
16730
- let repl = toAttr(name, merged[key]);
16731
- return changed = !0, repl ? [repl] : [];
16732
- }), newChildren = node.children.flatMap((c) => {
16733
- if (t2.isJSXElement(c) || t2.isJSXFragment(c)) {
16734
- let res = inlineArgsInJsx(c, merged);
16735
- return changed ||= res.changed, [res.node];
16736
- }
16737
- return t2.isJSXExpressionContainer(c) && getArgsMemberKey(c.expression) === "children" && merged.children ? (changed = !0, toJsxChildren(merged.children)) : [c];
16738
- }), selfClosing = opening.selfClosing && newChildren.length === 0;
16739
- return {
16740
- node: t2.jsxElement(
16741
- t2.jsxOpeningElement(opening.name, newAttrs, selfClosing),
16742
- selfClosing ? null : node.closingElement ?? t2.jsxClosingElement(opening.name),
16743
- newChildren,
16744
- selfClosing
16745
- ),
16746
- changed
16747
- };
16727
+ function extractDestructuringDefaults(typescript, resolved, checker) {
16728
+ let defaults = /* @__PURE__ */ new Map(), decl = resolved.valueDeclaration;
16729
+ if (!decl)
16730
+ return defaults;
16731
+ let fn;
16732
+ if (typescript.isFunctionDeclaration(decl)) {
16733
+ if (fn = decl, !fn.body) {
16734
+ let allDecls = resolved.getDeclarations?.() ?? [];
16735
+ for (let d of allDecls)
16736
+ if (typescript.isFunctionDeclaration(d) && d.body) {
16737
+ fn = d;
16738
+ break;
16739
+ }
16740
+ }
16741
+ } else typescript.isVariableDeclaration(decl) && decl.initializer ? fn = unwrapToFunction(typescript, decl.initializer, 0, checker) : typescript.isExportAssignment(decl) && decl.expression && (fn = unwrapToFunction(typescript, decl.expression, 0, checker));
16742
+ if (!fn)
16743
+ return defaults;
16744
+ let firstParam = fn.parameters[0];
16745
+ if (!firstParam)
16746
+ return defaults;
16747
+ if (typescript.isObjectBindingPattern(firstParam.name))
16748
+ return collectBindingDefaults(typescript, firstParam.name, defaults, checker), defaults;
16749
+ let propsParamName = typescript.isIdentifier(firstParam.name) ? firstParam.name : void 0;
16750
+ if (fn.body && propsParamName) {
16751
+ let body = typescript.isBlock(fn.body) ? fn.body : void 0;
16752
+ if (body) {
16753
+ for (let stmt of body.statements)
16754
+ if (typescript.isVariableStatement(stmt))
16755
+ for (let varDecl of stmt.declarationList.declarations)
16756
+ typescript.isObjectBindingPattern(varDecl.name) && varDecl.initializer && isPropsDerivedInitializer(typescript, varDecl.initializer, propsParamName, checker) && collectBindingDefaults(typescript, varDecl.name, defaults, checker);
16757
+ }
16748
16758
  }
16749
- let fragChildren = node.children.flatMap((c) => {
16750
- if (t2.isJSXElement(c) || t2.isJSXFragment(c)) {
16751
- let res = inlineArgsInJsx(c, merged);
16752
- return changed ||= res.changed, [res.node];
16759
+ return defaults;
16760
+ }
16761
+ function collectObjectLiteralDefaults(typescript, checker, obj, defaults) {
16762
+ for (let prop of obj.properties)
16763
+ if (typescript.isPropertyAssignment(prop) && prop.name) {
16764
+ let name = prop.name.getText();
16765
+ defaults.set(name, resolveLiteralValue(typescript, checker, prop.initializer));
16766
+ } else if (typescript.isShorthandPropertyAssignment(prop)) {
16767
+ let name = prop.name.getText(), symbol = checker.getShorthandAssignmentValueSymbol(prop);
16768
+ symbol?.valueDeclaration && typescript.isVariableDeclaration(symbol.valueDeclaration) && symbol.valueDeclaration.initializer ? defaults.set(
16769
+ name,
16770
+ resolveLiteralValue(typescript, checker, symbol.valueDeclaration.initializer)
16771
+ ) : defaults.set(name, name);
16753
16772
  }
16754
- return t2.isJSXExpressionContainer(c) && getArgsMemberKey(c.expression) === "children" && "children" in merged ? (changed = !0, toJsxChildren(merged.children)) : [c];
16755
- });
16756
- return { node: t2.jsxFragment(node.openingFragment, node.closingFragment, fragChildren), changed };
16757
16773
  }
16758
- function transformArgsSpreadsInJsx(node, merged) {
16759
- let changed = !1, makeInjectedPieces = (existing) => {
16760
- let entries = Object.entries(merged).filter(([k, v]) => v != null && k !== "children"), validEntries = entries.filter(([k]) => isValidJsxAttrName(k)), invalidEntries = entries.filter(([k]) => !isValidJsxAttrName(k)), injectedAttrs = validEntries.map(([k, v]) => toAttr(k, v)).filter((a) => !!a).filter((a) => t2.isJSXIdentifier(a.name) && !existing.has(a.name.name)), invalidSpread = buildInvalidSpread(invalidEntries.filter(([k]) => !existing.has(k)));
16761
- return invalidSpread ? [...injectedAttrs, invalidSpread] : injectedAttrs;
16762
- };
16763
- if (t2.isJSXElement(node)) {
16764
- let opening = node.openingElement, attrs = opening.attributes, isArgsSpread = (a) => t2.isJSXSpreadAttribute(a) && t2.isIdentifier(a.argument) && a.argument.name === "args", sawArgsSpread = attrs.some(isArgsSpread), firstIdx = attrs.findIndex(isArgsSpread), nonArgsAttrs = attrs.filter((a) => !isArgsSpread(a)), insertionIndex = sawArgsSpread ? attrs.slice(0, firstIdx).filter((a) => !isArgsSpread(a)).length : 0, newAttrs = sawArgsSpread ? (() => {
16765
- let existing = new Set(
16766
- nonArgsAttrs.filter((a) => t2.isJSXAttribute(a)).flatMap((a) => t2.isJSXIdentifier(a.name) ? [a.name.name] : [])
16767
- ), pieces = makeInjectedPieces(existing);
16768
- return changed = !0, [
16769
- ...nonArgsAttrs.slice(0, insertionIndex),
16770
- ...pieces,
16771
- ...nonArgsAttrs.slice(insertionIndex)
16772
- ];
16773
- })() : nonArgsAttrs, newChildren = node.children.flatMap((c) => {
16774
- if (t2.isJSXElement(c) || t2.isJSXFragment(c)) {
16775
- let res = transformArgsSpreadsInJsx(c, merged);
16776
- return changed ||= res.changed, [res.node];
16774
+ function extractStaticDefaultProps(typescript, checker, resolved) {
16775
+ let defaults = /* @__PURE__ */ new Map(), decl = resolved.valueDeclaration ?? resolved.getDeclarations()?.[0];
16776
+ if (!decl)
16777
+ return defaults;
16778
+ let componentSourceFile = decl.getSourceFile();
16779
+ for (let stmt of componentSourceFile.statements) {
16780
+ if (typescript.isClassDeclaration(stmt) && stmt.name) {
16781
+ if (checker.getSymbolAtLocation(stmt.name) !== resolved)
16782
+ continue;
16783
+ for (let member of stmt.members) {
16784
+ if (!typescript.isPropertyDeclaration(member) || !member.name || member.name.getText() !== "defaultProps" || !member.initializer)
16785
+ continue;
16786
+ let initializer = member.initializer;
16787
+ if (typescript.isIdentifier(initializer)) {
16788
+ let symDecl = checker.getSymbolAtLocation(initializer)?.valueDeclaration;
16789
+ symDecl && typescript.isVariableDeclaration(symDecl) && symDecl.initializer && (initializer = symDecl.initializer);
16790
+ }
16791
+ typescript.isObjectLiteralExpression(initializer) && collectObjectLiteralDefaults(typescript, checker, initializer, defaults);
16777
16792
  }
16778
- return [c];
16779
- }), children = sawArgsSpread && newChildren.length === 0 && merged.children ? (changed = !0, toJsxChildren(merged.children)) : newChildren, selfClosing = children.length === 0;
16780
- return {
16781
- node: t2.jsxElement(
16782
- t2.jsxOpeningElement(opening.name, newAttrs, selfClosing),
16783
- selfClosing ? null : node.closingElement ?? t2.jsxClosingElement(opening.name),
16784
- children,
16785
- selfClosing
16786
- ),
16787
- changed
16788
- };
16789
- }
16790
- let fragChildren = node.children.flatMap((c) => {
16791
- if (t2.isJSXElement(c) || t2.isJSXFragment(c)) {
16792
- let res = transformArgsSpreadsInJsx(c, merged);
16793
- return changed ||= res.changed, [res.node];
16794
16793
  }
16795
- return [c];
16796
- });
16797
- return { node: t2.jsxFragment(node.openingFragment, node.closingFragment, fragChildren), changed };
16798
- }
16799
- function resolveIdentifierInit(storyPath, identifier) {
16800
- let programPath = storyPath.findParent((p) => p.isProgram());
16801
- if (!programPath)
16802
- return null;
16803
- for (let stmt of programPath.get("body")) {
16804
- if (stmt.isFunctionDeclaration() && stmt.node.id?.name === identifier.node.name)
16805
- return stmt;
16806
- if (stmt.isExportNamedDeclaration()) {
16807
- let decl = stmt.get("declaration");
16808
- if (decl.isFunctionDeclaration() && decl.node.id?.name === identifier.node.name)
16809
- return decl;
16794
+ if (typescript.isExpressionStatement(stmt) && typescript.isBinaryExpression(stmt.expression) && stmt.expression.operatorToken.kind === typescript.SyntaxKind.EqualsToken) {
16795
+ let left = stmt.expression.left;
16796
+ if (!typescript.isPropertyAccessExpression(left) || left.name.text !== "defaultProps")
16797
+ continue;
16798
+ let targetSymbol = checker.getSymbolAtLocation(left.expression);
16799
+ if (!targetSymbol || (targetSymbol.flags & typescript.SymbolFlags.Alias ? checker.getAliasedSymbol(targetSymbol) : targetSymbol) !== resolved)
16800
+ continue;
16801
+ let right = stmt.expression.right;
16802
+ if (typescript.isIdentifier(right)) {
16803
+ let symDecl = checker.getSymbolAtLocation(right)?.valueDeclaration;
16804
+ symDecl && typescript.isVariableDeclaration(symDecl) && symDecl.initializer && (right = symDecl.initializer);
16805
+ }
16806
+ typescript.isObjectLiteralExpression(right) && collectObjectLiteralDefaults(typescript, checker, right, defaults);
16810
16807
  }
16811
16808
  }
16812
- let match = programPath.get("body").flatMap((stmt) => {
16813
- if (stmt.isVariableDeclaration())
16814
- return stmt.get("declarations");
16815
- if (stmt.isExportNamedDeclaration()) {
16816
- let decl = stmt.get("declaration");
16817
- if (decl && decl.isVariableDeclaration())
16818
- return decl.get("declarations");
16819
- }
16820
- return [];
16821
- }).find((d) => {
16822
- let id = d.get("id");
16823
- return id.isIdentifier() && id.node.name === identifier.node.name;
16824
- });
16825
- if (!match)
16826
- return null;
16827
- let init = match.get("init");
16828
- return init && init.isExpression() ? init : null;
16809
+ return defaults;
16829
16810
  }
16830
- function pathForNode(program, target) {
16831
- if (!target)
16832
- return;
16833
- let found;
16834
- return program.traverse({
16835
- enter(p) {
16836
- p.node && p.node === target && (found = p, p.stop());
16837
- }
16838
- }), found;
16811
+ function getJSDocDefault(typescript, prop, checker) {
16812
+ let tags = prop.getJsDocTags(checker);
16813
+ for (let tag of tags)
16814
+ if (tag.name === "default" || tag.name === "defaultValue")
16815
+ return typescript.displayPartsToString(tag.text) || void 0;
16839
16816
  }
16840
-
16841
- // src/componentManifest/getComponentImports.ts
16842
- import { dirname as dirname8 } from "node:path";
16843
- import { babelParse as babelParse2, recast, types as t3 } from "storybook/internal/babel";
16844
- import { logger as logger7 } from "storybook/internal/node-logger";
16845
-
16846
- // src/componentManifest/reactDocgenTypescript.ts
16847
- import { dirname as dirname7 } from "node:path";
16848
- import { logger as logger6 } from "storybook/internal/node-logger";
16849
- var typeScriptPromise, reactDocgenTypescriptPromise, loadTypeScript = () => typeScriptPromise ??= import("typescript"), loadReactDocgenTypescript = () => reactDocgenTypescriptPromise ??= import("react-docgen-typescript"), LARGE_NON_USER_SOURCE_THRESHOLD = 30, getPropSource = (prop) => prop.parent?.fileName ?? prop.declarations?.[0]?.fileName, getLargeNonUserPropSources = (props) => {
16850
- let countBySource = /* @__PURE__ */ new Map();
16851
- for (let prop of Object.values(props)) {
16852
- let source = getPropSource(prop);
16853
- (source?.includes("node_modules") || source?.endsWith(".d.ts")) && countBySource.set(source, (countBySource.get(source) ?? 0) + 1);
16854
- }
16855
- let largeNonUserSources = /* @__PURE__ */ new Set();
16856
- for (let [source, count] of countBySource)
16857
- count > LARGE_NON_USER_SOURCE_THRESHOLD && largeNonUserSources.add(source);
16858
- return largeNonUserSources;
16859
- };
16860
- function findDisplayNameAssignment(typescript, sourceFile, identifierName) {
16861
- for (let statement of sourceFile.statements) {
16862
- if (!typescript.isExpressionStatement(statement))
16863
- continue;
16864
- let expr = statement.expression;
16865
- if (typescript.isBinaryExpression(expr) && expr.operatorToken.kind === typescript.SyntaxKind.EqualsToken && typescript.isPropertyAccessExpression(expr.left) && expr.left.name.text === "displayName" && typescript.isIdentifier(expr.left.expression) && expr.left.expression.text === identifierName && typescript.isStringLiteral(expr.right))
16866
- return expr.right.text;
16867
- }
16817
+ function extractPropItem(typescript, checker, prop, contextNode, defaultsMap) {
16818
+ let isRequired = !!!(prop.flags & typescript.SymbolFlags.Optional), propType = checker.getTypeOfSymbolAtLocation(prop, contextNode), type = serializeType(typescript, checker, propType, isRequired), description = typescript.displayPartsToString(prop.getDocumentationComment(checker)), parent = getParentType(typescript, prop), declarations = getAllDeclarationParents(typescript, prop), propName = prop.getName(), destructuringDefault = defaultsMap?.get(propName), jsDocDefault = getJSDocDefault(typescript, prop, checker), defaultStr = destructuringDefault ?? jsDocDefault;
16819
+ return {
16820
+ name: propName,
16821
+ required: isRequired,
16822
+ type,
16823
+ description,
16824
+ defaultValue: defaultStr !== void 0 ? { value: defaultStr } : null,
16825
+ parent,
16826
+ declarations
16827
+ };
16868
16828
  }
16869
- function getExportNameMap(typescript, checker, sourceFile) {
16870
- let moduleSymbol = checker.getSymbolAtLocation(sourceFile);
16871
- if (!moduleSymbol)
16872
- return /* @__PURE__ */ new Map();
16873
- let result = /* @__PURE__ */ new Map(), fileName = sourceFile.fileName.replace(/.*\//, "").replace(/\.[^.]+$/, "");
16874
- for (let exportSymbol of checker.getExportsOfModule(moduleSymbol)) {
16875
- let resolved = exportSymbol.flags & typescript.SymbolFlags.Alias ? checker.getAliasedSymbol(exportSymbol) : exportSymbol, declaration = resolved.valueDeclaration ?? resolved.getDeclarations()?.[0];
16876
- if (!declaration)
16877
- continue;
16878
- let type = checker.getTypeOfSymbolAtLocation(resolved, declaration), isStateless = type.getCallSignatures().some((sig) => {
16879
- let params = sig.getParameters();
16880
- return params.length === 1 || params.length > 0 && params[0].getName() === "props";
16881
- }), isStateful = type.getConstructSignatures().some(
16882
- (sig) => sig.getReturnType().getProperty("props") !== void 0
16883
- );
16884
- if (isStateless || isStateful) {
16885
- let exportName = exportSymbol.getName(), resolvedName = resolved.getName();
16886
- result.set(resolvedName, exportName), exportName === "default" && result.set(fileName, "default");
16887
- let displayNameValue = findDisplayNameAssignment(typescript, sourceFile, resolvedName);
16888
- displayNameValue && result.set(displayNameValue, exportName);
16889
- }
16829
+ function getBulkSourceExclusions(properties) {
16830
+ let propSourceCache = /* @__PURE__ */ new Map(), getSource = (prop) => {
16831
+ let cached2 = propSourceCache.get(prop);
16832
+ return cached2 === void 0 && !propSourceCache.has(prop) && (cached2 = getPropSourceFile(prop), propSourceCache.set(prop, cached2)), cached2;
16833
+ }, sourceCount = /* @__PURE__ */ new Map();
16834
+ for (let prop of properties) {
16835
+ let source = getSource(prop);
16836
+ source && (source.includes("node_modules") || source.endsWith(".d.ts")) && sourceCount.set(source, (sourceCount.get(source) ?? 0) + 1);
16890
16837
  }
16891
- return result;
16892
- }
16893
- var cachedCompilerOptions, cachedFileNames, previousProgram, parser, cachedParserOptionsKey;
16894
- function invalidateParser() {
16895
- parser = void 0, cachedCompilerOptions = void 0, cachedFileNames = void 0, cachedParserOptionsKey = void 0;
16896
- }
16897
- async function getParser5(userOptions) {
16898
- let [typescript, reactDocgenTypescript] = await Promise.all([
16899
- loadTypeScript(),
16900
- loadReactDocgenTypescript()
16901
- ]), optionsKey = JSON.stringify(userOptions ?? {});
16902
- if (parser && cachedParserOptionsKey !== optionsKey && (parser = void 0), !parser) {
16903
- let configPath = findTsconfigPath(process.cwd());
16904
- if (cachedCompilerOptions = { noErrorTruncation: !0, strict: !0 }, configPath) {
16905
- let { config } = typescript.readConfigFile(configPath, typescript.sys.readFile), parsed = typescript.parseJsonConfigFileContent(
16906
- config,
16907
- typescript.sys,
16908
- dirname7(configPath)
16909
- );
16910
- cachedCompilerOptions = { ...parsed.options, noErrorTruncation: !0 }, cachedFileNames = parsed.fileNames;
16911
- } else
16912
- logger6.warn(
16913
- "No tsconfig.json (or tsconfig.base.json / tsconfig.app.json) found. TypeScript component props will not be documented by react-docgen-typescript. Create a tsconfig.json in your project root to enable automatic controls."
16914
- );
16915
- let program = typescript.createProgram(
16916
- cachedFileNames ?? [],
16917
- cachedCompilerOptions,
16918
- void 0,
16919
- previousProgram
16920
- );
16921
- previousProgram = program;
16922
- let parserOptions = {
16923
- shouldExtractLiteralValuesFromEnum: !0,
16924
- shouldRemoveUndefinedFromOptional: !0,
16925
- ...userOptions,
16926
- // Always force savePropValueAsString so default values are in a consistent format
16927
- savePropValueAsString: !0
16928
- };
16929
- parser = {
16930
- program,
16931
- fileParser: reactDocgenTypescript.withCompilerOptions(cachedCompilerOptions, parserOptions)
16932
- }, cachedParserOptionsKey = optionsKey;
16838
+ let bulkSources = new Set(
16839
+ [...sourceCount.entries()].filter(([, count]) => count > LARGE_SOURCE_THRESHOLD).map(([source]) => source)
16840
+ ), excluded = /* @__PURE__ */ new Set();
16841
+ for (let prop of properties) {
16842
+ let source = getSource(prop);
16843
+ source && bulkSources.has(source) && excluded.add(prop.getName());
16933
16844
  }
16934
- return { ...parser, typescript };
16845
+ return excluded;
16935
16846
  }
16936
- function matchComponentDoc(docs, {
16937
- importName,
16938
- localImportName,
16939
- componentName
16847
+ function computeDisplayName({
16848
+ exportSymbol,
16849
+ resolvedSymbol
16940
16850
  }) {
16941
- if (docs.length !== 0)
16942
- return docs.length === 1 ? docs[0] : docs.find(
16943
- (doc) => doc.exportName === importName || doc.exportName === localImportName || doc.displayName === importName || doc.displayName === localImportName || doc.displayName === componentName
16944
- );
16851
+ let resolvedName = resolvedSymbol.getName();
16852
+ if (!exportSymbol)
16853
+ return resolvedName && resolvedName !== "default" && resolvedName !== "__function" ? resolvedName : void 0;
16854
+ let exportName = exportSymbol.getName();
16855
+ return exportName === "default" ? resolvedName && resolvedName !== "default" && resolvedName !== "__function" ? resolvedName : void 0 : exportName;
16945
16856
  }
16946
- function getReactDocgenTypescriptError(path5, {
16947
- importName,
16948
- localImportName,
16949
- componentName
16950
- }, docs) {
16951
- return docs.length === 0 ? {
16952
- name: "react-docgen-typescript found no component docs",
16953
- message: [
16954
- `File: ${path5}`,
16955
- "react-docgen-typescript did not return any component docs for this file."
16956
- ].join(`
16957
- `)
16958
- } : {
16959
- name: "react-docgen-typescript could not match component docs",
16960
- message: [
16961
- `File: ${path5}`,
16962
- "react-docgen-typescript returned component docs for this file, but none matched the story's component import.",
16963
- `Looked for: componentName=${componentName}, localImportName=${localImportName ?? "<none>"}, importName=${importName ?? "<none>"}.`
16964
- ].join(`
16965
- `)
16966
- };
16857
+ function extractComponentJsDocTags(typescript, checker, symbol) {
16858
+ let tags = symbol.getJsDocTags(checker);
16859
+ if (tags.length === 0)
16860
+ return;
16861
+ let groupedTags = groupBy(tags, (tag) => tag.name);
16862
+ return Object.fromEntries(
16863
+ Object.entries(groupedTags).map(([name, grouped]) => [
16864
+ name,
16865
+ (grouped ?? []).map((tag) => typescript.displayPartsToString(tag.text ?? []).trim())
16866
+ ])
16867
+ );
16967
16868
  }
16968
- var parseWithReactDocgenTypescript = asyncCache(
16969
- async (filePath, userOptions) => {
16970
- let { program, fileParser, typescript } = await getParser5(userOptions), checker = program.getTypeChecker(), sourceFile = program.getSourceFile(filePath), docs = fileParser.parseWithProgramProvider(filePath, () => program), exportNameMap = sourceFile ? getExportNameMap(typescript, checker, sourceFile) : /* @__PURE__ */ new Map();
16971
- return docs.map((doc) => {
16972
- let largeNonUserSources = getLargeNonUserPropSources(doc.props);
16973
- return {
16974
- ...doc,
16975
- // Use name-based lookup: displayName is the resolved symbol name, so look it up in the
16976
- // export map to get the public export name. Falls back to displayName when not aliased.
16977
- exportName: exportNameMap.get(doc.displayName) ?? doc.displayName,
16978
- // Filter out bulk props from non-user sources (React built-ins, DOM, CSS-in-JS system props)
16979
- props: Object.fromEntries(
16980
- Object.entries(doc.props).filter(([, prop]) => {
16981
- let source = getPropSource(prop);
16982
- return !source || !largeNonUserSources.has(source);
16983
- })
16984
- )
16985
- };
16986
- });
16987
- },
16988
- { name: "parseWithReactDocgenTypescript" }
16989
- );
16990
-
16991
- // src/componentManifest/getComponentImports.ts
16992
- var baseIdentifier = (component) => component.split(".")[0] ?? component, isTypeSpecifier = (s) => t3.isImportSpecifier(s) && s.importKind === "type", importedName = (im) => t3.isIdentifier(im) ? im.name : im.value, addUniqueBy = (arr, item, eq2) => {
16993
- arr.find(eq2) || arr.push(item);
16994
- }, getComponents = async ({
16995
- csf,
16996
- storyFilePath,
16997
- typescriptOptions = {},
16998
- docgenEngine,
16999
- additionalComponentNames = []
17000
- }) => {
17001
- let { reactDocgenTypescriptOptions } = typescriptOptions, program = csf._file.path, componentSet = /* @__PURE__ */ new Set(), componentDepth = /* @__PURE__ */ new Map(), localToImport = /* @__PURE__ */ new Map(), jsxDepth = 0;
17002
- program.traverse({
17003
- JSXElement: {
17004
- enter() {
17005
- jsxDepth++;
17006
- },
17007
- exit() {
17008
- jsxDepth--;
17009
- }
17010
- },
17011
- JSXOpeningElement(p) {
17012
- let n = p.node.name, name;
17013
- if (t3.isJSXIdentifier(n))
17014
- name = n.name, name && /[A-Z]/.test(name.charAt(0)) && componentSet.add(name);
17015
- else if (t3.isJSXMemberExpression(n)) {
17016
- let jsxNameToString = (nm) => t3.isJSXIdentifier(nm) ? nm.name : `${jsxNameToString(nm.object)}.${jsxNameToString(nm.property)}`;
17017
- name = jsxNameToString(n), componentSet.add(name);
17018
- }
17019
- if (name) {
17020
- let depth = jsxDepth - 1, existing = componentDepth.get(name);
17021
- (existing === void 0 || depth < existing) && componentDepth.set(name, depth);
16869
+ function serializeComponentDoc(typescript, checker, {
16870
+ sourceFile,
16871
+ resolvedComponent,
16872
+ defaultsSourcePath
16873
+ }) {
16874
+ let { componentRef, propsType, symbol } = resolvedComponent, exportName = componentRef.importName;
16875
+ if (!exportName)
16876
+ return;
16877
+ let displayNameOverride = componentRef.componentName, isMemberSelection = !!componentRef.member, filePath = componentRef.path ?? sourceFile.fileName, resolved = resolveAliasedSymbol(typescript, checker, symbol), contextNode = resolved.valueDeclaration ?? resolved.getDeclarations()?.[0];
16878
+ if (!contextNode)
16879
+ return;
16880
+ let moduleSymbol = checker.getSymbolAtLocation(sourceFile), exportSymbol = moduleSymbol ? checker.getExportsOfModule(moduleSymbol).find((candidate) => candidate.getName() === exportName) : void 0, allProperties, unionForceOptional;
16881
+ if (isUnionType(propsType)) {
16882
+ let seen = /* @__PURE__ */ new Map(), forceOptional = /* @__PURE__ */ new Set(), unionMembers = propsType.types, allMemberPropSets = [];
16883
+ for (let member of unionMembers) {
16884
+ let memberPropNames = /* @__PURE__ */ new Set();
16885
+ for (let prop of member.getApparentProperties()) {
16886
+ let name = prop.getName();
16887
+ memberPropNames.add(name);
16888
+ let propType = checker.getTypeOfSymbolAtLocation(prop, contextNode), isOptional = !!(prop.flags & typescript.SymbolFlags.Optional), isDegraded = !!(propType.getFlags() & typescript.TypeFlags.Never) || !!(propType.getFlags() & typescript.TypeFlags.Undefined);
16889
+ (isOptional || isDegraded) && forceOptional.add(name);
16890
+ let existing = seen.get(name);
16891
+ if (!existing)
16892
+ seen.set(name, prop);
16893
+ else if (!isDegraded) {
16894
+ let existingType = checker.getTypeOfSymbolAtLocation(existing, contextNode);
16895
+ (!!(existingType.getFlags() & typescript.TypeFlags.Never) || !!(existingType.getFlags() & typescript.TypeFlags.Undefined)) && seen.set(name, prop);
16896
+ }
17022
16897
  }
16898
+ allMemberPropSets.push(memberPropNames);
17023
16899
  }
17024
- });
17025
- let metaComp = csf._meta?.component;
17026
- metaComp && componentSet.add(metaComp);
17027
- for (let componentName of additionalComponentNames)
17028
- componentSet.add(componentName);
17029
- let components = Array.from(componentSet).sort((a, b) => a.localeCompare(b)), body = program.get("body");
17030
- for (let stmt of body) {
17031
- if (!stmt.isImportDeclaration())
17032
- continue;
17033
- let decl = stmt.node;
17034
- if (decl.importKind === "type")
16900
+ for (let name of seen.keys())
16901
+ allMemberPropSets.every((s) => s.has(name)) || forceOptional.add(name);
16902
+ allProperties = Array.from(seen.values()), unionForceOptional = forceOptional;
16903
+ } else
16904
+ allProperties = propsType.getApparentProperties();
16905
+ let excluded = getBulkSourceExclusions(allProperties), defaultsMap = extractDestructuringDefaults(typescript, resolved, checker);
16906
+ if (defaultsMap.size === 0 && defaultsSourcePath) {
16907
+ let fallbackDefaults = extractDefaultsFromSourceFile(typescript, defaultsSourcePath, {
16908
+ exportName,
16909
+ localName: resolved.getName(),
16910
+ preferLocalName: isMemberSelection
16911
+ });
16912
+ for (let [key, value] of fallbackDefaults)
16913
+ defaultsMap.set(key, value);
16914
+ }
16915
+ let staticDefaults = extractStaticDefaultProps(typescript, checker, resolved);
16916
+ for (let [key, value] of staticDefaults)
16917
+ defaultsMap.has(key) || defaultsMap.set(key, value);
16918
+ let props = {};
16919
+ for (let prop of allProperties) {
16920
+ if (excluded.has(prop.getName()))
17035
16921
  continue;
17036
- let specifiers = decl.specifiers ?? [];
17037
- if (specifiers.length !== 0)
17038
- for (let s of specifiers) {
17039
- if (!("local" in s) || !s.local || isTypeSpecifier(s))
17040
- continue;
17041
- let importId = decl.source.value;
17042
- if (t3.isImportDefaultSpecifier(s))
17043
- localToImport.set(s.local.name, { importId, importName: "default" });
17044
- else if (t3.isImportNamespaceSpecifier(s))
17045
- localToImport.set(s.local.name, { importId, importName: "*" });
17046
- else if (t3.isImportSpecifier(s)) {
17047
- let imported = importedName(s.imported);
17048
- localToImport.set(s.local.name, { importId, importName: imported });
17049
- }
17050
- }
16922
+ let item = extractPropItem(typescript, checker, prop, contextNode, defaultsMap);
16923
+ unionForceOptional?.has(prop.getName()) && (item.required = !1), props[prop.getName()] = item;
17051
16924
  }
17052
- let isLocallyDefinedWithoutImport = (base2) => {
17053
- let binding = program.scope.getBinding(base2);
17054
- return binding ? !!!(binding.path.isImportSpecifier?.() || binding.path.isImportDefaultSpecifier?.() || binding.path.isImportNamespaceSpecifier?.()) : !1;
17055
- }, filteredComponents = components.filter(
17056
- (c) => !isLocallyDefinedWithoutImport(baseIdentifier(c))
17057
- );
17058
- return (await Promise.all(
17059
- filteredComponents.map(async (c) => {
17060
- let depth = componentDepth.get(c), dot = c.indexOf("."), component = dot !== -1 ? (() => {
17061
- let ns = c.slice(0, dot), mem = c.slice(dot + 1), direct = localToImport.get(ns);
17062
- return direct ? direct.importName === "*" ? {
17063
- componentName: c,
17064
- localImportName: ns,
17065
- importId: direct.importId,
17066
- importName: mem,
17067
- namespace: ns,
17068
- member: mem,
17069
- jsxDepth: depth
17070
- } : {
17071
- componentName: c,
17072
- localImportName: ns,
17073
- importId: direct.importId,
17074
- importName: direct.importName,
17075
- member: mem,
17076
- jsxDepth: depth
17077
- } : { componentName: c, member: mem, jsxDepth: depth };
17078
- })() : (() => {
17079
- let direct = localToImport.get(c);
17080
- return direct ? {
17081
- componentName: c,
17082
- localImportName: c,
17083
- importId: direct.importId,
17084
- importName: direct.importName,
17085
- jsxDepth: depth
17086
- } : { componentName: c, jsxDepth: depth };
17087
- })(), path5, isPackage = !1;
17088
- try {
17089
- component.importId && storyFilePath && (path5 = cachedResolveImport(matchPath(component.importId, dirname8(storyFilePath)), {
17090
- basedir: dirname8(storyFilePath)
17091
- }));
17092
- } catch (e) {
17093
- logger7.debug(e);
17094
- }
17095
- try {
17096
- component.importId && !component.importId.startsWith(".") && storyFilePath && (cachedResolveImport(component.importId, { basedir: dirname8(storyFilePath) }), isPackage = !0);
17097
- } catch {
17098
- }
17099
- let componentWithPackage = { ...component, isPackage };
17100
- if (path5) {
17101
- if (docgenEngine === "react-docgen-typescript") {
17102
- let reactDocgenTypescript, reactDocgenTypescriptError;
17103
- try {
17104
- let docs = await parseWithReactDocgenTypescript(path5, reactDocgenTypescriptOptions);
17105
- reactDocgenTypescript = matchComponentDoc(docs, component), reactDocgenTypescript || (reactDocgenTypescriptError = getReactDocgenTypescriptError(path5, component, docs));
17106
- } catch (e) {
17107
- let message = e instanceof Error ? e.message : String(e);
17108
- logger7.debug(`react-docgen-typescript failed for ${path5}: ${message}`), reactDocgenTypescriptError = {
17109
- name: "react-docgen-typescript parse error",
17110
- message: `File: ${path5}
17111
- ${message}`
17112
- };
17113
- }
17114
- let importOverride = reactDocgenTypescript ? getImportTag(reactDocgenTypescript) : void 0;
17115
- return {
17116
- ...componentWithPackage,
17117
- path: path5,
17118
- ...reactDocgenTypescript ? { reactDocgenTypescript } : {},
17119
- ...reactDocgenTypescriptError ? { reactDocgenTypescriptError } : {},
17120
- importOverride
17121
- };
16925
+ let displayName = (isMemberSelection ? displayNameOverride : void 0) ?? computeDisplayName({
16926
+ exportSymbol,
16927
+ resolvedSymbol: resolved
16928
+ }) ?? displayNameOverride, description = typescript.displayPartsToString(resolved.getDocumentationComment(checker)), selectedJsDocTags = extractComponentJsDocTags(typescript, checker, resolved), exportResolved = exportSymbol && exportSymbol !== resolved ? resolveAliasedSymbol(typescript, checker, exportSymbol) : void 0, exportJsDocTags = exportResolved ? extractComponentJsDocTags(typescript, checker, exportResolved) : void 0, jsDocTags = selectedJsDocTags?.import || !exportJsDocTags?.import ? selectedJsDocTags : {
16929
+ ...selectedJsDocTags ?? {},
16930
+ import: exportJsDocTags.import
16931
+ };
16932
+ return {
16933
+ displayName,
16934
+ exportName,
16935
+ filePath,
16936
+ description,
16937
+ jsDocTags,
16938
+ props
16939
+ };
16940
+ }
16941
+ function extractDefaultsFromSourceFile(typescript, filePath, {
16942
+ exportName,
16943
+ localName,
16944
+ preferLocalName = !1
16945
+ }) {
16946
+ let defaults = /* @__PURE__ */ new Map(), content = typescript.sys.readFile(filePath);
16947
+ if (!content)
16948
+ return defaults;
16949
+ let sf = typescript.createSourceFile(
16950
+ filePath,
16951
+ content,
16952
+ typescript.ScriptTarget.Latest,
16953
+ /* setParentNodes */
16954
+ !0
16955
+ ), varMap = /* @__PURE__ */ new Map();
16956
+ for (let stmt of sf.statements) {
16957
+ if (typescript.isVariableStatement(stmt))
16958
+ for (let decl of stmt.declarationList.declarations)
16959
+ typescript.isIdentifier(decl.name) && decl.initializer && varMap.set(decl.name.text, decl.initializer);
16960
+ typescript.isFunctionDeclaration(stmt) && stmt.name && varMap.set(stmt.name.text, stmt);
16961
+ }
16962
+ let fn = preferLocalName ? findLocalFunction(typescript, sf, localName, varMap) ?? findExportedFunction(typescript, sf, exportName, varMap) : findExportedFunction(typescript, sf, exportName, varMap) ?? findLocalFunction(typescript, sf, localName, varMap);
16963
+ if (!fn)
16964
+ return defaults;
16965
+ let firstParam = fn.parameters[0];
16966
+ if (!firstParam)
16967
+ return defaults;
16968
+ if (typescript.isObjectBindingPattern(firstParam.name))
16969
+ collectBindingDefaults(typescript, firstParam.name, defaults);
16970
+ else if (fn.body) {
16971
+ let propsParamName = typescript.isIdentifier(firstParam.name) ? firstParam.name : void 0, body = typescript.isBlock(fn.body) ? fn.body : void 0;
16972
+ if (body && propsParamName) {
16973
+ for (let stmt of body.statements)
16974
+ if (typescript.isVariableStatement(stmt))
16975
+ for (let varDecl of stmt.declarationList.declarations)
16976
+ typescript.isObjectBindingPattern(varDecl.name) && varDecl.initializer && isPropsDerivedInitializer(typescript, varDecl.initializer, propsParamName) && collectBindingDefaults(typescript, varDecl.name, defaults);
16977
+ }
16978
+ }
16979
+ return defaults;
16980
+ }
16981
+ function findLocalFunction(typescript, sf, localName, varMap) {
16982
+ if (!localName)
16983
+ return;
16984
+ let targetExpr = varMap.get(localName);
16985
+ if (targetExpr)
16986
+ return unwrapToFunctionAST(typescript, targetExpr, varMap, 0);
16987
+ }
16988
+ function findExportedFunction(typescript, sf, exportName, varMap) {
16989
+ let targetExpr;
16990
+ for (let stmt of sf.statements) {
16991
+ if (exportName === "default" && typescript.isExportAssignment(stmt) && !stmt.isExportEquals) {
16992
+ targetExpr = stmt.expression;
16993
+ break;
16994
+ }
16995
+ if (typescript.isVariableStatement(stmt) && hasExportModifier(typescript, stmt)) {
16996
+ for (let decl of stmt.declarationList.declarations)
16997
+ if (typescript.isIdentifier(decl.name) && decl.name.text === exportName && decl.initializer) {
16998
+ targetExpr = decl.initializer;
16999
+ break;
17122
17000
  }
17123
- if (docgenEngine === "react-docgen") {
17124
- let reactDocgen = getReactDocgen(path5, componentWithPackage);
17125
- return {
17126
- ...componentWithPackage,
17127
- path: path5,
17128
- reactDocgen,
17129
- importOverride: reactDocgen.type === "success" ? getImportTag(reactDocgen.data) : void 0
17130
- };
17001
+ if (targetExpr)
17002
+ break;
17003
+ }
17004
+ if (typescript.isFunctionDeclaration(stmt) && hasExportModifier(typescript, stmt) && stmt.name?.text === exportName)
17005
+ return findFunctionImpl(typescript, sf, stmt.name.text) ?? stmt;
17006
+ if (typescript.isExportDeclaration(stmt) && stmt.exportClause && typescript.isNamedExports(stmt.exportClause)) {
17007
+ for (let spec of stmt.exportClause.elements) {
17008
+ let exported = spec.name.text, local = spec.propertyName ? spec.propertyName.text : spec.name.text;
17009
+ if (exported === exportName) {
17010
+ targetExpr = varMap.get(local);
17011
+ break;
17131
17012
  }
17132
- if (docgenEngine === "react-component-meta")
17133
- return {
17134
- ...componentWithPackage,
17135
- path: path5
17136
- };
17137
17013
  }
17138
- return componentWithPackage;
17139
- })
17140
- )).sort((a, b) => a.componentName.localeCompare(b.componentName));
17141
- }, getImports = ({
17142
- components,
17143
- packageName
17144
- }) => {
17145
- let withSource = components.filter((c) => !!c.importId).map((c, idx) => {
17146
- let importId = c.importId, overrideSource = (() => {
17147
- if (c.importOverride)
17148
- try {
17149
- let src = babelParse2(c.importOverride).program.body.find((n) => t3.isImportDeclaration(n))?.source?.value;
17150
- return typeof src == "string" ? src : void 0;
17151
- } catch {
17014
+ if (targetExpr)
17015
+ break;
17016
+ }
17017
+ }
17018
+ if (targetExpr || (targetExpr = varMap.get(exportName)), !!targetExpr)
17019
+ return unwrapToFunctionAST(typescript, targetExpr, varMap, 0);
17020
+ }
17021
+ function unwrapToFunctionAST(typescript, node, varMap, depth) {
17022
+ if (!(depth > MAX_UNWRAP_DEPTH)) {
17023
+ if (typescript.isFunctionExpression(node) || typescript.isArrowFunction(node) || typescript.isFunctionDeclaration(node))
17024
+ return node;
17025
+ if (typescript.isParenthesizedExpression(node) || typescript.isAsExpression(node) || typescript.isTypeAssertionExpression && typescript.isTypeAssertionExpression(node))
17026
+ return unwrapToFunctionAST(typescript, node.expression, varMap, depth + 1);
17027
+ if (typescript.isCallExpression(node)) {
17028
+ let callee = node.expression;
17029
+ if (typescript.isPropertyAccessExpression(callee) && typescript.isIdentifier(callee.expression) && callee.expression.text === "Object" && callee.name.text === "assign" && node.arguments.length >= 1 || node.arguments.length >= 1)
17030
+ return unwrapToFunctionAST(typescript, node.arguments[0], varMap, depth + 1);
17031
+ }
17032
+ if (typescript.isIdentifier(node)) {
17033
+ let init = varMap.get(node.text);
17034
+ if (init)
17035
+ return unwrapToFunctionAST(typescript, init, varMap, depth + 1);
17036
+ }
17037
+ }
17038
+ }
17039
+ function findFunctionImpl(typescript, sf, name) {
17040
+ for (let stmt of sf.statements)
17041
+ if (typescript.isFunctionDeclaration(stmt) && stmt.name?.text === name && stmt.body)
17042
+ return stmt;
17043
+ }
17044
+ function hasExportModifier(typescript, node) {
17045
+ return typescript.canHaveModifiers(node) && typescript.getModifiers(node)?.some((m) => m.kind === typescript.SyntaxKind.ExportKeyword) === !0;
17046
+ }
17047
+
17048
+ // src/componentManifest/componentMeta/ComponentMetaProject.ts
17049
+ var ComponentMetaProject = class {
17050
+ constructor(typescript, commandLine, configFileName, fsFileSnapshots = /* @__PURE__ */ new Map(), getCommandLineFn) {
17051
+ this.typescript = typescript;
17052
+ this.commandLine = commandLine;
17053
+ this.configFileName = configFileName;
17054
+ this.fsFileSnapshots = fsFileSnapshots;
17055
+ this.getCommandLineFn = getCommandLineFn;
17056
+ this.projectVersion = 0;
17057
+ this.shouldCheckRootFiles = !1;
17058
+ /** Entries to extract — set by the generator, replayed during warmup for targeted type resolution. */
17059
+ this.entries = [];
17060
+ let language = (0, import_language_core.createLanguage)(
17061
+ [{ getLanguageId: (fileName) => (0, import_typescript.resolveFileLanguageId)(fileName) }],
17062
+ new import_language_core.FileMap(typescript.sys.useCaseSensitiveFileNames),
17063
+ (fileName, includeFsFiles) => {
17064
+ if (!includeFsFiles)
17152
17065
  return;
17153
- }
17154
- })(), rewritten = overrideSource !== void 0 ? overrideSource : (
17155
- // only rewrite to the package name it the import id is not already a valid package
17156
- // tsconfig paths such as ~/components/Button and components/Button are not seen as packages
17157
- packageName && !c.isPackage ? packageName : importId
17066
+ let cache = fsFileSnapshots.get(fileName), modifiedTime = typescript.sys.getModifiedTime?.(fileName)?.valueOf();
17067
+ if (!cache || cache[0] !== modifiedTime)
17068
+ if (typescript.sys.fileExists(fileName)) {
17069
+ let text = typescript.sys.readFile(fileName), snapshot2 = text !== void 0 ? typescript.ScriptSnapshot.fromString(text) : void 0;
17070
+ fsFileSnapshots.set(fileName, [modifiedTime, snapshot2]);
17071
+ } else
17072
+ fsFileSnapshots.set(fileName, [modifiedTime, void 0]);
17073
+ let snapshot = fsFileSnapshots.get(fileName)?.[1];
17074
+ snapshot ? language.scripts.set(fileName, snapshot) : language.scripts.delete(fileName);
17075
+ }
17076
+ ), projectHost = {
17077
+ getCurrentDirectory: () => configFileName ? path2.dirname(configFileName) : commandLine.options.rootDir ?? process.cwd(),
17078
+ getCompilationSettings: () => this.commandLine.options,
17079
+ getProjectReferences: () => this.commandLine.projectReferences,
17080
+ getProjectVersion: () => (this.checkRootFilesUpdate(), this.projectVersion.toString()),
17081
+ getScriptFileNames: () => (this.checkRootFilesUpdate(), this.commandLine.fileNames)
17082
+ }, { languageServiceHost } = (0, import_typescript.createLanguageServiceHost)(
17083
+ typescript,
17084
+ typescript.sys,
17085
+ language,
17086
+ (s) => s,
17087
+ // asScriptId — identity for React (no URI mapping needed)
17088
+ projectHost
17089
+ );
17090
+ this.ls = typescript.createLanguageService(languageServiceHost);
17091
+ }
17092
+ getCommandLine() {
17093
+ return this.commandLine;
17094
+ }
17095
+ dispose() {
17096
+ clearTimeout(this.warmupTimer), this.ls.dispose();
17097
+ }
17098
+ // ---------------------------------------------------------------------------
17099
+ // Project management
17100
+ // ---------------------------------------------------------------------------
17101
+ /**
17102
+ * Batch-add multiple files to the project in one go. Only bumps projectVersion once, avoiding
17103
+ * repeated program rebuilds.
17104
+ */
17105
+ ensureFiles(fileNames) {
17106
+ let added = !1;
17107
+ for (let fileName of fileNames)
17108
+ this.commandLine.fileNames.includes(fileName) || (this.commandLine.fileNames.push(fileName), added = !0);
17109
+ added && this.projectVersion++;
17110
+ }
17111
+ /**
17112
+ * Adapted from:
17113
+ * https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/kit/lib/createChecker.ts#L436-L447
17114
+ */
17115
+ checkRootFilesUpdate() {
17116
+ if (!this.shouldCheckRootFiles || (this.shouldCheckRootFiles = !1, !this.getCommandLineFn))
17117
+ return;
17118
+ let newCommandLine = this.getCommandLineFn();
17119
+ arrayItemsEqual(newCommandLine.fileNames, this.commandLine.fileNames) || (this.commandLine.fileNames = newCommandLine.fileNames, this.projectVersion++);
17120
+ }
17121
+ hasSourceFile(fileName) {
17122
+ return !!this.ls.getProgram()?.getSourceFile(fileName);
17123
+ }
17124
+ /**
17125
+ * Get all non-node_modules source file paths from the TS program. Used by ComponentMetaManager to
17126
+ * watch directories for file changes.
17127
+ */
17128
+ getSourceFilePaths() {
17129
+ let program = this.ls.getProgram();
17130
+ return program ? program.getSourceFiles().map((sf) => sf.fileName.replace(/\\/g, "/")).filter((f) => !f.includes("node_modules")) : [];
17131
+ }
17132
+ /**
17133
+ * Adapted from:
17134
+ * https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/kit/lib/createChecker.ts#L409-L432
17135
+ *
17136
+ * Created events only set shouldCheckRootFiles (version bump happens in checkRootFilesUpdate if
17137
+ * the file list actually changed). Deleted/created break early since they trigger a full config
17138
+ * reparse — processing remaining changes is unnecessary.
17139
+ */
17140
+ onFilesChanged(changes) {
17141
+ for (let { filePath } of changes)
17142
+ this.fsFileSnapshots.delete(filePath);
17143
+ let oldVersion = this.projectVersion, program = this.ls.getProgram();
17144
+ for (let { filePath, type } of changes)
17145
+ if (type === "changed")
17146
+ program?.getSourceFile(filePath) && this.projectVersion++;
17147
+ else if (type === "deleted") {
17148
+ program?.getSourceFile(filePath) && this.projectVersion++, this.shouldCheckRootFiles = !0;
17149
+ break;
17150
+ } else if (type === "created") {
17151
+ this.shouldCheckRootFiles = !0;
17152
+ break;
17153
+ }
17154
+ this.projectVersion !== oldVersion && this.entries.length > 0 && (clearTimeout(this.warmupTimer), this.warmupTimer = setTimeout(() => {
17155
+ try {
17156
+ this.extractPropsFromStories(this.entries);
17157
+ } catch {
17158
+ }
17159
+ }, 100), this.warmupTimer?.unref?.());
17160
+ }
17161
+ // ---------------------------------------------------------------------------
17162
+ // Primary extraction method — probe-free
17163
+ // ---------------------------------------------------------------------------
17164
+ extractPropsFromStories(entries) {
17165
+ this.entries = entries;
17166
+ let allFiles = entries.flatMap(
17167
+ (entry) => entry.component?.path ? [entry.storyPath, entry.component.path] : [entry.storyPath]
17158
17168
  );
17159
- return { c, src: t3.stringLiteral(rewritten), key: rewritten, ord: idx };
17160
- }), orderOfSource = {};
17161
- for (let w of withSource)
17162
- orderOfSource[w.key] === void 0 && (orderOfSource[w.key] = w.ord);
17163
- let buckets = /* @__PURE__ */ new Map(), ensureBucket = (key, src) => {
17164
- let prev = buckets.get(key);
17165
- if (prev)
17166
- return prev;
17167
- let b = {
17168
- source: src,
17169
- defaults: [],
17170
- namespaces: [],
17171
- named: [],
17172
- order: orderOfSource[key] ?? 0
17173
- };
17174
- return buckets.set(key, b), b;
17175
- };
17176
- for (let { c, src, key } of withSource) {
17177
- let b = ensureBucket(key, src), rewritten = src.value !== c.importId, overrideSpec = (() => {
17178
- if (c.importOverride)
17179
- try {
17180
- let decl = babelParse2(c.importOverride).program.body.find((n) => t3.isImportDeclaration(n));
17181
- if (!decl)
17182
- return;
17183
- let spec = (decl.specifiers ?? []).find((s) => !isTypeSpecifier(s));
17184
- return spec ? t3.isImportNamespaceSpecifier(spec) ? { kind: "namespace", local: spec.local.name } : t3.isImportDefaultSpecifier(spec) ? { kind: "default" } : t3.isImportSpecifier(spec) ? { kind: "named", imported: t3.isIdentifier(spec.imported) ? spec.imported.name : spec.imported.value } : void 0 : void 0;
17185
- } catch {
17186
- return;
17169
+ this.ensureFiles(allFiles), this.ensureFresh(allFiles);
17170
+ let program = this.ls.getProgram();
17171
+ if (!program)
17172
+ return;
17173
+ let checker = program.getTypeChecker(), serializationContextByComponentPath = /* @__PURE__ */ new Map();
17174
+ for (let entry of entries)
17175
+ try {
17176
+ let storySourceFile = program.getSourceFile(entry.storyPath), entryComponent = entry.component, componentPath = entryComponent?.path, exportName = entryComponent?.importName;
17177
+ if (!storySourceFile || !componentPath || !exportName || !entryComponent)
17178
+ continue;
17179
+ let importId = entryComponent.importId, isPackageImport = importId && !importId.startsWith("."), componentSourceFile;
17180
+ if (isPackageImport) {
17181
+ let resolved = this.typescript.resolveModuleName(
17182
+ importId,
17183
+ entry.storyPath,
17184
+ this.commandLine.options,
17185
+ this.typescript.sys
17186
+ );
17187
+ componentSourceFile = resolved.resolvedModule ? program.getSourceFile(resolved.resolvedModule.resolvedFileName) : program.getSourceFile(componentPath);
17188
+ } else
17189
+ componentSourceFile = program.getSourceFile(componentPath);
17190
+ if (!componentSourceFile)
17191
+ continue;
17192
+ let resolvedComponent;
17193
+ if (importId && (resolvedComponent = resolvePropsFromStoryFile(
17194
+ this.typescript,
17195
+ checker,
17196
+ storySourceFile,
17197
+ entryComponent
17198
+ )), resolvedComponent || (resolvedComponent = this.resolveFromMetaComponent(
17199
+ checker,
17200
+ storySourceFile,
17201
+ entryComponent
17202
+ )), resolvedComponent || (resolvedComponent = resolvePropsFromComponentExport(
17203
+ this.typescript,
17204
+ checker,
17205
+ componentSourceFile,
17206
+ entryComponent
17207
+ )), !resolvedComponent)
17208
+ continue;
17209
+ let serializationContext = serializationContextByComponentPath.get(componentPath);
17210
+ if (serializationContext === void 0) {
17211
+ let resolvedFileName = componentSourceFile.fileName;
17212
+ serializationContext = {
17213
+ sourceFile: componentSourceFile,
17214
+ defaultsSourcePath: resolvedFileName.endsWith(".d.ts") || resolvedFileName.endsWith(".d.mts") || resolvedFileName.endsWith(".d.cts") ? componentPath : void 0
17215
+ }, serializationContextByComponentPath.set(componentPath, serializationContext);
17187
17216
  }
17188
- })();
17189
- if (overrideSpec) {
17190
- if (overrideSpec.kind === "namespace") {
17191
- let ns = t3.identifier(overrideSpec.local);
17192
- addUniqueBy(b.namespaces, ns, (n) => n.name === ns.name);
17193
- continue;
17194
- }
17195
- if (!c.localImportName)
17196
- continue;
17197
- if (overrideSpec.kind === "default") {
17198
- let id = t3.identifier(c.localImportName);
17199
- addUniqueBy(b.defaults, id, (d) => d.name === id.name);
17217
+ let doc = serializeComponentDoc(this.typescript, checker, {
17218
+ sourceFile: serializationContext.sourceFile,
17219
+ resolvedComponent,
17220
+ defaultsSourcePath: serializationContext.defaultsSourcePath
17221
+ });
17222
+ doc && (entryComponent.reactComponentMeta = doc, entryComponent.componentJsDocTags = doc.jsDocTags, entryComponent.importOverride = entryComponent.componentJsDocTags?.import?.[0]?.trim());
17223
+ } catch {
17200
17224
  continue;
17201
17225
  }
17202
- if (overrideSpec.kind === "named") {
17203
- let local = t3.identifier(c.localImportName), imported = t3.identifier(overrideSpec.imported);
17204
- addUniqueBy(
17205
- b.named,
17206
- t3.importSpecifier(local, imported),
17207
- (n) => n.local.name === local.name && importedName(n.imported) === imported.name
17208
- );
17226
+ }
17227
+ /**
17228
+ * Check mtime for specific files and bump projectVersion if any changed.
17229
+ *
17230
+ * This bypasses the sync() gate in createLanguageServiceHost — sync() only runs when
17231
+ * projectVersion changes, so mtime-based cache alone can't detect stale files. We do a targeted
17232
+ * mtime check for the files we're about to extract from, ensuring freshness even when the
17233
+ * fs.watch event hasn't arrived yet (race with HMR) or was missed entirely.
17234
+ */
17235
+ ensureFresh(fileNames) {
17236
+ let stale = !1;
17237
+ for (let fileName of fileNames) {
17238
+ let cache = this.fsFileSnapshots.get(fileName);
17239
+ if (!cache)
17209
17240
  continue;
17210
- }
17241
+ let currentMtime = this.typescript.sys.getModifiedTime?.(fileName)?.valueOf();
17242
+ cache[0] !== currentMtime && (this.fsFileSnapshots.delete(fileName), stale = !0);
17211
17243
  }
17212
- if (c.namespace) {
17213
- if (rewritten) {
17214
- if (!c.importName)
17215
- continue;
17216
- let member = c.importName, id = t3.identifier(member);
17217
- addUniqueBy(
17218
- b.named,
17219
- t3.importSpecifier(id, id),
17220
- (n) => n.local.name === member && importedName(n.imported) === member
17221
- );
17222
- } else {
17223
- let ns = t3.identifier(c.namespace);
17224
- addUniqueBy(b.namespaces, ns, (n) => n.name === ns.name);
17225
- }
17226
- continue;
17244
+ stale && this.projectVersion++;
17245
+ }
17246
+ // ---------------------------------------------------------------------------
17247
+ // Internal helpers
17248
+ // ---------------------------------------------------------------------------
17249
+ /**
17250
+ * Path 2 fallback: resolve the component type from the story file's `meta.component` property.
17251
+ * Only works when the user explicitly set `component:` in the meta — no node means no
17252
+ * extraction.
17253
+ */
17254
+ resolveFromMetaComponent(checker, storySourceFile, componentRef) {
17255
+ let { member: memberAccess } = componentRef, moduleSymbol = checker.getSymbolAtLocation(storySourceFile);
17256
+ if (!moduleSymbol)
17257
+ return;
17258
+ let defaultExport = checker.getExportsOfModule(moduleSymbol).find((e) => e.getName() === "default");
17259
+ if (!defaultExport)
17260
+ return;
17261
+ let componentProp = checker.getTypeOfSymbol(defaultExport).getProperty("component");
17262
+ if (!componentProp?.valueDeclaration || !this.typescript.isPropertyAssignment(componentProp.valueDeclaration))
17263
+ return;
17264
+ let metaComponentInitializer = componentProp.valueDeclaration.initializer;
17265
+ if (!metaComponentInitializer || !metaComponentMatchesRef(
17266
+ this.typescript,
17267
+ checker,
17268
+ storySourceFile,
17269
+ componentRef,
17270
+ metaComponentInitializer
17271
+ ))
17272
+ return;
17273
+ let componentType = checker.getTypeOfSymbol(componentProp), selectedSymbol = componentProp.valueDeclaration && this.typescript.isPropertyAssignment(componentProp.valueDeclaration) ? checker.getSymbolAtLocation(componentProp.valueDeclaration.initializer) : componentType.getSymbol?.();
17274
+ if (memberAccess) {
17275
+ let prop = componentType.getProperty(memberAccess);
17276
+ if (prop)
17277
+ componentType = checker.getTypeOfSymbol(prop), selectedSymbol = prop;
17278
+ else
17279
+ return;
17227
17280
  }
17228
- if (c.importName === "default") {
17229
- if (!c.localImportName)
17230
- continue;
17231
- if (rewritten) {
17232
- let id = t3.identifier(c.localImportName);
17233
- addUniqueBy(
17234
- b.named,
17235
- t3.importSpecifier(id, id),
17236
- (n) => n.local.name === id.name && importedName(n.imported) === id.name
17237
- );
17238
- } else {
17239
- let id = t3.identifier(c.localImportName);
17240
- addUniqueBy(b.defaults, id, (d) => d.name === id.name);
17281
+ let propsType = resolvePropsFromComponentType(this.typescript, checker, componentType);
17282
+ if (!(!propsType || !selectedSymbol))
17283
+ return {
17284
+ componentRef,
17285
+ propsType,
17286
+ symbol: selectedSymbol
17287
+ };
17288
+ }
17289
+ };
17290
+ function arrayItemsEqual(a, b) {
17291
+ if (a.length !== b.length)
17292
+ return !1;
17293
+ let set = new Set(a);
17294
+ for (let file of b)
17295
+ if (!set.has(file))
17296
+ return !1;
17297
+ return !0;
17298
+ }
17299
+
17300
+ // src/componentManifest/componentMeta/ComponentMetaManager.ts
17301
+ var rootTsConfigNames = ["tsconfig.json", "jsconfig.json"], DEFAULT_INFERRED_OPTIONS = {
17302
+ strict: !0,
17303
+ esModuleInterop: !0,
17304
+ allowJs: !0,
17305
+ skipLibCheck: !0
17306
+ }, ComponentMetaManager = class {
17307
+ constructor(typescript) {
17308
+ this.typescript = typescript;
17309
+ // Adapted from:
17310
+ // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L34-L37
17311
+ this.configProjects = /* @__PURE__ */ new Map();
17312
+ this.rootTsConfigs = /* @__PURE__ */ new Set();
17313
+ this.searchedDirs = /* @__PURE__ */ new Set();
17314
+ // Our own file watching layer
17315
+ this.watching = !1;
17316
+ this.watchersByDir = /* @__PURE__ */ new Map();
17317
+ this.pendingEvents = /* @__PURE__ */ new Map();
17318
+ // Adapted from:
17319
+ // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/kit/lib/createChecker.ts#L83
17320
+ this.fsFileSnapshots = /* @__PURE__ */ new Map();
17321
+ }
17322
+ // ---------------------------------------------------------------------------
17323
+ // Adapted from:
17324
+ // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L70-L79
17325
+ // ---------------------------------------------------------------------------
17326
+ getProjectForFile(fileName) {
17327
+ let tsconfig = this.findMatchTSConfig(fileName);
17328
+ return tsconfig ? this.getOrCreateConfiguredProject(tsconfig) ?? this.getOrCreateInferredProject(fileName) : this.getOrCreateInferredProject(fileName);
17329
+ }
17330
+ /**
17331
+ * Batch-extract component props across all entries, grouping by tsconfig project so each project
17332
+ * builds its TS program only once.
17333
+ */
17334
+ batchExtract(entries) {
17335
+ let extractableEntries = entries.filter(
17336
+ (storyRef) => storyRef.component?.path && storyRef.component.importName
17337
+ ), byProject = groupByToMap(
17338
+ extractableEntries,
17339
+ (storyRef) => this.getProjectForFile(storyRef.storyPath)
17340
+ );
17341
+ for (let [project, projectEntries] of byProject)
17342
+ try {
17343
+ project.extractPropsFromStories(projectEntries);
17344
+ } catch (err) {
17345
+ logger7.debug(`[reactComponentMeta] Batch extraction failed: ${err}`);
17346
+ }
17347
+ }
17348
+ // ---------------------------------------------------------------------------
17349
+ // Adapted from:
17350
+ // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L101-L234
17351
+ // ---------------------------------------------------------------------------
17352
+ findMatchTSConfig(filePath) {
17353
+ let fileName = filePath.replace(/\\/g, "/"), dir = path3.dirname(fileName);
17354
+ for (; !this.searchedDirs.has(dir); ) {
17355
+ this.searchedDirs.add(dir);
17356
+ for (let tsConfigName of rootTsConfigNames) {
17357
+ let tsconfigPath = path3.join(dir, tsConfigName).replace(/\\/g, "/");
17358
+ this.typescript.sys.fileExists(tsconfigPath) && this.rootTsConfigs.add(tsconfigPath);
17241
17359
  }
17242
- continue;
17243
- }
17244
- if (c.importName) {
17245
- if (!c.localImportName)
17246
- continue;
17247
- let local = t3.identifier(c.localImportName), imported = t3.identifier(c.importName);
17248
- addUniqueBy(
17249
- b.named,
17250
- t3.importSpecifier(local, imported),
17251
- (n) => n.local.name === local.name && importedName(n.imported) === imported.name
17252
- );
17253
- continue;
17360
+ let parent = path3.dirname(dir);
17361
+ if (parent === dir)
17362
+ break;
17363
+ dir = parent;
17254
17364
  }
17255
- }
17256
- let merged = [], printDecl = (specs, src) => {
17257
- let node = t3.importDeclaration(specs, src), code = recast.print(node, {}).code;
17258
- merged.push(code);
17259
- }, sortedBuckets = Array.from(buckets.values()).sort((a, b) => a.order - b.order);
17260
- for (let bucket of sortedBuckets) {
17261
- let { source, defaults, namespaces, named } = bucket;
17262
- if (!(defaults.length === 0 && namespaces.length === 0 && named.length === 0))
17263
- if (namespaces.length > 0) {
17264
- let firstSpecs = [];
17265
- defaults[0] && firstSpecs.push(t3.importDefaultSpecifier(defaults[0])), firstSpecs.push(t3.importNamespaceSpecifier(namespaces[0])), printDecl(firstSpecs, source), named.length > 0 && printDecl(named, source);
17266
- for (let d of defaults.slice(1))
17267
- printDecl([t3.importDefaultSpecifier(d)], source);
17268
- for (let ns of namespaces.slice(1))
17269
- printDecl([t3.importNamespaceSpecifier(ns)], source);
17270
- } else {
17271
- if (defaults.length > 0 || named.length > 0) {
17272
- let specs = [];
17273
- defaults[0] && specs.push(t3.importDefaultSpecifier(defaults[0])), specs.push(...named), printDecl(specs, source);
17365
+ if (this.rootTsConfigs.size === 0)
17366
+ return null;
17367
+ let prepareClosestRootCommandLine = () => {
17368
+ let matches = [];
17369
+ for (let rootTsConfig of this.rootTsConfigs)
17370
+ isFileInDir(fileName, path3.dirname(rootTsConfig)) && matches.push(rootTsConfig);
17371
+ matches = matches.sort((a, b) => sortTSConfigs(fileName, a, b)), matches.length && getCommandLine(matches[0]);
17372
+ }, findIndirectReferenceTsconfig = () => findTSConfig((tsconfig) => !!this.configProjects.get(tsconfig)?.hasSourceFile(fileName)), findDirectIncludeTsconfig = () => findTSConfig((tsconfig) => {
17373
+ let commandLine = getCommandLine(tsconfig);
17374
+ return new Set(commandLine?.fileNames ?? []).has(fileName);
17375
+ }), findTSConfig = (match) => {
17376
+ let checked = /* @__PURE__ */ new Set();
17377
+ for (let rootTsConfig of [...this.rootTsConfigs].sort(
17378
+ (a, b) => sortTSConfigs(fileName, a, b)
17379
+ )) {
17380
+ let project = this.configProjects.get(rootTsConfig);
17381
+ if (project) {
17382
+ let chains = getReferencesChains(project.getCommandLine(), rootTsConfig, []);
17383
+ chains = chains.reverse();
17384
+ for (let chain of chains)
17385
+ for (let i = chain.length - 1; i >= 0; i--) {
17386
+ let tsconfig = chain[i];
17387
+ if (!checked.has(tsconfig) && (checked.add(tsconfig), match(tsconfig)))
17388
+ return tsconfig;
17389
+ }
17274
17390
  }
17275
- for (let d of defaults.slice(1))
17276
- printDecl([t3.importDefaultSpecifier(d)], source);
17277
17391
  }
17392
+ return null;
17393
+ }, getReferencesChains = (commandLine, tsConfig, before) => {
17394
+ if (commandLine.projectReferences?.length) {
17395
+ let newChains = [];
17396
+ for (let projectReference of commandLine.projectReferences) {
17397
+ let tsConfigPath = projectReference.path.replace(/\\/g, "/");
17398
+ if (this.typescript.sys.directoryExists(tsConfigPath)) {
17399
+ let newTsConfigPath = path3.join(tsConfigPath, "tsconfig.json"), newJsConfigPath = path3.join(tsConfigPath, "jsconfig.json");
17400
+ this.typescript.sys.fileExists(newTsConfigPath) ? tsConfigPath = newTsConfigPath : this.typescript.sys.fileExists(newJsConfigPath) && (tsConfigPath = newJsConfigPath);
17401
+ }
17402
+ let beforeIndex = before.indexOf(tsConfigPath);
17403
+ if (beforeIndex >= 0)
17404
+ newChains.push(before.slice(0, Math.max(beforeIndex, 1)));
17405
+ else {
17406
+ let referenceCommandLine = getCommandLine(tsConfigPath);
17407
+ if (referenceCommandLine)
17408
+ for (let chain of getReferencesChains(referenceCommandLine, tsConfigPath, [
17409
+ ...before,
17410
+ tsConfig
17411
+ ]))
17412
+ newChains.push(chain);
17413
+ }
17414
+ }
17415
+ return newChains;
17416
+ } else
17417
+ return [[...before, tsConfig]];
17418
+ }, getCommandLine = (tsConfig) => this.getOrCreateConfiguredProject(tsConfig)?.getCommandLine();
17419
+ return prepareClosestRootCommandLine(), findDirectIncludeTsconfig() ?? findIndirectReferenceTsconfig();
17278
17420
  }
17279
- return merged;
17280
- };
17281
-
17282
- // src/componentManifest/subcomponents.ts
17283
- import { types as t4 } from "storybook/internal/babel";
17284
- function findExactComponentMatch(components, componentName) {
17285
- if (componentName)
17286
- return components.find((component) => component.componentName === componentName);
17287
- }
17288
- function extractDeclaredSubcomponents(csf) {
17289
- let rawSubcomponents = unwrapSubcomponentNode(
17290
- csf._metaAnnotations.subcomponents,
17291
- csf._ast.program
17292
- );
17293
- return !rawSubcomponents || !t4.isObjectExpression(rawSubcomponents) ? [] : rawSubcomponents.properties.flatMap((property) => {
17294
- if (!t4.isObjectProperty(property))
17295
- return [];
17296
- let name = getObjectKeyName(property.key), directComponentName = getComponentExpressionName(property.value), componentExpression = unwrapSubcomponentNode(property.value, csf._ast.program), componentName = getComponentExpressionName(componentExpression) ?? directComponentName;
17297
- return name && componentName ? [{ name, componentName }] : [];
17298
- });
17299
- }
17300
- function findVariableInitialization(identifier, program) {
17301
- for (let node of program.body) {
17302
- let declaration = (t4.isVariableDeclaration(node) ? node.declarations : t4.isExportNamedDeclaration(node) && t4.isVariableDeclaration(node.declaration) ? node.declaration.declarations : void 0)?.find(
17303
- (decl) => t4.isVariableDeclarator(decl) && t4.isIdentifier(decl.id) && decl.id.name === identifier
17421
+ // ---------------------------------------------------------------------------
17422
+ // Adapted from:
17423
+ // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L236-L256
17424
+ // ---------------------------------------------------------------------------
17425
+ getOrCreateConfiguredProject(tsconfig) {
17426
+ tsconfig = tsconfig.replace(/\\/g, "/");
17427
+ let project = this.configProjects.get(tsconfig);
17428
+ if (!project)
17429
+ try {
17430
+ let getCommandLine = () => this.parseConfigWorker(tsconfig);
17431
+ project = new ComponentMetaProject(
17432
+ this.typescript,
17433
+ getCommandLine(),
17434
+ tsconfig,
17435
+ this.fsFileSnapshots,
17436
+ getCommandLine
17437
+ ), this.configProjects.set(tsconfig, project), this.watching && (this.watchDirectory(path3.dirname(tsconfig)), this.watchProgramSourceDirs(project));
17438
+ } catch (err) {
17439
+ return logger7.debug(`[reactComponentMeta] Failed to parse tsconfig ${tsconfig}: ${err}`), null;
17440
+ }
17441
+ return project;
17442
+ }
17443
+ // ---------------------------------------------------------------------------
17444
+ // Adapted from:
17445
+ // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L258-L284
17446
+ // ---------------------------------------------------------------------------
17447
+ getOrCreateInferredProject(fileName) {
17448
+ return this.inferredProject || (this.inferredProject = new ComponentMetaProject(
17449
+ this.typescript,
17450
+ {
17451
+ options: {
17452
+ ...DEFAULT_INFERRED_OPTIONS,
17453
+ target: this.typescript.ScriptTarget.Latest,
17454
+ module: this.typescript.ModuleKind.ESNext,
17455
+ moduleResolution: this.typescript.ModuleResolutionKind.Bundler,
17456
+ jsx: this.typescript.JsxEmit.ReactJSX
17457
+ },
17458
+ fileNames: [],
17459
+ errors: []
17460
+ },
17461
+ void 0,
17462
+ this.fsFileSnapshots
17463
+ )), this.inferredProject.ensureFiles([fileName]), this.inferredProject;
17464
+ }
17465
+ // ---------------------------------------------------------------------------
17466
+ // Adapted from:
17467
+ // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProjectLs.ts#L262-L353
17468
+ // ---------------------------------------------------------------------------
17469
+ parseConfigWorker(tsconfig) {
17470
+ let config = this.typescript.readJsonConfigFile(tsconfig, this.typescript.sys.readFile), content = this.typescript.parseJsonSourceFileConfigFileContent(
17471
+ config,
17472
+ this.typescript.sys,
17473
+ path3.dirname(tsconfig),
17474
+ {},
17475
+ tsconfig
17304
17476
  );
17305
- if (declaration?.init && t4.isExpression(declaration.init))
17306
- return declaration.init;
17477
+ return content.options.outDir = void 0, content.fileNames = content.fileNames.map((fileName) => fileName.replace(/\\/g, "/")), content;
17307
17478
  }
17308
- }
17309
- function unwrapSubcomponentNode(node, program, visitedIdentifiers = /* @__PURE__ */ new Set()) {
17310
- let current2 = node;
17311
- for (; current2; ) {
17312
- if (t4.isIdentifier(current2)) {
17313
- if (visitedIdentifiers.has(current2.name))
17314
- return;
17315
- visitedIdentifiers.add(current2.name), current2 = findVariableInitialization(current2.name, program);
17316
- continue;
17479
+ // ---------------------------------------------------------------------------
17480
+ // File events
17481
+ // ---------------------------------------------------------------------------
17482
+ /**
17483
+ * Broadcast file changes to all projects. Each project selectively bumps projectVersion.
17484
+ *
17485
+ * Adapted from:
17486
+ * https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/kit/lib/createChecker.ts#L409-L432
17487
+ */
17488
+ onFilesChanged(changes) {
17489
+ for (let project of this.configProjects.values())
17490
+ project.onFilesChanged(changes);
17491
+ this.inferredProject?.onFilesChanged(changes);
17492
+ }
17493
+ /**
17494
+ * Adapted from:
17495
+ * https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L43-L68
17496
+ */
17497
+ onConfigChanged(configPath, type) {
17498
+ if (configPath = configPath.replace(/\\/g, "/"), type === "created")
17499
+ this.rootTsConfigs.add(configPath);
17500
+ else if ((type === "changed" || type === "deleted") && this.configProjects.has(configPath)) {
17501
+ type === "deleted" && this.rootTsConfigs.delete(configPath);
17502
+ let project = this.configProjects.get(configPath);
17503
+ this.configProjects.delete(configPath), project?.dispose();
17317
17504
  }
17318
- if (t4.isParenthesizedExpression(current2) || t4.isTSAsExpression(current2) || t4.isTSSatisfiesExpression(current2) || t4.isTSNonNullExpression(current2)) {
17319
- current2 = current2.expression;
17320
- continue;
17505
+ this.searchedDirs.clear();
17506
+ }
17507
+ // ---------------------------------------------------------------------------
17508
+ // Our own file watching layer (no Volar equivalent — we're standalone)
17509
+ // ---------------------------------------------------------------------------
17510
+ startWatching() {
17511
+ if (!this.watching) {
17512
+ this.watching = !0;
17513
+ for (let tsconfig of this.configProjects.keys())
17514
+ this.watchDirectory(path3.dirname(tsconfig));
17515
+ this.watchProgramSourceDirs();
17321
17516
  }
17322
- return current2;
17323
17517
  }
17324
- }
17325
- function getObjectKeyName(key) {
17326
- if (t4.isIdentifier(key))
17327
- return key.name;
17328
- if (t4.isStringLiteral(key))
17329
- return key.value;
17330
- }
17331
- function getComponentExpressionName(node) {
17332
- if (node) {
17333
- if (t4.isIdentifier(node))
17334
- return node.name;
17335
- if (t4.isMemberExpression(node) && !node.computed) {
17336
- let objectName = getComponentExpressionName(node.object), propertyName = getComponentExpressionName(node.property);
17337
- return objectName && propertyName ? `${objectName}.${propertyName}` : void 0;
17518
+ /**
17519
+ * Watch directories that contain source files from all TS programs. This covers monorepo setups
17520
+ * where stories import components via path aliases (e.g. apps/storybook/ imports from
17521
+ * packages/ui/ via tsconfig paths).
17522
+ */
17523
+ watchProgramSourceDirs(singleProject) {
17524
+ let dirs = /* @__PURE__ */ new Set();
17525
+ if (singleProject)
17526
+ for (let filePath of singleProject.getSourceFilePaths())
17527
+ dirs.add(path3.dirname(filePath));
17528
+ else {
17529
+ for (let project of this.configProjects.values())
17530
+ for (let filePath of project.getSourceFilePaths())
17531
+ dirs.add(path3.dirname(filePath));
17532
+ if (this.inferredProject)
17533
+ for (let filePath of this.inferredProject.getSourceFilePaths())
17534
+ dirs.add(path3.dirname(filePath));
17535
+ }
17536
+ let roots = /* @__PURE__ */ new Set();
17537
+ for (let dir of dirs) {
17538
+ let candidate = dir;
17539
+ for (; candidate !== path3.dirname(candidate); ) {
17540
+ let normalized = candidate.replace(/\\/g, "/"), alreadyWatched = !1;
17541
+ for (let watched of this.watchersByDir.keys())
17542
+ if (normalized === watched || normalized.startsWith(watched + "/")) {
17543
+ alreadyWatched = !0;
17544
+ break;
17545
+ }
17546
+ if (alreadyWatched)
17547
+ break;
17548
+ if (this.typescript.sys.fileExists(path3.join(candidate, "package.json")) || this.typescript.sys.fileExists(path3.join(candidate, "tsconfig.json"))) {
17549
+ roots.add(candidate);
17550
+ break;
17551
+ }
17552
+ candidate = path3.dirname(candidate);
17553
+ }
17338
17554
  }
17555
+ for (let root of roots)
17556
+ this.watchDirectory(root);
17339
17557
  }
17340
- }
17341
-
17342
- // src/componentManifest/generator.ts
17343
- var componentMetaManager;
17344
- async function createComponentMetaManager(watch2) {
17345
- if (componentMetaManager && watch2)
17346
- return componentMetaManager;
17347
- try {
17348
- let ts = await import("typescript"), manager = new ComponentMetaManager(ts);
17349
- return watch2 && (componentMetaManager = manager), manager;
17350
- } catch {
17351
- logger8.debug(
17352
- "[reactComponentMeta] TypeScript not available, skipping component meta extraction"
17353
- );
17354
- }
17355
- }
17356
- function isAttachedDocsEntry(entry) {
17357
- return entry.type === "docs" && entry.tags?.includes(Tag.ATTACHED_MDX) === !0 && entry.storiesImports.length > 0;
17358
- }
17359
- function selectComponentEntries(manifestEntries) {
17360
- let entriesByComponentId = /* @__PURE__ */ new Map();
17361
- return manifestEntries.filter(
17362
- (entry) => entry.type === "story" && entry.subtype === "story" || // Attached docs entries are the only docs entries that can contribute to a
17363
- // component manifest, because they point back to a story file through storiesImports.
17364
- isAttachedDocsEntry(entry)
17365
- ).forEach((entry) => {
17366
- let componentId = entry.id.split("--")[0], existingEntry = entriesByComponentId.get(componentId);
17367
- if (!existingEntry) {
17368
- entriesByComponentId.set(componentId, entry);
17558
+ watchDirectory(dir) {
17559
+ if (!this.watching)
17369
17560
  return;
17561
+ let normalized = dir.replace(/\\/g, "/");
17562
+ for (let watched of this.watchersByDir.keys())
17563
+ if (normalized === watched || normalized.startsWith(watched + "/"))
17564
+ return;
17565
+ for (let [watched, watcher] of this.watchersByDir)
17566
+ watched.startsWith(normalized + "/") && (watcher.close(), this.watchersByDir.delete(watched));
17567
+ try {
17568
+ let watcher = watch(dir, { recursive: !0 }, (eventType, filename) => {
17569
+ if (!filename)
17570
+ return;
17571
+ let filePath = path3.resolve(dir, filename).replace(/\\/g, "/");
17572
+ if (filePath.includes("/node_modules/") || filePath.includes("/.git/"))
17573
+ return;
17574
+ let existing = this.pendingEvents.get(filePath);
17575
+ existing && clearTimeout(existing), this.pendingEvents.set(
17576
+ filePath,
17577
+ setTimeout(() => {
17578
+ this.pendingEvents.delete(filePath), eventType === "rename" ? existsSync3(filePath) ? this.handleFileEvent(filePath, "created") : this.handleFileEvent(filePath, "deleted") : this.handleFileEvent(filePath, "changed");
17579
+ }, 50)
17580
+ );
17581
+ });
17582
+ watcher.unref(), this.watchersByDir.set(normalized, watcher);
17583
+ } catch (err) {
17584
+ logger7.debug(`[reactComponentMeta] Failed to watch directory ${normalized}: ${err}`);
17370
17585
  }
17371
- existingEntry.type === "docs" && entry.type === "story" && entriesByComponentId.set(componentId, entry);
17372
- }), [...entriesByComponentId.values()];
17373
- }
17374
- function findMatchingComponent(components, componentName, title) {
17375
- let exactMatch = findExactComponentMatch(components, componentName);
17376
- if (exactMatch)
17377
- return exactMatch;
17378
- let trimmedTitle = title.replace(/\s+/g, ""), matches = components.filter(
17379
- (it) => trimmedTitle.includes(it.componentName) || it.localImportName && trimmedTitle.includes(it.localImportName) || it.importName && trimmedTitle.includes(it.importName)
17380
- );
17381
- if (matches.length <= 1)
17382
- return matches[0];
17383
- let best = matches[0];
17384
- for (let cur of matches) {
17385
- if (cur.jsxDepth === 0)
17386
- return cur;
17387
- (cur.jsxDepth ?? 1 / 0) < (best.jsxDepth ?? 1 / 0) && (best = cur);
17388
17586
  }
17389
- return best;
17390
- }
17391
- function getPackageInfo(componentPath, fallbackPath) {
17392
- let nearestPkg = cachedFindUp("package.json", {
17393
- cwd: path.dirname(componentPath ?? fallbackPath)
17394
- });
17395
- try {
17396
- if (!nearestPkg)
17587
+ stopWatching() {
17588
+ for (let timeout of this.pendingEvents.values())
17589
+ clearTimeout(timeout);
17590
+ this.pendingEvents.clear();
17591
+ for (let watcher of this.watchersByDir.values())
17592
+ watcher.close();
17593
+ this.watchersByDir.clear(), this.watching = !1;
17594
+ }
17595
+ /**
17596
+ * Map raw fs.watch events to LSP-style FileChangeType before broadcasting.
17597
+ *
17598
+ * Fs.watch reports atomic saves (sed -i, editors) as `rename` → we classify as `created` (file
17599
+ * exists after rename). But an IDE/LSP would report an atomic save of an _existing_ file as
17600
+ * `Changed`, not `Created`.
17601
+ *
17602
+ * We reclassify here so that onFilesChanged stays 1:1 with Volar Kit.
17603
+ */
17604
+ handleFileEvent(filePath, type) {
17605
+ if (type === "created") {
17606
+ for (let project of this.configProjects.values())
17607
+ if (project.hasSourceFile(filePath)) {
17608
+ type = "changed";
17609
+ break;
17610
+ }
17611
+ type === "created" && this.inferredProject?.hasSourceFile(filePath) && (type = "changed");
17612
+ }
17613
+ let basename3 = path3.basename(filePath);
17614
+ if (rootTsConfigNames.includes(basename3)) {
17615
+ this.onConfigChanged(filePath, type);
17397
17616
  return;
17398
- let parsed = JSON.parse(cachedReadTextFileSync(nearestPkg));
17399
- return typeof parsed == "object" && parsed && "name" in parsed && typeof parsed.name == "string" ? parsed.name : void 0;
17400
- } catch {
17401
- return;
17617
+ }
17618
+ this.onFilesChanged([{ filePath, type }]);
17402
17619
  }
17620
+ dispose() {
17621
+ this.stopWatching();
17622
+ for (let project of this.configProjects.values())
17623
+ project.dispose();
17624
+ this.inferredProject?.dispose(), this.configProjects.clear(), this.inferredProject = void 0, this.fsFileSnapshots.clear(), this.searchedDirs.clear(), this.rootTsConfigs.clear();
17625
+ }
17626
+ };
17627
+ function sortTSConfigs(file, a, b) {
17628
+ let inA = isFileInDir(file, path3.dirname(a)), inB = isFileInDir(file, path3.dirname(b));
17629
+ if (inA !== inB)
17630
+ return (inB ? 1 : 0) - (inA ? 1 : 0);
17631
+ let aLength = a.split("/").length, bLength = b.split("/").length;
17632
+ if (aLength === bLength) {
17633
+ let aWeight = path3.basename(a) === "tsconfig.json" ? 1 : 0;
17634
+ return (path3.basename(b) === "tsconfig.json" ? 1 : 0) - aWeight;
17635
+ }
17636
+ return bLength - aLength;
17403
17637
  }
17404
- function getFallbackImport(packageName, componentName) {
17405
- let exportName = componentName?.split(".").at(-1);
17406
- return packageName && exportName ? `import { ${exportName} } from "${packageName}";` : "";
17407
- }
17408
- function getComponentDocgenData(component, docgenEngine) {
17409
- let reactDocgen, reactDocgenTypescript, reactComponentMeta, docgenDescription, docgenJsDocTags, docgenError;
17410
- if (docgenEngine === "react-docgen") {
17411
- let result = component?.reactDocgen;
17412
- reactDocgen = result?.type === "success" ? result.data : void 0, docgenDescription = reactDocgen?.description, docgenError = result?.type === "error" ? result.error : void 0;
17413
- } else docgenEngine === "react-docgen-typescript" ? (reactDocgenTypescript = component?.reactDocgenTypescript, docgenDescription = reactDocgenTypescript?.description, docgenError = component?.reactDocgenTypescriptError) : (reactComponentMeta = component?.reactComponentMeta, docgenDescription = reactComponentMeta?.description, docgenJsDocTags = component?.componentJsDocTags);
17414
- return {
17415
- docgenDescription,
17416
- docgenError,
17417
- docgenJsDocTags,
17418
- reactComponentMeta,
17419
- reactDocgen,
17420
- reactDocgenTypescript
17421
- };
17422
- }
17423
- function createSubcomponentManifest({
17424
- component,
17425
- declaredName,
17426
- docgenEngine,
17427
- packageName,
17428
- storyFilePath
17429
- }) {
17430
- let imports = getImports({ components: component ? [component] : [], packageName }).join(`
17431
- `).trim() || getFallbackImport(packageName, component?.componentName), {
17432
- reactDocgen,
17433
- reactDocgenTypescript,
17434
- reactComponentMeta,
17435
- docgenDescription,
17436
- docgenJsDocTags,
17437
- docgenError
17438
- } = getComponentDocgenData(component, docgenEngine), { description, summary, jsDocTags } = extractComponentDescription(
17439
- void 0,
17440
- docgenDescription,
17441
- docgenJsDocTags
17442
- );
17443
- return {
17444
- name: declaredName,
17445
- path: component?.path ?? storyFilePath,
17446
- description,
17447
- summary,
17448
- import: imports || void 0,
17449
- jsDocTags,
17450
- reactDocgen,
17451
- reactDocgenTypescript,
17452
- reactComponentMeta,
17453
- error: docgenError ?? (component ? void 0 : {
17454
- name: "No component import found",
17455
- message: `No component file found for the "${declaredName}" subcomponent.`
17456
- })
17457
- };
17638
+ function isFileInDir(fileName, dir) {
17639
+ let relative3 = path3.relative(dir, fileName);
17640
+ return !!relative3 && !relative3.startsWith("..") && !path3.isAbsolute(relative3);
17458
17641
  }
17459
- function extractStories(csf, componentName, manifestEntries) {
17460
- let manifestEntryIds = new Set(manifestEntries.map((entry) => entry.id));
17461
- return Object.entries(csf._stories).filter(
17462
- ([, story]) => (
17463
- // Only include stories that are in the list of entries already filtered for the 'manifest' tag
17464
- manifestEntryIds.has(story.id)
17465
- )
17466
- ).map(([storyExport, story]) => {
17642
+
17643
+ // src/componentManifest/componentMetaManagerSingleton.ts
17644
+ var componentMetaManagerPromise;
17645
+ function getSharedComponentMetaManager() {
17646
+ return componentMetaManagerPromise || (componentMetaManagerPromise = (async () => {
17467
17647
  try {
17468
- let jsdocComment = extractDescription(csf._storyStatements[storyExport]), { tags = {}, description } = jsdocComment ? extractJSDocInfo(jsdocComment) : {}, finalDescription = (tags?.describe?.[0] || tags?.desc?.[0]) ?? description;
17469
- return {
17470
- id: story.id,
17471
- name: story.name ?? storyNameFromExport(storyExport),
17472
- snippet: recast2.print(getCodeSnippet(csf, storyExport, componentName)).code,
17473
- description: finalDescription?.trim(),
17474
- summary: tags.summary?.[0]
17475
- };
17476
- } catch (e) {
17477
- return invariant(e instanceof Error), {
17478
- id: story.id,
17479
- name: story.name ?? storyNameFromExport(storyExport),
17480
- error: { name: e.name, message: e.message }
17481
- };
17648
+ let ts = await import("typescript");
17649
+ return new ComponentMetaManager(ts);
17650
+ } catch {
17651
+ logger8.debug(
17652
+ "[reactComponentMeta] TypeScript not available, skipping component meta extraction."
17653
+ );
17654
+ return;
17482
17655
  }
17483
- });
17484
- }
17485
- function extractComponentDescription(metaJsDoc, docgenDescription, docgenJsDocTags) {
17486
- let jsdocComment = metaJsDoc || docgenDescription, extracted = jsdocComment ? extractJSDocInfo(jsdocComment) : void 0, tags = docgenJsDocTags ?? extracted?.tags ?? {}, description = extracted?.description;
17487
- return {
17488
- description: ((tags?.describe?.[0] || tags?.desc?.[0]) ?? description)?.trim(),
17489
- summary: tags.summary?.[0],
17490
- jsDocTags: tags
17491
- };
17656
+ })()), componentMetaManagerPromise;
17492
17657
  }
17493
- var manifests = async (existingManifests = {}, options) => {
17494
- let { manifestEntries, presets, watch: watch2 } = options, typescriptOptions = await presets?.apply("typescript", {}) ?? {}, docgenEngine = (await presets?.apply("features", {}))?.experimentalReactComponentMeta ? "react-component-meta" : typescriptOptions.reactDocgen || "react-docgen";
17495
- invalidateCache(), invalidateParser();
17496
- let startTime = performance.now(), manager = docgenEngine === "react-component-meta" ? await createComponentMetaManager(watch2) : null;
17497
- try {
17498
- let entriesByUniqueComponent = selectComponentEntries(manifestEntries), resolvedEntries = await Promise.all(
17499
- entriesByUniqueComponent.map(async (entry) => {
17500
- let storyFilePath = entry.type === "story" ? entry.importPath : (
17501
- // For attached docs entries, storiesImports[0] points to the stories file being attached to
17502
- entry.storiesImports[0]
17503
- ), storyPath = path.join(process.cwd(), storyFilePath), storyFile = cachedReadTextFileSync(storyPath), csf = loadCsf(storyFile, {
17504
- makeTitle: () => entry.title
17505
- }).parse(), componentName = csf._meta?.component, declaredSubcomponents = extractDeclaredSubcomponents(csf), allComponents = await getComponents({
17506
- additionalComponentNames: declaredSubcomponents.map(
17507
- (subcomponent) => subcomponent.componentName
17508
- ),
17509
- csf,
17510
- storyFilePath: storyPath,
17511
- typescriptOptions,
17512
- docgenEngine
17513
- }), component = findMatchingComponent(allComponents, componentName, entry.title), subcomponents = declaredSubcomponents.map((declaredSubcomponent) => ({
17514
- component: findExactComponentMatch(allComponents, declaredSubcomponent.componentName),
17515
- name: declaredSubcomponent.name
17516
- }));
17517
- return {
17518
- storyPath,
17519
- component,
17520
- entry,
17521
- storyFilePath,
17522
- storyFile,
17523
- csf,
17524
- componentName,
17525
- allComponents,
17526
- subcomponents
17527
- };
17528
- })
17529
- );
17530
- docgenEngine === "react-component-meta" && manager && manager.batchExtract(
17531
- resolvedEntries.flatMap(({ storyPath, component, subcomponents }) => [
17532
- ...component ? [{ storyPath, component }] : [],
17533
- ...subcomponents.filter(
17534
- (subcomponent) => subcomponent.component !== void 0
17535
- ).map((subcomponent) => ({
17536
- storyPath,
17537
- component: subcomponent.component
17538
- }))
17539
- ])
17540
- );
17541
- let components = resolvedEntries.map(
17542
- ({
17543
- storyPath,
17544
- component,
17545
- entry,
17546
- storyFilePath,
17547
- storyFile,
17548
- csf,
17549
- componentName,
17550
- allComponents,
17551
- subcomponents
17552
- }) => {
17553
- let id = entry.id.split("--")[0], title = entry.title.split("/").at(-1).replace(/\s+/g, ""), packageName = getPackageInfo(component?.path, storyPath), fallbackImport = getFallbackImport(packageName, componentName), imports = getImports({ components: allComponents, packageName }).join(`
17554
- `).trim() || fallbackImport, stories = extractStories(csf, component?.componentName, manifestEntries), base2 = {
17555
- id,
17556
- name: componentName ?? title,
17557
- path: storyFilePath,
17558
- stories,
17559
- import: imports,
17560
- jsDocTags: {}
17561
- }, {
17562
- reactDocgen,
17563
- reactDocgenTypescript,
17564
- reactComponentMeta,
17565
- docgenDescription,
17566
- docgenJsDocTags,
17567
- docgenError
17568
- } = getComponentDocgenData(component, docgenEngine);
17569
- if (!reactDocgen && !reactDocgenTypescript && !reactComponentMeta) {
17570
- let error = csf._meta?.component ? {
17571
- name: "No component import found",
17572
- message: `No component file found for the "${csf.meta.component}" component.`
17573
- } : {
17574
- name: "No component found",
17575
- message: "We could not detect the component from your story file. Specify meta.component."
17576
- };
17577
- return {
17578
- ...base2,
17579
- error: docgenError ?? {
17580
- name: error.name,
17581
- message: (csf._metaStatementPath?.buildCodeFrameError(error.message).message ?? error.message) + `
17582
17658
 
17583
- ${entry.importPath}:
17584
- ${storyFile}`
17585
- }
17586
- };
17587
- }
17588
- let metaJsDoc = extractDescription(csf._metaStatement) || void 0, { description, summary, jsDocTags } = extractComponentDescription(
17589
- metaJsDoc,
17590
- docgenDescription,
17591
- docgenJsDocTags
17592
- ), subcomponentEntries = Object.fromEntries(
17593
- subcomponents.map((subcomponent) => [
17594
- subcomponent.name,
17595
- createSubcomponentManifest({
17596
- component: subcomponent.component,
17597
- declaredName: subcomponent.name,
17598
- docgenEngine,
17599
- packageName,
17600
- storyFilePath
17601
- })
17602
- ])
17603
- );
17604
- return {
17605
- ...base2,
17606
- description,
17607
- summary,
17608
- import: imports,
17609
- reactDocgen,
17610
- reactDocgenTypescript,
17611
- reactComponentMeta,
17612
- jsDocTags,
17613
- ...Object.keys(subcomponentEntries).length > 0 ? { subcomponents: subcomponentEntries } : {},
17614
- error: docgenError
17615
- };
17616
- }
17617
- ).filter((component) => component !== void 0);
17618
- manager && watch2 && manager.startWatching();
17619
- let durationMs = Math.round(performance.now() - startTime);
17659
+ // src/componentManifest/generator.ts
17660
+ var manifests = async (existingManifests = {}, options) => {
17661
+ let { manifestEntries, presets, watch: watch2 } = options, typescriptOptions = await presets?.apply("typescript", {}) ?? {}, features = await presets?.apply("features", {});
17662
+ if (features?.experimentalDocgenServer)
17620
17663
  return {
17621
17664
  ...existingManifests,
17622
17665
  components: {
17623
17666
  v: 0,
17624
- components: Object.fromEntries(components.map((component) => [component.id, component])),
17625
- meta: {
17626
- docgen: docgenEngine,
17627
- durationMs
17628
- }
17667
+ components: {},
17668
+ meta: { docgen: "react-component-meta", durationMs: 0 }
17629
17669
  }
17630
17670
  };
17631
- } finally {
17632
- manager && !watch2 && manager.dispose();
17633
- }
17671
+ let docgenEngine = features?.experimentalReactComponentMeta ? "react-component-meta" : typescriptOptions.reactDocgen || "react-docgen";
17672
+ invalidateCache(), invalidateParser();
17673
+ let startTime = performance.now(), manager = docgenEngine === "react-component-meta" ? await getSharedComponentMetaManager() : void 0, entriesByUniqueComponent = [
17674
+ ...selectComponentEntriesByComponentId(manifestEntries).values()
17675
+ ], resolvedEntries = await Promise.all(
17676
+ entriesByUniqueComponent.map(async (entry) => {
17677
+ let storyFilePath = getStoryImportPathFromEntry(entry);
17678
+ if (!storyFilePath)
17679
+ throw new Error(`No story file path for index entry ${entry.id}`);
17680
+ let storyPath = path.join(process.cwd(), storyFilePath), resolved = await resolveStoryFileComponents({
17681
+ storyPath,
17682
+ title: entry.title,
17683
+ typescriptOptions,
17684
+ docgenEngine
17685
+ });
17686
+ return { entry, storyFilePath, ...resolved };
17687
+ })
17688
+ );
17689
+ docgenEngine === "react-component-meta" && manager && manager.batchExtract(
17690
+ resolvedEntries.flatMap(({ storyPath, component, subcomponents }) => [
17691
+ ...component ? [{ storyPath, component }] : [],
17692
+ ...subcomponents.filter(
17693
+ (subcomponent) => subcomponent.component !== void 0
17694
+ ).map((subcomponent) => ({
17695
+ storyPath,
17696
+ component: subcomponent.component
17697
+ }))
17698
+ ])
17699
+ );
17700
+ let manifestEntryIds = new Set(manifestEntries.map((entry) => entry.id)), components = resolvedEntries.map(
17701
+ ({
17702
+ storyPath,
17703
+ component,
17704
+ entry,
17705
+ storyFilePath,
17706
+ storyFile,
17707
+ csf,
17708
+ componentName,
17709
+ allComponents,
17710
+ subcomponents
17711
+ }) => buildReactComponentDocgenFromResolved({
17712
+ entry,
17713
+ storyPath,
17714
+ storyFilePath,
17715
+ storyFile,
17716
+ csf,
17717
+ componentName,
17718
+ component,
17719
+ allComponents,
17720
+ subcomponents,
17721
+ docgenEngine,
17722
+ filterStoryIds: manifestEntryIds
17723
+ })
17724
+ ).filter((component) => component !== void 0);
17725
+ manager && watch2 && manager.startWatching();
17726
+ let durationMs = Math.round(performance.now() - startTime);
17727
+ return {
17728
+ ...existingManifests,
17729
+ components: {
17730
+ v: 0,
17731
+ components: Object.fromEntries(components.map((component) => [component.id, component])),
17732
+ meta: {
17733
+ docgen: docgenEngine,
17734
+ durationMs
17735
+ }
17736
+ }
17737
+ };
17634
17738
  };
17635
17739
 
17636
17740
  // src/enrichCsf.ts
@@ -17706,6 +17810,67 @@ var enrichCsf = async (input, options) => {
17706
17810
  };
17707
17811
  };
17708
17812
 
17813
+ // src/docgen/preset.ts
17814
+ import { STORY_FILE_TEST_REGEXP, getStoryImportPathFromEntry as getStoryImportPathFromEntry3 } from "storybook/internal/common";
17815
+
17816
+ // src/docgen/buildDocgen.ts
17817
+ import { getStoryImportPathFromEntry as getStoryImportPathFromEntry2 } from "storybook/internal/common";
17818
+ async function buildDocgenPayload(input, context) {
17819
+ let storyFilePath = getStoryImportPathFromEntry2(input.entry);
17820
+ if (!storyFilePath)
17821
+ return;
17822
+ let storyPath = (context.resolvePath ?? ((importPath) => path.join(process.cwd(), importPath)))(storyFilePath), resolved;
17823
+ try {
17824
+ resolved = await resolveStoryFileComponents({
17825
+ storyPath,
17826
+ title: input.entry.title,
17827
+ typescriptOptions: context.typescriptOptions,
17828
+ docgenEngine: "react-component-meta"
17829
+ });
17830
+ } catch {
17831
+ return;
17832
+ }
17833
+ let { csf, componentName, component, allComponents, subcomponents, storyFile } = resolved, usableSubcomponents = subcomponents.filter(
17834
+ (sub) => sub.component !== void 0
17835
+ ), storyRefs = [
17836
+ ...component ? [{ storyPath, component }] : [],
17837
+ ...usableSubcomponents.map((sub) => ({ storyPath, component: sub.component }))
17838
+ ];
17839
+ return storyRefs.length > 0 && context.componentMetaManager.batchExtract(storyRefs), buildReactComponentDocgenFromResolved({
17840
+ entry: input.entry,
17841
+ storyPath,
17842
+ storyFilePath,
17843
+ storyFile,
17844
+ csf,
17845
+ componentName,
17846
+ component,
17847
+ allComponents,
17848
+ subcomponents,
17849
+ docgenEngine: "react-component-meta"
17850
+ });
17851
+ }
17852
+
17853
+ // src/docgen/preset.ts
17854
+ var experimental_docgenProvider = async (nextDocgen, options) => {
17855
+ let typescriptOptionsPromise = options.presets?.apply(
17856
+ "typescript",
17857
+ {}
17858
+ ) ?? Promise.resolve({});
17859
+ return getSharedComponentMetaManager(), async (input) => {
17860
+ let storyImportPath = getStoryImportPathFromEntry3(input.entry);
17861
+ if (!storyImportPath || !STORY_FILE_TEST_REGEXP.test(storyImportPath))
17862
+ return nextDocgen(input);
17863
+ let componentMetaManager = await getSharedComponentMetaManager();
17864
+ if (!componentMetaManager)
17865
+ return nextDocgen(input);
17866
+ let ours = await buildDocgenPayload(input, {
17867
+ componentMetaManager,
17868
+ typescriptOptions: await typescriptOptionsPromise
17869
+ });
17870
+ return ours ? { ...await nextDocgen(input), ...ours } : nextDocgen(input);
17871
+ };
17872
+ };
17873
+
17709
17874
  // src/preset.ts
17710
17875
  var addons = [
17711
17876
  import.meta.resolve("@storybook/react-dom-shim/preset")
@@ -17759,6 +17924,7 @@ async function internal_getArgTypesData(_input, options) {
17759
17924
  var optimizeViteDeps = ["react-dom/test-utils"];
17760
17925
  export {
17761
17926
  addons,
17927
+ experimental_docgenProvider,
17762
17928
  enrichCsf as experimental_enrichCsf,
17763
17929
  manifests as experimental_manifests,
17764
17930
  internal_getArgTypesData,