fumadocs-typescript 5.1.2 → 5.1.4
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/{base-BVIaJVDA.d.ts → base-CLqyTLv7.d.ts} +16 -16
- package/dist/get-simple-form-B8HWDNe0.js +45 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +167 -145
- package/dist/{parse-tags-D9KSwbHI.js → parse-tags-DMoo_pSD.js} +5 -3
- package/dist/ui/index.d.ts +8 -7
- package/dist/ui/index.js +13 -4
- package/package.json +7 -6
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
import { ExportedDeclarations, Project, Symbol, Type } from "ts-morph";
|
|
2
2
|
|
|
3
|
-
//#region src/create-project.d.ts
|
|
4
|
-
interface TypescriptConfig {
|
|
5
|
-
files?: string[];
|
|
6
|
-
tsconfigPath?: string;
|
|
7
|
-
/** A root directory to resolve relative path entries in the config file to. e.g. outDir */
|
|
8
|
-
basePath?: string;
|
|
9
|
-
}
|
|
10
|
-
declare function createProject(options?: TypescriptConfig): Project;
|
|
11
|
-
//#endregion
|
|
12
3
|
//#region src/lib/type-table.d.ts
|
|
13
4
|
interface BaseTypeTableProps {
|
|
14
5
|
/**
|
|
@@ -51,20 +42,26 @@ interface GenerateTypeTableOptions extends GenerateOptions {
|
|
|
51
42
|
//#endregion
|
|
52
43
|
//#region src/cache/index.d.ts
|
|
53
44
|
interface Cache {
|
|
54
|
-
read: (
|
|
55
|
-
write: (
|
|
45
|
+
read: (hash: string) => unknown | undefined | Promise<unknown | undefined>;
|
|
46
|
+
write: (hash: string, value: unknown) => void | Promise<void>;
|
|
56
47
|
}
|
|
48
|
+
declare function generateHash(str: string): string;
|
|
57
49
|
//#endregion
|
|
58
50
|
//#region src/lib/base.d.ts
|
|
59
51
|
interface GeneratedDoc {
|
|
52
|
+
/**
|
|
53
|
+
* unique ID generated from file name & export declaration.
|
|
54
|
+
*/
|
|
55
|
+
id: string;
|
|
60
56
|
name: string;
|
|
61
|
-
description
|
|
57
|
+
description?: string;
|
|
62
58
|
entries: DocEntry[];
|
|
63
59
|
}
|
|
64
60
|
interface DocEntry {
|
|
65
61
|
name: string;
|
|
66
62
|
description: string;
|
|
67
63
|
type: string;
|
|
64
|
+
typeHref?: string;
|
|
68
65
|
simplifiedType: string;
|
|
69
66
|
tags: RawTag[];
|
|
70
67
|
required: boolean;
|
|
@@ -74,9 +71,8 @@ interface RawTag {
|
|
|
74
71
|
name: string;
|
|
75
72
|
text: string;
|
|
76
73
|
}
|
|
77
|
-
interface EntryContext {
|
|
74
|
+
interface EntryContext extends GenerateOptions {
|
|
78
75
|
program: Project;
|
|
79
|
-
transform?: Transformer;
|
|
80
76
|
type: Type;
|
|
81
77
|
declaration: ExportedDeclarations;
|
|
82
78
|
}
|
|
@@ -103,7 +99,11 @@ interface GeneratorOptions extends TypescriptConfig {
|
|
|
103
99
|
cache?: Cache | false;
|
|
104
100
|
project?: Project;
|
|
105
101
|
}
|
|
106
|
-
|
|
102
|
+
interface TypescriptConfig {
|
|
103
|
+
tsconfigPath?: string;
|
|
104
|
+
}
|
|
105
|
+
declare function createProject(options?: TypescriptConfig): Promise<Project>;
|
|
106
|
+
declare function createGenerator(options?: GeneratorOptions): {
|
|
107
107
|
generateDocumentation(file: {
|
|
108
108
|
path: string;
|
|
109
109
|
content?: string;
|
|
@@ -111,4 +111,4 @@ declare function createGenerator(config?: GeneratorOptions | Project): {
|
|
|
111
111
|
generateTypeTable(props: BaseTypeTableProps, options?: GenerateTypeTableOptions): Promise<GeneratedDoc[]>;
|
|
112
112
|
};
|
|
113
113
|
//#endregion
|
|
114
|
-
export { GeneratorOptions as a,
|
|
114
|
+
export { GeneratorOptions as a, createGenerator as c, generateHash as d, BaseTypeTableProps as f, Generator as i, createProject as l, GenerateOptions as n, RawTag as o, GenerateTypeTableOptions as p, GeneratedDoc as r, TypescriptConfig as s, DocEntry as t, Cache as u };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { TypeFormatFlags } from "ts-morph";
|
|
2
|
+
|
|
3
|
+
//#region src/lib/get-simple-form.ts
|
|
4
|
+
function getSimpleForm(type, checker, noUndefined = false, location) {
|
|
5
|
+
if (type.isUndefined() && noUndefined) return "";
|
|
6
|
+
const alias = type.getAliasSymbol();
|
|
7
|
+
if (alias) {
|
|
8
|
+
const args = type.getAliasTypeArguments();
|
|
9
|
+
if (args.length === 0) return alias.getName();
|
|
10
|
+
return `${alias.getName()}<${args.map((arg) => getSimpleForm(arg, checker)).join(", ")}>`;
|
|
11
|
+
}
|
|
12
|
+
if (type.isUnion()) {
|
|
13
|
+
const types = [];
|
|
14
|
+
for (const t of type.getUnionTypes()) {
|
|
15
|
+
const str = getSimpleForm(t, checker, noUndefined);
|
|
16
|
+
if (str.length > 0 && str !== "never") types.unshift(str);
|
|
17
|
+
}
|
|
18
|
+
return types.length > 0 ? dedupe(types).join(" | ").replace("true | false", "boolean") : "never";
|
|
19
|
+
}
|
|
20
|
+
if (type.isIntersection()) {
|
|
21
|
+
const types = [];
|
|
22
|
+
for (const t of type.getIntersectionTypes()) {
|
|
23
|
+
const str = getSimpleForm(t, checker, noUndefined);
|
|
24
|
+
if (str.length > 0 && str !== "never") types.unshift(str);
|
|
25
|
+
}
|
|
26
|
+
return dedupe(types).join(" & ");
|
|
27
|
+
}
|
|
28
|
+
if (type.isTuple()) return `[${type.getTupleElements().map((t) => getSimpleForm(t, checker)).join(", ")}]`;
|
|
29
|
+
if (type.isArray() || type.isReadonlyArray()) return "array";
|
|
30
|
+
if (type.getCallSignatures().length > 0) return "function";
|
|
31
|
+
if (type.isClassOrInterface() || type.isObject()) return "object";
|
|
32
|
+
return type.getText(location, TypeFormatFlags.UseAliasDefinedOutsideCurrentScope);
|
|
33
|
+
}
|
|
34
|
+
function dedupe(arr) {
|
|
35
|
+
const dedupe = /* @__PURE__ */ new Set();
|
|
36
|
+
const out = [];
|
|
37
|
+
for (const item of arr) if (!dedupe.has(item)) {
|
|
38
|
+
out.push(item);
|
|
39
|
+
dedupe.add(item);
|
|
40
|
+
}
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
//#endregion
|
|
45
|
+
export { getSimpleForm };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as GeneratorOptions, c as
|
|
1
|
+
import { a as GeneratorOptions, c as createGenerator, d as generateHash, f as BaseTypeTableProps, i as Generator, l as createProject, n as GenerateOptions, o as RawTag, p as GenerateTypeTableOptions, r as GeneratedDoc, s as TypescriptConfig, t as DocEntry, u as Cache } from "./base-CLqyTLv7.js";
|
|
2
2
|
import { ResolvedShikiConfig } from "fumadocs-core/highlight/config";
|
|
3
3
|
import { Nodes } from "hast";
|
|
4
4
|
import { Root } from "mdast";
|
|
@@ -31,7 +31,7 @@ interface RemarkAutoTypeTableOptions {
|
|
|
31
31
|
*/
|
|
32
32
|
options?: GenerateTypeTableOptions;
|
|
33
33
|
/**
|
|
34
|
-
* generate
|
|
34
|
+
* generate the stringified form of props (useful for `remark-stringify` etc).
|
|
35
35
|
*/
|
|
36
36
|
remarkStringify?: boolean;
|
|
37
37
|
generator?: Generator;
|
|
@@ -49,4 +49,4 @@ declare function remarkAutoTypeTable(config?: RemarkAutoTypeTableOptions): Trans
|
|
|
49
49
|
//#region src/cache/fs-cache.d.ts
|
|
50
50
|
declare function createFileSystemGeneratorCache(dir: string): Cache;
|
|
51
51
|
//#endregion
|
|
52
|
-
export { Cache, DocEntry, GenerateOptions, GeneratedDoc, Generator, GeneratorOptions, type MarkdownRenderer, RawTag, RemarkAutoTypeTableOptions, TypeTableProps, createFileSystemGeneratorCache, createGenerator, createProject, remarkAutoTypeTable };
|
|
52
|
+
export { Cache, DocEntry, GenerateOptions, GeneratedDoc, Generator, GeneratorOptions, type MarkdownRenderer, RawTag, RemarkAutoTypeTableOptions, TypeTableProps, TypescriptConfig, createFileSystemGeneratorCache, createGenerator, createProject, generateHash, remarkAutoTypeTable };
|
package/dist/index.js
CHANGED
|
@@ -1,29 +1,17 @@
|
|
|
1
|
-
import { n as markdownRenderer, t as parseTags } from "./parse-tags-
|
|
2
|
-
import * as ts$1 from "ts-morph";
|
|
3
|
-
import { Project, ts } from "ts-morph";
|
|
4
|
-
import * as fs$1 from "node:fs/promises";
|
|
1
|
+
import { n as markdownRenderer, t as parseTags } from "./parse-tags-DMoo_pSD.js";
|
|
5
2
|
import fs from "node:fs/promises";
|
|
6
|
-
import path
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { createHash } from "node:crypto";
|
|
7
5
|
import { valueToEstree } from "estree-util-value-to-estree";
|
|
8
6
|
import { visit } from "unist-util-visit";
|
|
9
7
|
import { toEstree } from "hast-util-to-estree";
|
|
10
|
-
import { createHash } from "node:crypto";
|
|
11
8
|
|
|
12
|
-
//#region src/create-project.ts
|
|
13
|
-
function createProject(options = {}) {
|
|
14
|
-
return new Project({
|
|
15
|
-
tsConfigFilePath: options.tsconfigPath ?? "./tsconfig.json",
|
|
16
|
-
skipAddingFilesFromTsConfig: true
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
//#endregion
|
|
21
9
|
//#region src/lib/type-table.ts
|
|
22
10
|
async function getTypeTableOutput(gen, { name, type, ...props }, options) {
|
|
23
|
-
const file = props.path && options?.basePath ? join(options.basePath, props.path) : props.path;
|
|
11
|
+
const file = props.path && options?.basePath ? path.join(options.basePath, props.path) : props.path;
|
|
24
12
|
let typeName = name;
|
|
25
13
|
let content = "";
|
|
26
|
-
if (file) content = (await fs
|
|
14
|
+
if (file) content = (await fs.readFile(file)).toString();
|
|
27
15
|
if (type && type.split("\n").length > 1) content += `\n${type}`;
|
|
28
16
|
else if (type) {
|
|
29
17
|
typeName ??= "$Fumadocs";
|
|
@@ -38,73 +26,69 @@ async function getTypeTableOutput(gen, { name, type, ...props }, options) {
|
|
|
38
26
|
}
|
|
39
27
|
|
|
40
28
|
//#endregion
|
|
41
|
-
//#region src/
|
|
42
|
-
function
|
|
43
|
-
|
|
44
|
-
const alias = type.getAliasSymbol();
|
|
45
|
-
if (alias) {
|
|
46
|
-
const args = type.getAliasTypeArguments();
|
|
47
|
-
if (args.length === 0) return alias.getName();
|
|
48
|
-
return `${alias.getName()}<${args.map((arg) => getSimpleForm(arg, checker)).join(", ")}>`;
|
|
49
|
-
}
|
|
50
|
-
if (type.isUnion()) {
|
|
51
|
-
const types = [];
|
|
52
|
-
for (const t of type.getUnionTypes()) {
|
|
53
|
-
const str = getSimpleForm(t, checker, noUndefined);
|
|
54
|
-
if (str.length > 0 && str !== "never") types.unshift(str);
|
|
55
|
-
}
|
|
56
|
-
return types.length > 0 ? dedupe(types).join(" | ").replace("true | false", "boolean") : "never";
|
|
57
|
-
}
|
|
58
|
-
if (type.isIntersection()) {
|
|
59
|
-
const types = [];
|
|
60
|
-
for (const t of type.getIntersectionTypes()) {
|
|
61
|
-
const str = getSimpleForm(t, checker, noUndefined);
|
|
62
|
-
if (str.length > 0 && str !== "never") types.unshift(str);
|
|
63
|
-
}
|
|
64
|
-
return dedupe(types).join(" & ");
|
|
65
|
-
}
|
|
66
|
-
if (type.isTuple()) return `[${type.getTupleElements().map((t) => getSimpleForm(t, checker)).join(", ")}]`;
|
|
67
|
-
if (type.isArray() || type.isReadonlyArray()) return "array";
|
|
68
|
-
if (type.getCallSignatures().length > 0) return "function";
|
|
69
|
-
if (type.isClassOrInterface() || type.isObject()) return "object";
|
|
70
|
-
return type.getText(location, ts$1.TypeFormatFlags.UseAliasDefinedOutsideCurrentScope);
|
|
71
|
-
}
|
|
72
|
-
function dedupe(arr) {
|
|
73
|
-
const dedupe = /* @__PURE__ */ new Set();
|
|
74
|
-
const out = [];
|
|
75
|
-
for (const item of arr) if (!dedupe.has(item)) {
|
|
76
|
-
out.push(item);
|
|
77
|
-
dedupe.add(item);
|
|
78
|
-
}
|
|
79
|
-
return out;
|
|
29
|
+
//#region src/cache/index.ts
|
|
30
|
+
function generateHash(str) {
|
|
31
|
+
return createHash("SHA256").update(str).digest("hex").slice(0, 12);
|
|
80
32
|
}
|
|
81
33
|
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region package.json
|
|
36
|
+
var version = "5.1.4";
|
|
37
|
+
|
|
82
38
|
//#endregion
|
|
83
39
|
//#region src/lib/base.ts
|
|
84
|
-
function
|
|
85
|
-
const
|
|
40
|
+
async function createProject(options = {}) {
|
|
41
|
+
const { Project } = await import("ts-morph");
|
|
42
|
+
return new Project({
|
|
43
|
+
tsConfigFilePath: options.tsconfigPath ?? "./tsconfig.json",
|
|
44
|
+
skipAddingFilesFromTsConfig: true
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
function createGenerator(options = {}) {
|
|
86
48
|
const cache = options?.cache ? options.cache : null;
|
|
87
|
-
let instance;
|
|
49
|
+
let instance = options?.project;
|
|
88
50
|
function getProject() {
|
|
89
|
-
instance
|
|
90
|
-
return instance;
|
|
51
|
+
if (instance) return instance;
|
|
52
|
+
return instance = createProject(options);
|
|
53
|
+
}
|
|
54
|
+
function getSourceFile(project, filePath, fileContent) {
|
|
55
|
+
const ext = path.extname(filePath);
|
|
56
|
+
const fileBase = filePath.slice(0, -ext.length);
|
|
57
|
+
let i = 0;
|
|
58
|
+
let sourceFile = project.getSourceFile(filePath);
|
|
59
|
+
while (sourceFile && sourceFile.getFullText() !== fileContent) {
|
|
60
|
+
filePath = `${fileBase}.${i++}${ext}`;
|
|
61
|
+
sourceFile = project.getSourceFile(filePath);
|
|
62
|
+
}
|
|
63
|
+
if (sourceFile) return sourceFile;
|
|
64
|
+
return project.createSourceFile(filePath, fileContent, { overwrite: true });
|
|
91
65
|
}
|
|
92
66
|
return {
|
|
93
|
-
async generateDocumentation(file, name, options) {
|
|
94
|
-
const
|
|
95
|
-
const
|
|
67
|
+
async generateDocumentation(file, name, options = {}) {
|
|
68
|
+
const fullPath = path.resolve(file.path);
|
|
69
|
+
const content = file.content ?? (await fs.readFile(fullPath)).toString();
|
|
70
|
+
let cacheKey;
|
|
96
71
|
if (cache) {
|
|
72
|
+
cacheKey = generateHash(`${file.path}:${name}:${content}:${version}`);
|
|
97
73
|
const cached = await cache.read(cacheKey);
|
|
98
74
|
if (cached) return cached;
|
|
99
75
|
}
|
|
100
|
-
const
|
|
76
|
+
const project = await getProject();
|
|
77
|
+
const sourceFile = getSourceFile(project, fullPath, content);
|
|
101
78
|
const out = [];
|
|
102
79
|
for (const [k, d] of sourceFile.getExportedDeclarations()) {
|
|
103
|
-
if (name
|
|
80
|
+
if (d.length === 0 || !name || name !== k) continue;
|
|
104
81
|
if (d.length > 1) console.warn(`export ${k} should not have more than one type declaration.`);
|
|
105
|
-
|
|
82
|
+
const declaration = d[0];
|
|
83
|
+
const entryContext = {
|
|
84
|
+
...options,
|
|
85
|
+
program: project,
|
|
86
|
+
type: declaration.getType(),
|
|
87
|
+
declaration
|
|
88
|
+
};
|
|
89
|
+
out.push(await generate(encodeURI(`${path.basename(file.path)}-${name}`), k, entryContext));
|
|
106
90
|
}
|
|
107
|
-
cache
|
|
91
|
+
if (cache && cacheKey) await cache.write(cacheKey, out);
|
|
108
92
|
return out;
|
|
109
93
|
},
|
|
110
94
|
generateTypeTable(props, options) {
|
|
@@ -112,51 +96,66 @@ function createGenerator(config) {
|
|
|
112
96
|
}
|
|
113
97
|
};
|
|
114
98
|
}
|
|
115
|
-
function generate(
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
program,
|
|
119
|
-
type: declaration.getType(),
|
|
120
|
-
declaration
|
|
121
|
-
};
|
|
99
|
+
async function generate(id, name, entryContext) {
|
|
100
|
+
const { ts } = await import("ts-morph");
|
|
101
|
+
const { declaration, program } = entryContext;
|
|
122
102
|
const comment = declaration.getSymbol()?.compilerSymbol.getDocumentationComment(program.getTypeChecker().compilerObject);
|
|
103
|
+
const entries = [];
|
|
104
|
+
for (const prop of declaration.getType().getProperties()) {
|
|
105
|
+
const out = await getDocEntry(prop, entryContext);
|
|
106
|
+
if (out) entries.push(out);
|
|
107
|
+
}
|
|
123
108
|
return {
|
|
109
|
+
id,
|
|
124
110
|
name,
|
|
125
|
-
description: comment ? ts.displayPartsToString(comment) :
|
|
126
|
-
entries
|
|
111
|
+
description: comment ? ts.displayPartsToString(comment) : void 0,
|
|
112
|
+
entries
|
|
127
113
|
};
|
|
128
114
|
}
|
|
129
|
-
function getDocEntry(prop, context) {
|
|
130
|
-
const {
|
|
115
|
+
async function getDocEntry(prop, context) {
|
|
116
|
+
const { ts } = await import("ts-morph");
|
|
117
|
+
const { getSimpleForm } = await import("./get-simple-form-B8HWDNe0.js");
|
|
118
|
+
const { transform, allowInternal = false, program } = context;
|
|
131
119
|
if (context.type.isClass() && prop.getName().startsWith("#")) return;
|
|
132
120
|
const subType = prop.getTypeAtLocation(context.declaration);
|
|
133
121
|
const isOptional = prop.isOptional();
|
|
134
|
-
const tags =
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if (tag.name === "fumadocsType") {
|
|
142
|
-
const match = /`(?<name>.+)`$/.exec(tag.text)?.[1];
|
|
143
|
-
if (match) type = match;
|
|
144
|
-
continue;
|
|
145
|
-
}
|
|
146
|
-
if (tag.name === "remarks") {
|
|
147
|
-
const match = /^`(?<name>.+)`/.exec(tag.text)?.[1];
|
|
148
|
-
if (match) simplifiedType = match;
|
|
149
|
-
}
|
|
122
|
+
const tags = [];
|
|
123
|
+
for (const tag of prop.getJsDocTags()) {
|
|
124
|
+
if (!allowInternal && tag.getName() === "internal") return;
|
|
125
|
+
tags.push({
|
|
126
|
+
name: tag.getName(),
|
|
127
|
+
text: ts.displayPartsToString(tag.getText())
|
|
128
|
+
});
|
|
150
129
|
}
|
|
151
130
|
const entry = {
|
|
152
131
|
name: prop.getName(),
|
|
153
132
|
description: ts.displayPartsToString(prop.compilerSymbol.getDocumentationComment(program.getTypeChecker().compilerObject)),
|
|
154
133
|
tags,
|
|
155
|
-
type,
|
|
156
|
-
simplifiedType,
|
|
134
|
+
type: subType.getText(context.declaration, ts.TypeFormatFlags.UseAliasDefinedOutsideCurrentScope | ts.TypeFormatFlags.NoTruncation),
|
|
135
|
+
simplifiedType: getSimpleForm(subType, program.getTypeChecker(), isOptional, context.declaration),
|
|
157
136
|
required: !isOptional,
|
|
158
|
-
deprecated:
|
|
137
|
+
deprecated: false
|
|
159
138
|
};
|
|
139
|
+
for (const tag of tags) switch (tag.name) {
|
|
140
|
+
case "fumadocsType": {
|
|
141
|
+
const match = /`(?<name>.+)`$/.exec(tag.text)?.[1];
|
|
142
|
+
if (match) entry.type = match;
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
case "remarks": {
|
|
146
|
+
const match = /^`(?<name>.+)`/.exec(tag.text)?.[1];
|
|
147
|
+
if (match) entry.simplifiedType = match;
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
case "fumadocsHref": {
|
|
151
|
+
const content = tag.text.trim();
|
|
152
|
+
if (content.length > 0) entry.typeHref = content;
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
case "deprecated":
|
|
156
|
+
entry.deprecated = true;
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
160
159
|
transform?.call(context, entry, subType, prop);
|
|
161
160
|
return entry;
|
|
162
161
|
}
|
|
@@ -176,8 +175,8 @@ function objectBuilder() {
|
|
|
176
175
|
shorthand: false,
|
|
177
176
|
computed: false,
|
|
178
177
|
key: {
|
|
179
|
-
type: "
|
|
180
|
-
|
|
178
|
+
type: "Literal",
|
|
179
|
+
value: key
|
|
181
180
|
},
|
|
182
181
|
kind: "init",
|
|
183
182
|
value: expression
|
|
@@ -199,6 +198,7 @@ async function buildTypeProp(entries, renderer) {
|
|
|
199
198
|
node.addJsxProperty("type", await renderer.renderTypeToHast(entry.simplifiedType));
|
|
200
199
|
node.addJsxProperty("typeDescription", await renderer.renderTypeToHast(entry.type));
|
|
201
200
|
node.addExpressionNode("required", valueToEstree(entry.required));
|
|
201
|
+
if (entry.typeHref) node.addExpressionNode("typeDescriptionLink", valueToEstree(entry.typeHref));
|
|
202
202
|
if (tags.default) node.addJsxProperty("default", await renderer.renderTypeToHast(tags.default));
|
|
203
203
|
if (tags.returns) node.addJsxProperty("returns", await renderer.renderMarkdownToHast(tags.returns));
|
|
204
204
|
if (tags.params) node.addExpressionNode("parameters", {
|
|
@@ -239,55 +239,79 @@ function remarkAutoTypeTable(config = {}) {
|
|
|
239
239
|
if (renderMarkdown) renderer.renderMarkdownToHast = renderMarkdown;
|
|
240
240
|
if (renderType) renderer.renderTypeToHast = renderType;
|
|
241
241
|
}
|
|
242
|
+
async function generate(file, props, attributes) {
|
|
243
|
+
let basePath = props.cwd ? file.cwd : generateOptions.basePath;
|
|
244
|
+
if (file.dirname) basePath ??= file.dirname;
|
|
245
|
+
const output = await generator.generateTypeTable(props, {
|
|
246
|
+
...generateOptions,
|
|
247
|
+
basePath
|
|
248
|
+
});
|
|
249
|
+
const rendered = [];
|
|
250
|
+
for (const doc of output) rendered.push({
|
|
251
|
+
type: "mdxJsxFlowElement",
|
|
252
|
+
name: outputName,
|
|
253
|
+
attributes: [
|
|
254
|
+
{
|
|
255
|
+
type: "mdxJsxAttribute",
|
|
256
|
+
name: "id",
|
|
257
|
+
value: `type-table-${doc.id}`
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
type: "mdxJsxAttribute",
|
|
261
|
+
name: "type",
|
|
262
|
+
value: {
|
|
263
|
+
type: "mdxJsxAttributeValueExpression",
|
|
264
|
+
value: remarkStringify ? JSON.stringify(doc, null, 2) : "",
|
|
265
|
+
data: { estree: {
|
|
266
|
+
type: "Program",
|
|
267
|
+
sourceType: "module",
|
|
268
|
+
body: [{
|
|
269
|
+
type: "ExpressionStatement",
|
|
270
|
+
expression: await buildTypeProp(doc.entries, renderer)
|
|
271
|
+
}]
|
|
272
|
+
} }
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
...attributes
|
|
276
|
+
],
|
|
277
|
+
children: []
|
|
278
|
+
});
|
|
279
|
+
return rendered;
|
|
280
|
+
}
|
|
242
281
|
return async (tree, file) => {
|
|
243
282
|
const queue = [];
|
|
244
|
-
async function run(node, props) {
|
|
245
|
-
let basePath = props.cwd ? file.cwd : generateOptions.basePath;
|
|
246
|
-
if (file.dirname) basePath ??= file.dirname;
|
|
247
|
-
const rendered = (await generator.generateTypeTable(props, {
|
|
248
|
-
...generateOptions,
|
|
249
|
-
basePath
|
|
250
|
-
})).map(async (doc) => {
|
|
251
|
-
return {
|
|
252
|
-
type: "mdxJsxFlowElement",
|
|
253
|
-
name: outputName,
|
|
254
|
-
attributes: [{
|
|
255
|
-
type: "mdxJsxAttribute",
|
|
256
|
-
name: "type",
|
|
257
|
-
value: {
|
|
258
|
-
type: "mdxJsxAttributeValueExpression",
|
|
259
|
-
value: remarkStringify ? JSON.stringify(doc, null, 2) : "",
|
|
260
|
-
data: { estree: {
|
|
261
|
-
type: "Program",
|
|
262
|
-
sourceType: "module",
|
|
263
|
-
body: [{
|
|
264
|
-
type: "ExpressionStatement",
|
|
265
|
-
expression: await buildTypeProp(doc.entries, renderer)
|
|
266
|
-
}]
|
|
267
|
-
} }
|
|
268
|
-
}
|
|
269
|
-
}],
|
|
270
|
-
children: []
|
|
271
|
-
};
|
|
272
|
-
});
|
|
273
|
-
Object.assign(node, {
|
|
274
|
-
type: "root",
|
|
275
|
-
attributes: [],
|
|
276
|
-
children: await Promise.all(rendered)
|
|
277
|
-
});
|
|
278
|
-
}
|
|
279
283
|
visit(tree, "mdxJsxFlowElement", (node) => {
|
|
280
284
|
if (node.name !== name) return;
|
|
281
285
|
const props = {};
|
|
286
|
+
const attributes = [];
|
|
282
287
|
const onError = (message, cause) => {
|
|
283
288
|
const location = node.position ? `${file.path}:${node.position.start.line}:${node.position.start.column}` : file.path;
|
|
284
289
|
throw new Error(`${location} from <auto-type-table>: ${message}`, { cause });
|
|
285
290
|
};
|
|
286
|
-
for (const attr of node.attributes)
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
+
for (const attr of node.attributes) {
|
|
292
|
+
if (attr.type !== "mdxJsxAttribute") {
|
|
293
|
+
attributes.push(attr);
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
switch (attr.name) {
|
|
297
|
+
case "cwd":
|
|
298
|
+
props.cwd = true;
|
|
299
|
+
break;
|
|
300
|
+
case "path":
|
|
301
|
+
case "name":
|
|
302
|
+
case "type":
|
|
303
|
+
if (typeof attr.value === "string") props[attr.name] = attr.value;
|
|
304
|
+
else onError(`invalid type for attribute ${attr.name}: ${typeof attr.value}, expected: string`);
|
|
305
|
+
break;
|
|
306
|
+
default: attributes.push(attr);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
queue.push(generate(file, props, attributes).then((children) => {
|
|
310
|
+
Object.assign(node, {
|
|
311
|
+
type: "root",
|
|
312
|
+
children
|
|
313
|
+
});
|
|
314
|
+
}).catch((err) => {
|
|
291
315
|
onError("failed to generate type table", err);
|
|
292
316
|
}));
|
|
293
317
|
return "skip";
|
|
@@ -302,13 +326,11 @@ function createFileSystemGeneratorCache(dir) {
|
|
|
302
326
|
dir = path.resolve(dir);
|
|
303
327
|
const initDirPromise = fs.mkdir(dir, { recursive: true }).catch(() => {});
|
|
304
328
|
return {
|
|
305
|
-
async write(
|
|
306
|
-
const hash = createHash("SHA256").update(input).digest("hex").slice(0, 12);
|
|
329
|
+
async write(hash, data) {
|
|
307
330
|
await initDirPromise;
|
|
308
331
|
await fs.writeFile(path.join(dir, `${hash}.json`), JSON.stringify(data));
|
|
309
332
|
},
|
|
310
|
-
async read(
|
|
311
|
-
const hash = createHash("SHA256").update(input).digest("hex").slice(0, 12);
|
|
333
|
+
async read(hash) {
|
|
312
334
|
try {
|
|
313
335
|
return JSON.parse((await fs.readFile(path.join(dir, `${hash}.json`))).toString());
|
|
314
336
|
} catch {
|
|
@@ -319,4 +341,4 @@ function createFileSystemGeneratorCache(dir) {
|
|
|
319
341
|
}
|
|
320
342
|
|
|
321
343
|
//#endregion
|
|
322
|
-
export { createFileSystemGeneratorCache, createGenerator, createProject, remarkAutoTypeTable };
|
|
344
|
+
export { createFileSystemGeneratorCache, createGenerator, createProject, generateHash, remarkAutoTypeTable };
|
|
@@ -51,11 +51,13 @@ function parseTags(tags) {
|
|
|
51
51
|
continue;
|
|
52
52
|
}
|
|
53
53
|
if (key === "param") {
|
|
54
|
-
const
|
|
54
|
+
const sepIdx = text.indexOf("-");
|
|
55
|
+
const param = sepIdx === -1 ? text.trim() : text.slice(0, sepIdx).trim();
|
|
56
|
+
const description = sepIdx === -1 ? "" : text.slice(sepIdx + 1).trim();
|
|
55
57
|
typed.params ??= [];
|
|
56
58
|
typed.params.push({
|
|
57
|
-
name: param
|
|
58
|
-
description
|
|
59
|
+
name: param,
|
|
60
|
+
description
|
|
59
61
|
});
|
|
60
62
|
continue;
|
|
61
63
|
}
|
package/dist/ui/index.d.ts
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { f as BaseTypeTableProps, i as Generator, p as GenerateTypeTableOptions } from "../base-CLqyTLv7.js";
|
|
2
2
|
import * as runtime from "react/jsx-runtime";
|
|
3
3
|
import "server-only";
|
|
4
4
|
import { ResolvedShikiConfig } from "fumadocs-core/highlight/config";
|
|
5
|
-
import { ReactNode } from "react";
|
|
5
|
+
import { ComponentProps, ReactNode } from "react";
|
|
6
6
|
|
|
7
7
|
//#region src/ui/auto-type-table.d.ts
|
|
8
|
-
interface
|
|
9
|
-
renderMarkdown: (md: string) => Promise<ReactNode>;
|
|
10
|
-
renderType: (type: string) => Promise<ReactNode>;
|
|
11
|
-
}
|
|
12
|
-
interface AutoTypeTableProps extends BaseTypeTableProps, Partial<JSXMarkdownRenderer> {
|
|
8
|
+
interface AutoTypeTableProps extends BaseTypeTableProps, ComponentProps<'div'> {
|
|
13
9
|
generator: Generator;
|
|
14
10
|
/** Shiki configuration when using default `renderMarkdown` & `renderType` */
|
|
15
11
|
shiki?: ResolvedShikiConfig;
|
|
16
12
|
options?: GenerateTypeTableOptions;
|
|
13
|
+
renderMarkdown?: (md: string) => Promise<ReactNode>;
|
|
14
|
+
renderType?: (type: string) => Promise<ReactNode>;
|
|
17
15
|
}
|
|
18
16
|
declare function AutoTypeTable({
|
|
19
17
|
generator,
|
|
@@ -21,6 +19,9 @@ declare function AutoTypeTable({
|
|
|
21
19
|
renderType,
|
|
22
20
|
renderMarkdown,
|
|
23
21
|
shiki,
|
|
22
|
+
name,
|
|
23
|
+
path,
|
|
24
|
+
type,
|
|
24
25
|
...props
|
|
25
26
|
}: AutoTypeTableProps): Promise<Promise<runtime.JSX.Element>[]>;
|
|
26
27
|
//#endregion
|
package/dist/ui/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as markdownRenderer, t as parseTags } from "../parse-tags-
|
|
1
|
+
import { n as markdownRenderer, t as parseTags } from "../parse-tags-DMoo_pSD.js";
|
|
2
2
|
import { TypeTable } from "fumadocs-ui/components/type-table";
|
|
3
3
|
import { toJsxRuntime } from "hast-util-to-jsx-runtime";
|
|
4
4
|
import * as runtime from "react/jsx-runtime";
|
|
@@ -7,13 +7,17 @@ import defaultMdxComponents from "fumadocs-ui/mdx";
|
|
|
7
7
|
import "server-only";
|
|
8
8
|
|
|
9
9
|
//#region src/ui/auto-type-table.tsx
|
|
10
|
-
async function AutoTypeTable({ generator, options
|
|
10
|
+
async function AutoTypeTable({ generator, options, renderType, renderMarkdown, shiki, name, path, type, ...props }) {
|
|
11
11
|
if (!renderType || !renderMarkdown) {
|
|
12
12
|
const renderer = markdownRenderer(shiki);
|
|
13
13
|
renderType ??= async (v) => toJsx(await renderer.renderTypeToHast(v));
|
|
14
14
|
renderMarkdown ??= async (v) => toJsx(await renderer.renderMarkdownToHast(v));
|
|
15
15
|
}
|
|
16
|
-
return (await generator.generateTypeTable(
|
|
16
|
+
return (await generator.generateTypeTable({
|
|
17
|
+
name,
|
|
18
|
+
path,
|
|
19
|
+
type
|
|
20
|
+
}, options)).map(async (item) => {
|
|
17
21
|
const entries = item.entries.map(async (entry) => {
|
|
18
22
|
const tags = parseTags(entry.tags);
|
|
19
23
|
const paramNodes = [];
|
|
@@ -24,6 +28,7 @@ async function AutoTypeTable({ generator, options = {}, renderType, renderMarkdo
|
|
|
24
28
|
return [entry.name, {
|
|
25
29
|
type: await renderType(entry.simplifiedType),
|
|
26
30
|
typeDescription: await renderType(entry.type),
|
|
31
|
+
typeDescriptionLink: entry.typeHref,
|
|
27
32
|
description: await renderMarkdown(entry.description),
|
|
28
33
|
default: tags.default ? await renderType(tags.default) : void 0,
|
|
29
34
|
parameters: paramNodes,
|
|
@@ -32,7 +37,11 @@ async function AutoTypeTable({ generator, options = {}, renderType, renderMarkdo
|
|
|
32
37
|
returns: tags.returns ? await renderMarkdown(tags.returns) : void 0
|
|
33
38
|
}];
|
|
34
39
|
});
|
|
35
|
-
return /* @__PURE__ */ jsx(TypeTable, {
|
|
40
|
+
return /* @__PURE__ */ jsx(TypeTable, {
|
|
41
|
+
id: `type-table-${item.id}`,
|
|
42
|
+
type: Object.fromEntries(await Promise.all(entries)),
|
|
43
|
+
...props
|
|
44
|
+
}, item.name);
|
|
36
45
|
});
|
|
37
46
|
}
|
|
38
47
|
function toJsx(hast) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fumadocs-typescript",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.4",
|
|
4
4
|
"description": "Typescript Integration for Fumadocs",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Docs",
|
|
@@ -36,7 +36,6 @@
|
|
|
36
36
|
"hast-util-to-jsx-runtime": "^2.3.6",
|
|
37
37
|
"remark": "^15.0.1",
|
|
38
38
|
"remark-rehype": "^11.1.2",
|
|
39
|
-
"tinyglobby": "^0.2.15",
|
|
40
39
|
"ts-morph": "^27.0.2",
|
|
41
40
|
"unified": "^11.0.5",
|
|
42
41
|
"unist-util-visit": "^5.1.0"
|
|
@@ -46,14 +45,16 @@
|
|
|
46
45
|
"@types/estree": "^1.0.8",
|
|
47
46
|
"@types/hast": "^3.0.4",
|
|
48
47
|
"@types/mdast": "^4.0.4",
|
|
49
|
-
"@types/node": "25.2.
|
|
50
|
-
"@types/react": "^19.2.
|
|
48
|
+
"@types/node": "25.2.3",
|
|
49
|
+
"@types/react": "^19.2.14",
|
|
51
50
|
"@types/react-dom": "^19.2.3",
|
|
51
|
+
"mdast-util-mdx": "^3.0.0",
|
|
52
52
|
"tsdown": "^0.20.3",
|
|
53
53
|
"typescript": "^5.9.3",
|
|
54
|
+
"vfile": "^6.0.3",
|
|
54
55
|
"eslint-config-custom": "0.0.0",
|
|
55
|
-
"fumadocs-core": "16.5
|
|
56
|
-
"fumadocs-ui": "16.5
|
|
56
|
+
"fumadocs-core": "16.6.5",
|
|
57
|
+
"fumadocs-ui": "16.6.5",
|
|
57
58
|
"tsconfig": "0.0.0"
|
|
58
59
|
},
|
|
59
60
|
"peerDependencies": {
|