@mui/internal-docs-infra 0.12.1-canary.22 → 0.12.1-canary.24
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/cli/loadNextConfig.d.mts +3 -0
- package/cli/loadNextConfig.mjs +6 -0
- package/cli/runValidate.mjs +2 -0
- package/cli/validateWorker.mjs +1 -0
- package/package.json +10 -10
- package/pipeline/loadPrecomputedTypes/loadPrecomputedTypes.d.mts +6 -0
- package/pipeline/loadPrecomputedTypes/loadPrecomputedTypes.mjs +1 -0
- package/pipeline/loadServerTypesMeta/inheritedExternalProps.d.mts +34 -0
- package/pipeline/loadServerTypesMeta/inheritedExternalProps.mjs +286 -0
- package/pipeline/loadServerTypesMeta/loadServerTypesMeta.d.mts +9 -0
- package/pipeline/loadServerTypesMeta/loadServerTypesMeta.mjs +2 -1
- package/pipeline/loadServerTypesMeta/processTypes.d.mts +6 -0
- package/pipeline/loadServerTypesMeta/processTypes.mjs +5 -0
- package/pipeline/syncTypes/syncTypes.d.mts +6 -0
- package/pipeline/syncTypes/syncTypes.mjs +2 -1
- package/useDemo/useDemo.d.mts +2 -2
- package/withDocsInfra/withDocsInfra.d.mts +22 -0
- package/withDocsInfra/withDocsInfra.mjs +7 -0
package/cli/loadNextConfig.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { DescriptionReplacement } from "../pipeline/loadServerTypesMeta/format.mjs";
|
|
2
|
+
import type { InheritedExternalPropsConfig } from "../pipeline/loadServerTypesMeta/inheritedExternalProps.mjs";
|
|
2
3
|
import type { OrderingConfig } from "../pipeline/loadServerTypesText/order.mjs";
|
|
3
4
|
export interface DemoClientRequirement {
|
|
4
5
|
/**
|
|
@@ -21,6 +22,8 @@ export interface DemoPageRequirement {
|
|
|
21
22
|
export type ExtractedNextConfigOptions = {
|
|
22
23
|
ordering?: OrderingConfig;
|
|
23
24
|
descriptionReplacements?: DescriptionReplacement[];
|
|
25
|
+
/** Props to re-include when inherited from these externally declared types. */
|
|
26
|
+
inheritedExternalProps?: InheritedExternalPropsConfig;
|
|
24
27
|
useVisibleDescription?: boolean;
|
|
25
28
|
socketDir?: string;
|
|
26
29
|
/** Page-index cache directory configured on the sitemap loader. */
|
package/cli/loadNextConfig.mjs
CHANGED
|
@@ -47,6 +47,9 @@ function extractOptionsFromLoaderEntries(loaders) {
|
|
|
47
47
|
if (!result.descriptionReplacements && loader.loader === TYPES_LOADER && loader.options?.descriptionReplacements) {
|
|
48
48
|
result.descriptionReplacements = loader.options.descriptionReplacements;
|
|
49
49
|
}
|
|
50
|
+
if (!result.inheritedExternalProps && loader.loader === TYPES_LOADER && loader.options?.inheritedExternalProps) {
|
|
51
|
+
result.inheritedExternalProps = loader.options.inheritedExternalProps;
|
|
52
|
+
}
|
|
50
53
|
if (!result.socketDir && loader.loader === TYPES_LOADER && typeof loader.options?.socketDir === 'string') {
|
|
51
54
|
result.socketDir = loader.options.socketDir;
|
|
52
55
|
}
|
|
@@ -83,6 +86,7 @@ export function extractOptionsFromTurbopack(config) {
|
|
|
83
86
|
const extracted = extractOptionsFromLoaderEntries(loaders);
|
|
84
87
|
merged.ordering ??= extracted.ordering;
|
|
85
88
|
merged.descriptionReplacements ??= extracted.descriptionReplacements;
|
|
89
|
+
merged.inheritedExternalProps ??= extracted.inheritedExternalProps;
|
|
86
90
|
merged.useVisibleDescription ??= extracted.useVisibleDescription;
|
|
87
91
|
merged.socketDir ??= extracted.socketDir;
|
|
88
92
|
merged.cacheDir ??= extracted.cacheDir;
|
|
@@ -171,6 +175,7 @@ function extractOptionsFromWebpackResult(result) {
|
|
|
171
175
|
const extracted = extractOptionsFromLoaderEntries(useEntries);
|
|
172
176
|
merged.ordering ??= extracted.ordering;
|
|
173
177
|
merged.descriptionReplacements ??= extracted.descriptionReplacements;
|
|
178
|
+
merged.inheritedExternalProps ??= extracted.inheritedExternalProps;
|
|
174
179
|
merged.useVisibleDescription ??= extracted.useVisibleDescription;
|
|
175
180
|
merged.socketDir ??= extracted.socketDir;
|
|
176
181
|
merged.cacheDir ??= extracted.cacheDir;
|
|
@@ -329,6 +334,7 @@ export async function extractDocsInfraOptionsFromNextConfig(dir) {
|
|
|
329
334
|
return {
|
|
330
335
|
ordering: turbopack.ordering ?? webpack.ordering,
|
|
331
336
|
descriptionReplacements: turbopack.descriptionReplacements ?? webpack.descriptionReplacements,
|
|
337
|
+
inheritedExternalProps: turbopack.inheritedExternalProps ?? webpack.inheritedExternalProps,
|
|
332
338
|
useVisibleDescription: turbopack.useVisibleDescription ?? webpack.useVisibleDescription,
|
|
333
339
|
socketDir: turbopack.socketDir ?? webpack.socketDir,
|
|
334
340
|
cacheDir: turbopack.cacheDir ?? webpack.cacheDir,
|
package/cli/runValidate.mjs
CHANGED
|
@@ -88,6 +88,7 @@ const runValidate = {
|
|
|
88
88
|
const {
|
|
89
89
|
ordering,
|
|
90
90
|
descriptionReplacements,
|
|
91
|
+
inheritedExternalProps,
|
|
91
92
|
useVisibleDescription = false,
|
|
92
93
|
socketDir: configSocketDir,
|
|
93
94
|
cacheDir: configCacheDir,
|
|
@@ -300,6 +301,7 @@ const runValidate = {
|
|
|
300
301
|
},
|
|
301
302
|
ordering,
|
|
302
303
|
descriptionReplacements,
|
|
304
|
+
inheritedExternalProps,
|
|
303
305
|
socketDir,
|
|
304
306
|
cacheDir
|
|
305
307
|
}
|
package/cli/validateWorker.mjs
CHANGED
|
@@ -74,6 +74,7 @@ if (parentPort) {
|
|
|
74
74
|
updateParentIndex: excludeFromIndex ? undefined : task.syncTypesOptions.updateParentIndex,
|
|
75
75
|
ordering: task.syncTypesOptions.ordering,
|
|
76
76
|
descriptionReplacements: task.syncTypesOptions.descriptionReplacements,
|
|
77
|
+
inheritedExternalProps: task.syncTypesOptions.inheritedExternalProps,
|
|
77
78
|
socketDir: task.syncTypesOptions.socketDir,
|
|
78
79
|
cacheDir: task.syncTypesOptions.cacheDir
|
|
79
80
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mui/internal-docs-infra",
|
|
3
|
-
"version": "0.12.1-canary.
|
|
3
|
+
"version": "0.12.1-canary.24",
|
|
4
4
|
"author": "MUI Team",
|
|
5
5
|
"description": "MUI Infra - internal documentation creation tools.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,15 +30,15 @@
|
|
|
30
30
|
"homepage": "https://github.com/mui/mui-public/tree/master/packages/docs-infra",
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@babel/runtime": "^7.29.7",
|
|
33
|
-
"@csstools/postcss-light-dark-function": "^3.0.
|
|
34
|
-
"@csstools/postcss-relative-color-syntax": "^4.0.
|
|
35
|
-
"@csstools/postcss-stepped-value-functions": "^5.0.
|
|
33
|
+
"@csstools/postcss-light-dark-function": "^3.0.2",
|
|
34
|
+
"@csstools/postcss-relative-color-syntax": "^4.0.7",
|
|
35
|
+
"@csstools/postcss-stepped-value-functions": "^5.0.4",
|
|
36
36
|
"@orama/orama": "^3.1.18",
|
|
37
37
|
"@orama/plugin-qps": "^3.1.18",
|
|
38
38
|
"@orama/stemmers": "^3.1.18",
|
|
39
39
|
"@orama/stopwords": "^3.1.18",
|
|
40
|
-
"@wooorm/starry-night": "^3.
|
|
41
|
-
"autoprefixer": "^10.5.
|
|
40
|
+
"@wooorm/starry-night": "^3.10.0",
|
|
41
|
+
"autoprefixer": "^10.5.4",
|
|
42
42
|
"chalk": "^5.6.2",
|
|
43
43
|
"clipboard-copy": "^4.0.1",
|
|
44
44
|
"es-toolkit": "^1.49.0",
|
|
@@ -48,11 +48,11 @@
|
|
|
48
48
|
"icss-utils": "^5.1.0",
|
|
49
49
|
"import-meta-resolve": "^4.2.0",
|
|
50
50
|
"jiti": "^2.7.0",
|
|
51
|
-
"jsondiffpatch": "^0.7.
|
|
51
|
+
"jsondiffpatch": "^0.7.6",
|
|
52
52
|
"kebab-case": "^2.0.2",
|
|
53
53
|
"lz-string": "^1.5.0",
|
|
54
54
|
"path-module": "^0.1.2",
|
|
55
|
-
"postcss": "^8.5.
|
|
55
|
+
"postcss": "^8.5.22",
|
|
56
56
|
"postcss-modules-extract-imports": "^3.1.0",
|
|
57
57
|
"postcss-modules-local-by-default": "^4.2.0",
|
|
58
58
|
"postcss-modules-scope": "^3.2.1",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"remark-stringify": "^11.0.0",
|
|
65
65
|
"remark-typography": "^0.7.3",
|
|
66
66
|
"sucrase": "^3.35.1",
|
|
67
|
-
"typescript-api-extractor": "1.0.0-beta.
|
|
67
|
+
"typescript-api-extractor": "1.0.0-beta.4",
|
|
68
68
|
"uint8-to-base64": "^0.2.1",
|
|
69
69
|
"unified": "^11.0.5",
|
|
70
70
|
"unist-util-visit": "^5.1.0",
|
|
@@ -804,5 +804,5 @@
|
|
|
804
804
|
"bin": {
|
|
805
805
|
"docs-infra": "./cli/index.mjs"
|
|
806
806
|
},
|
|
807
|
-
"gitSha": "
|
|
807
|
+
"gitSha": "da1a18c9574a4a0c716b373ec6169e6ab47abc62"
|
|
808
808
|
}
|
|
@@ -2,6 +2,7 @@ import type { LoaderContext } from 'webpack';
|
|
|
2
2
|
import type { FormatInlineTypeOptions, DescriptionReplacement } from "../loadServerTypesMeta/format.mjs";
|
|
3
3
|
import type { SyncPageIndexBaseOptions } from "../transformMarkdownMetadata/types.mjs";
|
|
4
4
|
import type { OrderingConfig } from "../loadServerTypesText/order.mjs";
|
|
5
|
+
import type { InheritedExternalPropsConfig } from "../loadServerTypesMeta/inheritedExternalProps.mjs";
|
|
5
6
|
import type { TransformHtmlCodeBlockOptions } from "../transformHtmlCodeBlock/transformHtmlCodeBlock.mjs";
|
|
6
7
|
export type LoaderOptions = {
|
|
7
8
|
/** Performance tracking and logging options */
|
|
@@ -54,6 +55,11 @@ export type LoaderOptions = {
|
|
|
54
55
|
* Each entry has a `pattern` (regex string) and `replacement` string.
|
|
55
56
|
*/
|
|
56
57
|
descriptionReplacements?: DescriptionReplacement[];
|
|
58
|
+
/**
|
|
59
|
+
* Props to re-include when inherited from these externally declared types,
|
|
60
|
+
* keyed by the declaring type's name.
|
|
61
|
+
*/
|
|
62
|
+
inheritedExternalProps?: InheritedExternalPropsConfig;
|
|
57
63
|
/** Options for code blocks highlighted inside generated type metadata */
|
|
58
64
|
codeBlockEmphasisOptions?: TransformHtmlCodeBlockOptions;
|
|
59
65
|
/**
|
|
@@ -92,6 +92,7 @@ export async function loadPrecomputedTypes(source) {
|
|
|
92
92
|
externalTypesPattern: options.externalTypesPattern,
|
|
93
93
|
ordering: options.ordering,
|
|
94
94
|
descriptionReplacements: options.descriptionReplacements,
|
|
95
|
+
inheritedExternalProps: options.inheritedExternalProps,
|
|
95
96
|
codeBlockEmphasisOptions: options.codeBlockEmphasisOptions,
|
|
96
97
|
cacheDir: options.cacheDir,
|
|
97
98
|
sync: true,
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
import type { ExportNode } from 'typescript-api-extractor';
|
|
3
|
+
/**
|
|
4
|
+
* Props to re-include for a single externally declared type. Either a list of
|
|
5
|
+
* prop names, or an object that additionally pins the package the type must be
|
|
6
|
+
* declared in — use the object form when another installed package could
|
|
7
|
+
* declare a type with the same name.
|
|
8
|
+
*/
|
|
9
|
+
export type InheritedExternalPropsEntry = string[] | {
|
|
10
|
+
/** Name of the package the type must be declared in (e.g. `@base-ui/react`). */
|
|
11
|
+
from: string;
|
|
12
|
+
props: string[];
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Props to re-include when they are inherited from externally declared types,
|
|
16
|
+
* keyed by the name of the type (interface or type alias) that declares them.
|
|
17
|
+
*
|
|
18
|
+
* @example { BaseUIComponentProps: ['className', 'render', 'style'] }
|
|
19
|
+
* @example { BaseUIComponentProps: { from: '@base-ui/react', props: ['className'] } }
|
|
20
|
+
*/
|
|
21
|
+
export interface InheritedExternalPropsConfig {
|
|
22
|
+
[typeName: string]: InheritedExternalPropsEntry;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Re-adds configured props to parsed component exports when they are inherited
|
|
26
|
+
* from a type declared in an installed package. typescript-api-extractor skips
|
|
27
|
+
* properties that are only declared inside `node_modules` (which is what keeps
|
|
28
|
+
* native DOM attributes out of the docs), so shared props that a library
|
|
29
|
+
* inherits from another package's base props type silently disappear from its
|
|
30
|
+
* prop tables. The synthesized nodes are built from the checker's resolved
|
|
31
|
+
* types, so the output matches what the extractor produces when the same props
|
|
32
|
+
* are declared locally.
|
|
33
|
+
*/
|
|
34
|
+
export declare function augmentComponentsWithInheritedProps(exports: ExportNode[], program: ts.Program, sourceFile: ts.SourceFile, config: InheritedExternalPropsConfig | undefined): void;
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
import { CallSignature, Documentation, ExternalTypeNode, FunctionNode, IntrinsicNode, LiteralNode, Parameter, PropertyNode, TypeName, UnionNode } from 'typescript-api-extractor';
|
|
3
|
+
import { isComponentType, isObjectType } from "./typeGuards.mjs";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Props to re-include for a single externally declared type. Either a list of
|
|
7
|
+
* prop names, or an object that additionally pins the package the type must be
|
|
8
|
+
* declared in — use the object form when another installed package could
|
|
9
|
+
* declare a type with the same name.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Props to re-include when they are inherited from externally declared types,
|
|
14
|
+
* keyed by the name of the type (interface or type alias) that declares them.
|
|
15
|
+
*
|
|
16
|
+
* @example { BaseUIComponentProps: ['className', 'render', 'style'] }
|
|
17
|
+
* @example { BaseUIComponentProps: { from: '@base-ui/react', props: ['className'] } }
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
function resolveConfig(config) {
|
|
21
|
+
return new Map(Object.entries(config).map(([typeName, entry]) => [typeName, Array.isArray(entry) ? {
|
|
22
|
+
props: entry
|
|
23
|
+
} : entry]));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Bail out of type conversion once nesting gets deeper than any expected prop shape. */
|
|
27
|
+
const MAX_CONVERSION_DEPTH = 8;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Re-adds configured props to parsed component exports when they are inherited
|
|
31
|
+
* from a type declared in an installed package. typescript-api-extractor skips
|
|
32
|
+
* properties that are only declared inside `node_modules` (which is what keeps
|
|
33
|
+
* native DOM attributes out of the docs), so shared props that a library
|
|
34
|
+
* inherits from another package's base props type silently disappear from its
|
|
35
|
+
* prop tables. The synthesized nodes are built from the checker's resolved
|
|
36
|
+
* types, so the output matches what the extractor produces when the same props
|
|
37
|
+
* are declared locally.
|
|
38
|
+
*/
|
|
39
|
+
export function augmentComponentsWithInheritedProps(exports, program, sourceFile, config) {
|
|
40
|
+
if (!config || Object.keys(config).length === 0) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const checker = program.getTypeChecker();
|
|
44
|
+
const moduleSymbol = checker.getSymbolAtLocation(sourceFile);
|
|
45
|
+
if (!moduleSymbol) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const symbolsByExportName = new Map();
|
|
49
|
+
collectExportSymbols(checker, moduleSymbol, [], symbolsByExportName, new Set());
|
|
50
|
+
const exportNames = exports.map(exportNode => exportNode.name);
|
|
51
|
+
const resolvedConfig = resolveConfig(config);
|
|
52
|
+
const propNames = new Set(Array.from(resolvedConfig.values()).flatMap(entry => entry.props));
|
|
53
|
+
for (const exportNode of exports) {
|
|
54
|
+
if (!isComponentType(exportNode.type)) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const symbol = symbolsByExportName.get(exportNode.name);
|
|
58
|
+
if (!symbol) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const propsType = getComponentPropsType(checker, symbol);
|
|
62
|
+
if (!propsType) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const component = exportNode.type;
|
|
66
|
+
const existingNames = new Set(component.props.map(prop => prop.name));
|
|
67
|
+
const addedProps = [];
|
|
68
|
+
for (const propName of propNames) {
|
|
69
|
+
if (existingNames.has(propName)) {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
const propSymbol = propsType.getProperty(propName);
|
|
73
|
+
if (!propSymbol || !isInheritedExternalProp(propSymbol, propName, resolvedConfig)) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const propNode = createPropNode(propSymbol, checker, exportNames);
|
|
77
|
+
if (propNode) {
|
|
78
|
+
addedProps.push(propNode);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (addedProps.length === 0) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
component.props.push(...addedProps);
|
|
85
|
+
augmentPropsTypeExports(exports, exportNode, addedProps);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Mirrors the synthesized props onto the exported props type of the component
|
|
91
|
+
* (both the namespaced `Component.Props` alias and the flat interface export),
|
|
92
|
+
* so their rendered type definitions match the component's prop table.
|
|
93
|
+
*/
|
|
94
|
+
function augmentPropsTypeExports(exports, componentExport, addedProps) {
|
|
95
|
+
const componentName = componentExport.name;
|
|
96
|
+
const propsExportNames = new Set([`${componentName}.Props`, `${componentName.replaceAll('.', '')}Props`]);
|
|
97
|
+
if (componentExport.reexportedFrom) {
|
|
98
|
+
propsExportNames.add(`${componentExport.reexportedFrom}Props`);
|
|
99
|
+
}
|
|
100
|
+
for (const exportNode of exports) {
|
|
101
|
+
if (!propsExportNames.has(exportNode.name) || !isObjectType(exportNode.type)) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
const existingNames = new Set(exportNode.type.properties.map(prop => prop.name));
|
|
105
|
+
exportNode.type.properties.push(...addedProps.filter(prop => !existingNames.has(prop.name)));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Maps parsed export names to their TypeScript symbols, using the same naming
|
|
111
|
+
* scheme as typescript-api-extractor (namespace members become dotted names,
|
|
112
|
+
* e.g. `Menu.Root`).
|
|
113
|
+
*/
|
|
114
|
+
function collectExportSymbols(checker, moduleSymbol, namespaces, result, visited) {
|
|
115
|
+
if (namespaces.length > 2 || visited.has(moduleSymbol)) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
visited.add(moduleSymbol);
|
|
119
|
+
for (const exportSymbol of checker.getExportsOfModule(moduleSymbol)) {
|
|
120
|
+
const name = [...namespaces, exportSymbol.name].join('.');
|
|
121
|
+
result.set(name, exportSymbol);
|
|
122
|
+
|
|
123
|
+
// Recurse into `export * as Namespace from '...'` re-exports.
|
|
124
|
+
const declaration = exportSymbol.declarations?.[0];
|
|
125
|
+
if (declaration && ts.isNamespaceExport(declaration)) {
|
|
126
|
+
const aliased = checker.getAliasedSymbol(exportSymbol);
|
|
127
|
+
if (aliased) {
|
|
128
|
+
collectExportSymbols(checker, aliased, [...namespaces, exportSymbol.name], result, visited);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Resolves the props type of a component export from its first call signature.
|
|
136
|
+
*/
|
|
137
|
+
function getComponentPropsType(checker, symbol) {
|
|
138
|
+
// eslint-disable-next-line no-bitwise
|
|
139
|
+
const isAlias = (symbol.flags & ts.SymbolFlags.Alias) !== 0;
|
|
140
|
+
const resolvedSymbol = isAlias ? checker.getAliasedSymbol(symbol) : symbol;
|
|
141
|
+
const componentType = checker.getTypeOfSymbol(resolvedSymbol);
|
|
142
|
+
for (const signature of componentType.getCallSignatures()) {
|
|
143
|
+
const propsParameter = signature.parameters[0];
|
|
144
|
+
const declaration = propsParameter?.valueDeclaration ?? propsParameter?.declarations?.[0];
|
|
145
|
+
if (declaration) {
|
|
146
|
+
return checker.getTypeOfSymbolAtLocation(propsParameter, declaration);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Checks that a prop is declared in an installed package on one of the
|
|
154
|
+
* configured types (and, when configured, in the expected package). Locally
|
|
155
|
+
* declared props are already handled by the extractor, and external props of
|
|
156
|
+
* any other origin (e.g. native DOM attributes) must stay excluded from the
|
|
157
|
+
* docs.
|
|
158
|
+
*/
|
|
159
|
+
function isInheritedExternalProp(propSymbol, propName, config) {
|
|
160
|
+
const declarations = propSymbol.declarations ?? [];
|
|
161
|
+
if (declarations.length === 0) {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
return declarations.every(declaration => {
|
|
165
|
+
const fileName = declaration.getSourceFile().fileName;
|
|
166
|
+
if (!fileName.includes('node_modules')) {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
const owner = ts.findAncestor(declaration, node => ts.isTypeAliasDeclaration(node) || ts.isInterfaceDeclaration(node));
|
|
170
|
+
const entry = owner && config.get(owner.name.text);
|
|
171
|
+
if (!entry || !entry.props.includes(propName)) {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
return !entry.from || getPackageName(fileName) === entry.from;
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Extracts the package name from a file path inside `node_modules`,
|
|
180
|
+
* e.g. `.../node_modules/@base-ui/react/types.d.ts` → `@base-ui/react`.
|
|
181
|
+
* Uses the last `node_modules` segment to handle nested installations.
|
|
182
|
+
*/
|
|
183
|
+
function getPackageName(fileName) {
|
|
184
|
+
const segments = fileName.split(/[\\/]/);
|
|
185
|
+
const index = segments.lastIndexOf('node_modules');
|
|
186
|
+
if (index === -1) {
|
|
187
|
+
return undefined;
|
|
188
|
+
}
|
|
189
|
+
const first = segments[index + 1];
|
|
190
|
+
if (!first) {
|
|
191
|
+
return undefined;
|
|
192
|
+
}
|
|
193
|
+
if (first.startsWith('@')) {
|
|
194
|
+
const second = segments[index + 2];
|
|
195
|
+
return second ? `${first}/${second}` : undefined;
|
|
196
|
+
}
|
|
197
|
+
return first;
|
|
198
|
+
}
|
|
199
|
+
function createPropNode(propSymbol, checker, exportNames) {
|
|
200
|
+
const declaration = propSymbol.valueDeclaration ?? propSymbol.declarations?.[0];
|
|
201
|
+
if (!declaration) {
|
|
202
|
+
return undefined;
|
|
203
|
+
}
|
|
204
|
+
const propType = checker.getTypeOfSymbolAtLocation(propSymbol, declaration);
|
|
205
|
+
const description = ts.displayPartsToString(propSymbol.getDocumentationComment(checker));
|
|
206
|
+
// eslint-disable-next-line no-bitwise
|
|
207
|
+
const optional = (propSymbol.flags & ts.SymbolFlags.Optional) !== 0;
|
|
208
|
+
return new PropertyNode(propSymbol.name, convertType(propType, checker, exportNames, 0), description ? new Documentation(description) : undefined, optional);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Converts a checker-resolved type into the extractor's type model, mirroring
|
|
213
|
+
* how typescript-api-extractor represents locally declared props: intrinsics
|
|
214
|
+
* and unions are expanded, anonymous function types are expanded into call
|
|
215
|
+
* signatures, and named types become references.
|
|
216
|
+
*/
|
|
217
|
+
function convertType(type, checker, exportNames, depth) {
|
|
218
|
+
if (depth > MAX_CONVERSION_DEPTH) {
|
|
219
|
+
return new ExternalTypeNode(new TypeName(checker.typeToString(type)));
|
|
220
|
+
}
|
|
221
|
+
const intrinsic = getIntrinsicName(type);
|
|
222
|
+
if (intrinsic) {
|
|
223
|
+
return new IntrinsicNode(intrinsic);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// eslint-disable-next-line no-bitwise
|
|
227
|
+
if ((type.flags & ts.TypeFlags.Literal) !== 0) {
|
|
228
|
+
return new LiteralNode(checker.typeToString(type));
|
|
229
|
+
}
|
|
230
|
+
if (type.isUnion()) {
|
|
231
|
+
return new UnionNode(undefined, type.types.map(member => convertType(member, checker, exportNames, depth + 1)));
|
|
232
|
+
}
|
|
233
|
+
const typeName = getNamedTypeReference(type, exportNames);
|
|
234
|
+
const callSignatures = type.getCallSignatures();
|
|
235
|
+
if (callSignatures.length > 0) {
|
|
236
|
+
return new FunctionNode(typeName, callSignatures.map(signature => convertSignature(signature, checker, exportNames, depth)));
|
|
237
|
+
}
|
|
238
|
+
if (typeName) {
|
|
239
|
+
return new ExternalTypeNode(typeName);
|
|
240
|
+
}
|
|
241
|
+
return new ExternalTypeNode(new TypeName(checker.typeToString(type)));
|
|
242
|
+
}
|
|
243
|
+
function convertSignature(signature, checker, exportNames, depth) {
|
|
244
|
+
const parameters = signature.parameters.map(parameter => {
|
|
245
|
+
const declaration = parameter.valueDeclaration ?? parameter.declarations?.[0];
|
|
246
|
+
const parameterType = declaration ? checker.getTypeOfSymbolAtLocation(parameter, declaration) : checker.getTypeOfSymbol(parameter);
|
|
247
|
+
const optional = Boolean(declaration && ts.isParameter(declaration) && (declaration.questionToken || declaration.initializer));
|
|
248
|
+
return new Parameter(convertType(parameterType, checker, exportNames, depth + 1), parameter.name, undefined, optional, undefined);
|
|
249
|
+
});
|
|
250
|
+
return new CallSignature(parameters, convertType(signature.getReturnType(), checker, exportNames, depth + 1));
|
|
251
|
+
}
|
|
252
|
+
const INTRINSIC_FLAGS = [[ts.TypeFlags.String, 'string'], [ts.TypeFlags.Number, 'number'], [ts.TypeFlags.Boolean, 'boolean'], [ts.TypeFlags.BigInt, 'bigint'], [ts.TypeFlags.Undefined, 'undefined'], [ts.TypeFlags.Null, 'null'], [ts.TypeFlags.Void, 'void'], [ts.TypeFlags.Any, 'any'], [ts.TypeFlags.Unknown, 'unknown'], [ts.TypeFlags.Never, 'never']];
|
|
253
|
+
function getIntrinsicName(type) {
|
|
254
|
+
// `boolean` is represented as a union of literals, so check it before unions.
|
|
255
|
+
// eslint-disable-next-line no-bitwise
|
|
256
|
+
const match = INTRINSIC_FLAGS.find(([flag]) => (type.flags & flag) !== 0);
|
|
257
|
+
return match?.[1];
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Builds a reference for a named type, preferring the module's dotted export
|
|
262
|
+
* name (e.g. `Menu.Root.State`) when one exists for the flat name.
|
|
263
|
+
*/
|
|
264
|
+
function getNamedTypeReference(type, exportNames) {
|
|
265
|
+
const symbol = type.aliasSymbol ?? type.getSymbol();
|
|
266
|
+
const name = symbol?.name;
|
|
267
|
+
if (!symbol || !name || name.startsWith('__')) {
|
|
268
|
+
return undefined;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Collect enclosing namespaces (e.g. `React` for `React.CSSProperties`),
|
|
272
|
+
// stopping at module/source-file symbols whose names are quoted paths.
|
|
273
|
+
const namespaces = [];
|
|
274
|
+
let parent = symbol.parent;
|
|
275
|
+
while (parent && /^[A-Za-z_$][\w$]*$/.test(parent.name)) {
|
|
276
|
+
namespaces.unshift(parent.name);
|
|
277
|
+
parent = parent.parent;
|
|
278
|
+
}
|
|
279
|
+
const flatName = [...namespaces, name].join('');
|
|
280
|
+
const dottedName = exportNames.find(exportName => exportName.includes('.') && exportName.replaceAll('.', '') === flatName);
|
|
281
|
+
if (dottedName) {
|
|
282
|
+
const parts = dottedName.split('.');
|
|
283
|
+
return new TypeName(parts[parts.length - 1], parts.slice(0, -1));
|
|
284
|
+
}
|
|
285
|
+
return new TypeName(name, namespaces.length > 0 ? namespaces : undefined);
|
|
286
|
+
}
|
|
@@ -4,6 +4,7 @@ import type { HookTypeMeta as HookType } from "./formatHook.mjs";
|
|
|
4
4
|
import type { FunctionTypeMeta as FunctionType } from "./formatFunction.mjs";
|
|
5
5
|
import type { RawTypeMeta as RawType, ReExportInfo } from "./formatRaw.mjs";
|
|
6
6
|
import type { FormattedProperty, FormattedEnumMember, FormattedParameter, FormatInlineTypeOptions, DescriptionReplacement } from "./format.mjs";
|
|
7
|
+
import type { InheritedExternalPropsConfig } from "./inheritedExternalProps.mjs";
|
|
7
8
|
import type { OrderingConfig } from "../loadServerTypesText/order.mjs";
|
|
8
9
|
import type { OrganizeTypesResult } from "../loadServerTypesText/organizeTypesByExport.mjs";
|
|
9
10
|
export type ClassTypeMeta = ClassType;
|
|
@@ -93,6 +94,14 @@ export interface LoadServerTypesMetaOptions {
|
|
|
93
94
|
* Each entry has a `pattern` (regex string) and `replacement` string.
|
|
94
95
|
*/
|
|
95
96
|
descriptionReplacements?: DescriptionReplacement[];
|
|
97
|
+
/**
|
|
98
|
+
* Props to re-include when inherited from these externally declared types,
|
|
99
|
+
* keyed by the declaring type's name. The parser normally drops props that are
|
|
100
|
+
* only declared inside `node_modules`; this re-adds the configured ones.
|
|
101
|
+
*
|
|
102
|
+
* @example { BaseUIComponentProps: ['className', 'render', 'style'] }
|
|
103
|
+
*/
|
|
104
|
+
inheritedExternalProps?: InheritedExternalPropsConfig;
|
|
96
105
|
}
|
|
97
106
|
export interface LoadServerTypesMetaResult extends OrganizeTypesResult<TypesMeta> {
|
|
98
107
|
/** All dependencies that should be watched for changes */
|
|
@@ -166,7 +166,8 @@ export async function loadServerTypesMeta(options) {
|
|
|
166
166
|
resolvedVariantMap: Array.from(resolvedVariantMap.entries()),
|
|
167
167
|
dependencies: config.dependencies,
|
|
168
168
|
rootContextDir,
|
|
169
|
-
relativePath
|
|
169
|
+
relativePath,
|
|
170
|
+
inheritedExternalProps: options.inheritedExternalProps
|
|
170
171
|
});
|
|
171
172
|
if (!workerResult.success) {
|
|
172
173
|
throw new Error(workerResult.error || 'Worker failed to process types');
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { CompilerOptions } from 'typescript';
|
|
2
2
|
import type { ExportNode } from 'typescript-api-extractor';
|
|
3
|
+
import type { InheritedExternalPropsConfig } from "./inheritedExternalProps.mjs";
|
|
3
4
|
import type { PerformanceLog } from "./performanceTracking.mjs";
|
|
4
5
|
export interface VariantResult {
|
|
5
6
|
exports: ExportNode[];
|
|
@@ -22,6 +23,11 @@ export interface WorkerRequest {
|
|
|
22
23
|
/** Root context directory path (must end with /) */
|
|
23
24
|
rootContextDir: string;
|
|
24
25
|
relativePath: string;
|
|
26
|
+
/**
|
|
27
|
+
* Props to re-include when inherited from these externally declared types,
|
|
28
|
+
* keyed by the declaring type's name.
|
|
29
|
+
*/
|
|
30
|
+
inheritedExternalProps?: InheritedExternalPropsConfig;
|
|
25
31
|
}
|
|
26
32
|
export interface WorkerResponse {
|
|
27
33
|
requestId?: number;
|
|
@@ -3,6 +3,7 @@ import { fileURLToPath } from 'url';
|
|
|
3
3
|
import { parseFromProgram } from 'typescript-api-extractor';
|
|
4
4
|
import ts from 'typescript';
|
|
5
5
|
import { createOptimizedProgram } from "./createOptimizedProgram.mjs";
|
|
6
|
+
import { augmentComponentsWithInheritedProps } from "./inheritedExternalProps.mjs";
|
|
6
7
|
import { extractJSDocText, isJSDocNodeArray } from "./extractJSDocText.mjs";
|
|
7
8
|
import { PerformanceTracker } from "./performanceTracking.mjs";
|
|
8
9
|
import { nameMark } from "../loadPrecomputedCodeHighlighter/performanceLogger.mjs";
|
|
@@ -299,6 +300,10 @@ export async function processTypes(request) {
|
|
|
299
300
|
exports
|
|
300
301
|
} = parseFromProgram(entrypoint, program, parserOptions);
|
|
301
302
|
|
|
303
|
+
// Re-add configured props that the parser dropped because they are
|
|
304
|
+
// inherited from an externally declared type in node_modules
|
|
305
|
+
augmentComponentsWithInheritedProps(exports, program, sourceFile, request.inheritedExternalProps);
|
|
306
|
+
|
|
302
307
|
// Extract namespaces from the exports (e.g., "Menu" from "Menu.Root")
|
|
303
308
|
const namespaces = extractNamespaces(exports);
|
|
304
309
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { InheritedExternalPropsConfig } from "../loadServerTypesMeta/inheritedExternalProps.mjs";
|
|
1
2
|
import type { FormatInlineTypeOptions, DescriptionReplacement } from "../loadServerTypesMeta/format.mjs";
|
|
2
3
|
import type { OrderingConfig } from "../loadServerTypesText/order.mjs";
|
|
3
4
|
import type { SyncPageIndexBaseOptions } from "../transformMarkdownMetadata/types.mjs";
|
|
@@ -62,6 +63,11 @@ export interface SyncTypesOptions {
|
|
|
62
63
|
* Each entry has a `pattern` (regex string) and `replacement` string.
|
|
63
64
|
*/
|
|
64
65
|
descriptionReplacements?: DescriptionReplacement[];
|
|
66
|
+
/**
|
|
67
|
+
* Props to re-include when inherited from these externally declared types,
|
|
68
|
+
* keyed by the declaring type's name.
|
|
69
|
+
*/
|
|
70
|
+
inheritedExternalProps?: InheritedExternalPropsConfig;
|
|
65
71
|
/**
|
|
66
72
|
* Directory for the sha256-validated JSON cache of the types pipeline. When set, after
|
|
67
73
|
* writing types.md syncTypes pre-populates `{cacheDir}/types-text/{route}.json` with the
|
|
@@ -196,7 +196,8 @@ export async function syncTypes(options) {
|
|
|
196
196
|
socketDir: options.socketDir,
|
|
197
197
|
externalTypesPattern: options.externalTypesPattern,
|
|
198
198
|
ordering: options.ordering,
|
|
199
|
-
descriptionReplacements: options.descriptionReplacements
|
|
199
|
+
descriptionReplacements: options.descriptionReplacements,
|
|
200
|
+
inheritedExternalProps: options.inheritedExternalProps
|
|
200
201
|
});
|
|
201
202
|
const {
|
|
202
203
|
allDependencies,
|
package/useDemo/useDemo.d.mts
CHANGED
|
@@ -68,8 +68,8 @@ export declare function useDemo<T extends {} = {}>(contentProps: ContentProps<T>
|
|
|
68
68
|
expanded: boolean;
|
|
69
69
|
expand: () => void;
|
|
70
70
|
setExpanded: (expanded: boolean) => void;
|
|
71
|
-
copy: (event: React.MouseEvent<Element
|
|
72
|
-
copyMarkdown: (event: React.MouseEvent<Element
|
|
71
|
+
copy: (event: React.MouseEvent<Element>) => Promise<void>;
|
|
72
|
+
copyMarkdown: (event: React.MouseEvent<Element>) => Promise<void>;
|
|
73
73
|
availableTransforms: string[];
|
|
74
74
|
selectedTransform: string | null | undefined;
|
|
75
75
|
selectTransform: (transformName: string | null) => void;
|
|
@@ -2,6 +2,7 @@ import type { NextConfig } from 'next';
|
|
|
2
2
|
import type { RuleSetRule } from 'webpack';
|
|
3
3
|
import type { OrderingConfig } from "../pipeline/loadServerTypesText/order.mjs";
|
|
4
4
|
import type { DescriptionReplacement } from "../pipeline/loadServerTypesMeta/format.mjs";
|
|
5
|
+
import type { InheritedExternalPropsConfig } from "../pipeline/loadServerTypesMeta/inheritedExternalProps.mjs";
|
|
5
6
|
import type { EnhanceCodeEmphasisOptions } from "../pipeline/parseSource/calculateFrameRanges.mjs";
|
|
6
7
|
import type { TransformHtmlCodeBlockOptions } from "../pipeline/transformHtmlCodeBlock/transformHtmlCodeBlock.mjs";
|
|
7
8
|
export interface WebpackOptions {
|
|
@@ -165,6 +166,27 @@ export interface WithDocsInfraOptions {
|
|
|
165
166
|
* ```
|
|
166
167
|
*/
|
|
167
168
|
descriptionReplacements?: DescriptionReplacement[];
|
|
169
|
+
/**
|
|
170
|
+
* Props to re-include in component docs when they are inherited from these
|
|
171
|
+
* externally declared types, keyed by the declaring type's name. Type
|
|
172
|
+
* extraction normally drops props that are only declared inside
|
|
173
|
+
* `node_modules` (which keeps native DOM attributes out of the docs); this
|
|
174
|
+
* option re-adds the configured props when a component's props type extends
|
|
175
|
+
* one of the listed types from an installed package.
|
|
176
|
+
*
|
|
177
|
+
* Entries can also pin the package the type must come from, to disambiguate
|
|
178
|
+
* same-named types from different packages.
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* ```js
|
|
182
|
+
* { BaseUIComponentProps: ['className', 'render', 'style'] }
|
|
183
|
+
* ```
|
|
184
|
+
* @example
|
|
185
|
+
* ```js
|
|
186
|
+
* { BaseUIComponentProps: { from: '@base-ui/react', props: ['className', 'render', 'style'] } }
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
inheritedExternalProps?: InheritedExternalPropsConfig;
|
|
168
190
|
/**
|
|
169
191
|
* Directory rooting docs-infra's build caches and coordination state — relocate it (or point it
|
|
170
192
|
* at a persistent cache) and everything under it moves together: the sha256-validated JSON caches
|
|
@@ -93,6 +93,7 @@ export function withDocsInfra(options = {}) {
|
|
|
93
93
|
// Only include ordering in loader options if explicitly provided
|
|
94
94
|
const ordering = options.ordering;
|
|
95
95
|
const descriptionReplacements = options.descriptionReplacements;
|
|
96
|
+
const inheritedExternalProps = options.inheritedExternalProps;
|
|
96
97
|
const demoEmphasisOptions = options.demoEmphasisOptions;
|
|
97
98
|
const codeBlockEmphasisOptions = options.codeBlockEmphasisOptions;
|
|
98
99
|
|
|
@@ -183,6 +184,9 @@ export function withDocsInfra(options = {}) {
|
|
|
183
184
|
} : {}),
|
|
184
185
|
...(descriptionReplacements ? {
|
|
185
186
|
descriptionReplacements: descriptionReplacements
|
|
187
|
+
} : {}),
|
|
188
|
+
...(inheritedExternalProps ? {
|
|
189
|
+
inheritedExternalProps: inheritedExternalProps
|
|
186
190
|
} : {})
|
|
187
191
|
}
|
|
188
192
|
}]
|
|
@@ -313,6 +317,9 @@ export function withDocsInfra(options = {}) {
|
|
|
313
317
|
} : {}),
|
|
314
318
|
...(descriptionReplacements ? {
|
|
315
319
|
descriptionReplacements
|
|
320
|
+
} : {}),
|
|
321
|
+
...(inheritedExternalProps ? {
|
|
322
|
+
inheritedExternalProps
|
|
316
323
|
} : {})
|
|
317
324
|
}
|
|
318
325
|
}]
|