UNPKG

@mui/internal-docs-infra

Version:

MUI Infra - internal documentation creation tools.

293 lines (275 loc) 13.1 kB
import * as React from 'react'; import enhanceCodeInline from "../pipeline/enhanceCodeInline/index.mjs"; import enhanceCodeTypes from "../pipeline/enhanceCodeTypes/index.mjs"; import { typeToJsx, additionalTypesToJsx } from "./typesToJsx.mjs"; import { jsx as _jsx } from "react/jsx-runtime"; /** * Default enhancers applied when no enhancers are specified. * Note: enhanceCodeTypes is added dynamically when anchorMap is available. */ const DEFAULT_ENHANCERS = [enhanceCodeInline]; /** * Default inline enhancers applied to shortType and default fields. * These are simpler than full enhancers since inline fields don't need * block-level processing like export links. */ const DEFAULT_ENHANCERS_INLINE = [enhanceCodeInline]; /** * Export data structure containing a main type and its related additional types. * Used in the precompute field for structured type data. */ export function abstractCreateTypes(options, url, meta, exportName) { if (!url.startsWith('file:')) { throw new Error('abstractCreateTypes() requires the `url` parameter to be a file URL. Use `import.meta.url` to get the current file URL.'); } if (!meta || !meta.precompute) { throw new Error('abstractCreateTypes() must be called within a `types.ts` file'); } const singleComponentName = meta.precompute.singleComponentName; // Merge components from factory options and meta, with meta taking priority const components = { ...options.components, ...meta.components }; // Resolve named component slots (meta overrides options) const TypePre = meta.TypePre ?? options.TypePre; const DetailedTypePre = meta.DetailedTypePre ?? options.DetailedTypePre; const ShortTypeCode = meta.ShortTypeCode ?? options.ShortTypeCode; const DefaultCode = meta.DefaultCode ?? options.DefaultCode; const RawTypePre = meta.RawTypePre ?? options.RawTypePre; const highlightAt = meta.highlightAt ?? options.highlightAt; // Enhancers from meta completely override options.enhancers if set // Use DEFAULT_ENHANCERS if neither meta nor options specify enhancers // Then append enhanceCodeTypes if anchorMap is available let enhancers = meta.enhancers ?? options.enhancers ?? DEFAULT_ENHANCERS; if (meta.precompute.anchorMap && (Object.keys(meta.precompute.anchorMap.js ?? {}).length > 0 || Object.keys(meta.precompute.anchorMap.css ?? {}).length > 0)) { const typeRefComponent = meta.typeRefComponent ?? options.typeRefComponent; const typePropRefComponent = meta.typePropRefComponent ?? options.typePropRefComponent; const typeParamRefComponent = meta.typeParamRefComponent ?? options.typeParamRefComponent; const linkProps = meta.linkProps ?? options.linkProps; const linkParams = meta.linkParams ?? options.linkParams; const linkScope = meta.linkScope ?? options.linkScope; const moduleLinkMap = meta.moduleLinkMap ?? options.moduleLinkMap; const defaultImportSlug = meta.defaultImportSlug ?? options.defaultImportSlug; const exportLinksOptions = { linkMap: meta.precompute.anchorMap }; if (typeRefComponent) { exportLinksOptions.typeRefComponent = typeRefComponent; } if (typePropRefComponent) { exportLinksOptions.typePropRefComponent = typePropRefComponent; } if (typeParamRefComponent) { exportLinksOptions.typeParamRefComponent = typeParamRefComponent; } if (linkProps) { exportLinksOptions.linkProps = linkProps; } if (linkParams) { exportLinksOptions.linkParams = linkParams; } if (linkScope) { exportLinksOptions.linkScope = linkScope; } if (moduleLinkMap) { exportLinksOptions.moduleLinkMap = moduleLinkMap; } if (defaultImportSlug) { exportLinksOptions.defaultImportSlug = defaultImportSlug; } enhancers = [...enhancers, [enhanceCodeTypes, exportLinksOptions]]; } // Inline enhancers for shortType and default fields const enhancersInline = meta.enhancersInline ?? options.enhancersInline ?? DEFAULT_ENHANCERS_INLINE; // Extract precompute reference to avoid null checks inside component const precompute = meta.precompute; // Determine target export name outside component - it's static let targetExportName = exportName || singleComponentName || Object.keys(precompute.exports)[0]; // Handle default imports in single-component mode: when a component is imported // via default import, singleComponentName is the local binding name (e.g., 'loadPrecomputedTypes') // but the API extractor uses 'default' as the export key. // Only apply in single-component mode to avoid mapping every key to 'default' in multiple mode. if (!exportName && !(targetExportName in precompute.exports) && 'default' in precompute.exports) { targetExportName = 'default'; } // For single component mode (createTypes), include global additional types // For multiple component mode (createMultipleTypes), they go to the separate AdditionalTypes component // Exception: if the export doesn't exist (e.g., namespace import on types-only module), // use the variant-only additional types for that specific variant const isMultipleMode = Boolean(exportName); const exportExists = targetExportName in precompute.exports; // For namespace imports on types-only modules, use the pre-separated // variantOnlyAdditionalTypes instead of filtering from the shared pool const filteredAdditionalTypes = !exportExists && precompute.variantOnlyAdditionalTypes?.[targetExportName] ? precompute.variantOnlyAdditionalTypes[targetExportName] : precompute.additionalTypes; function TypesComponent(props) { // Memoize the conversion from HAST to JSX - only for the single export we need const { type, additionalTypes } = React.useMemo(() => typeToJsx(precompute.exports[targetExportName], filteredAdditionalTypes, { components, TypePre, DetailedTypePre, ShortTypeCode, DefaultCode, RawTypePre, enhancers, enhancersInline, highlightAt }, // Include additionalTypes for: // 1. Single component mode (createTypes) // 2. Multiple mode when export doesn't exist (namespace import on types-only module) !isMultipleMode || !exportExists), []); return /*#__PURE__*/_jsx(options.TypesTable, { ...props, type: type, additionalTypes: additionalTypes, multiple: isMultipleMode }); } if (process.env.NODE_ENV !== 'production') { TypesComponent.displayName = meta?.displayName || `${meta?.name?.replace(/ /g, '') || ''}${singleComponentName || exportName || ''}Types`; } return TypesComponent; } export function createTypesFactory(options) { /** * Creates a types table component for displaying TypeScript type information. * @param url Depends on `import.meta.url` to determine the source file location. * @param typeDef The type definition object to extract types from. * @param [meta] Additional meta for the types table. */ const createTypes = (url, typeDef, meta) => { return abstractCreateTypes(options, url, meta); }; return createTypes; } export function createMultipleTypesFactory(options) { /** * Creates multiple types table components for displaying TypeScript type information. * Each key in the typeDef object will have a corresponding component in `types`. * Also returns an `AdditionalTypes` component for top-level non-namespaced types. * @param url Depends on `import.meta.url` to determine the source file location. * @param typeDef The type definition object with multiple exports to extract types from. * @param [meta] Additional meta for the types tables. */ const createMultipleTypes = (url, typeDef, meta) => { const types = {}; // When precompute data is available, use its exports keys instead of typeDef keys. // This allows the webpack loader to replace the typeDef with a plain object, // avoiding the need to import actual component modules at runtime. // Also include keys from variantTypeNames for namespace imports on types-only modules. let keys; if (meta?.precompute) { const exportKeys = Object.keys(meta.precompute.exports); // Add variant names that have types but no export (namespace imports on types-only modules) const variantKeys = meta.precompute.variantTypeNames ? Object.keys(meta.precompute.variantTypeNames).filter(k => !exportKeys.includes(k) && meta.precompute.variantTypeNames[k].length > 0) : []; keys = [...exportKeys, ...variantKeys]; } else { keys = Object.keys(typeDef); } keys.forEach(key => { types[key] = abstractCreateTypes(options, url, meta, String(key)); }); // Create AdditionalTypes component for top-level non-namespaced types const AdditionalTypes = createAdditionalTypesComponent(options, url, meta); return { types, AdditionalTypes }; }; return createMultipleTypes; } function createAdditionalTypesComponent(options, url, meta) { if (!url.startsWith('file:')) { throw new Error('createAdditionalTypesComponent() requires the `url` parameter to be a file URL. Use `import.meta.url` to get the current file URL.'); } if (!meta || !meta.precompute) { throw new Error('createAdditionalTypesComponent() must be called within a `types.ts` file'); } // Merge components from factory options and meta, with meta taking priority const components = { ...options.components, ...meta.components }; // Resolve named component slots (meta overrides options) const TypePre = meta.TypePre ?? options.TypePre; const DetailedTypePre = meta.DetailedTypePre ?? options.DetailedTypePre; const ShortTypeCode = meta.ShortTypeCode ?? options.ShortTypeCode; const DefaultCode = meta.DefaultCode ?? options.DefaultCode; const RawTypePre = meta.RawTypePre ?? options.RawTypePre; const highlightAt = meta.highlightAt ?? options.highlightAt; // Enhancers from meta completely override options.enhancers if set // Use DEFAULT_ENHANCERS if neither meta nor options specify enhancers // Then append enhanceCodeTypes if anchorMap is available let enhancers = meta.enhancers ?? options.enhancers ?? DEFAULT_ENHANCERS; if (meta.precompute.anchorMap && (Object.keys(meta.precompute.anchorMap.js ?? {}).length > 0 || Object.keys(meta.precompute.anchorMap.css ?? {}).length > 0)) { const typeRefComponent = meta.typeRefComponent ?? options.typeRefComponent; const typePropRefComponent = meta.typePropRefComponent ?? options.typePropRefComponent; const typeParamRefComponent = meta.typeParamRefComponent ?? options.typeParamRefComponent; const linkProps = meta.linkProps ?? options.linkProps; const linkParams = meta.linkParams ?? options.linkParams; const linkScope = meta.linkScope ?? options.linkScope; const moduleLinkMap = meta.moduleLinkMap ?? options.moduleLinkMap; const defaultImportSlug = meta.defaultImportSlug ?? options.defaultImportSlug; const exportLinksOptions = { linkMap: meta.precompute.anchorMap }; if (typeRefComponent) { exportLinksOptions.typeRefComponent = typeRefComponent; } if (typePropRefComponent) { exportLinksOptions.typePropRefComponent = typePropRefComponent; } if (typeParamRefComponent) { exportLinksOptions.typeParamRefComponent = typeParamRefComponent; } if (linkProps) { exportLinksOptions.linkProps = linkProps; } if (linkParams) { exportLinksOptions.linkParams = linkParams; } if (linkScope) { exportLinksOptions.linkScope = linkScope; } if (moduleLinkMap) { exportLinksOptions.moduleLinkMap = moduleLinkMap; } if (defaultImportSlug) { exportLinksOptions.defaultImportSlug = defaultImportSlug; } enhancers = [...enhancers, [enhanceCodeTypes, exportLinksOptions]]; } // Inline enhancers for shortType and default fields const enhancersInline = meta.enhancersInline ?? options.enhancersInline ?? DEFAULT_ENHANCERS_INLINE; const precompute = meta.precompute; // Include the "Default" variant-only types since they represent the catch-all // flat/common types that belong in the Additional Types section. const allAdditionalTypes = precompute.variantOnlyAdditionalTypes?.Default ? [...precompute.additionalTypes, ...precompute.variantOnlyAdditionalTypes.Default] : precompute.additionalTypes; function AdditionalTypesComponent(props) { const additionalTypes = React.useMemo(() => additionalTypesToJsx(allAdditionalTypes, { components, TypePre, DetailedTypePre, ShortTypeCode, DefaultCode, RawTypePre, enhancers, enhancersInline, highlightAt }), []); return /*#__PURE__*/_jsx(options.TypesTable, { ...props, type: undefined, additionalTypes: additionalTypes, multiple: true }); } if (process.env.NODE_ENV !== 'production') { AdditionalTypesComponent.displayName = `${meta?.name?.replace(/ /g, '') || ''}AdditionalTypes`; } return AdditionalTypesComponent; }