@siemens/ix-docs 0.0.0-pr-2238-20251103095443
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/.turbo/turbo-build.log +500 -0
- package/CHANGELOG.md +7 -0
- package/LICENSE.md +9 -0
- package/README.md +5 -0
- package/package.json +33 -0
- package/scripts/build.ts +529 -0
- package/scripts/collector/collectAngularExamples.ts +50 -0
- package/scripts/collector/collectHTMLExamples.ts +29 -0
- package/scripts/collector/collectReactExamples.ts +33 -0
- package/scripts/collector/collectVueExamples.ts +30 -0
- package/scripts/collector/util.ts +111 -0
- package/scripts/templates/api.mustache +24 -0
- package/scripts/templates/event-table.mustache +21 -0
- package/scripts/templates/playground-files.mustache +25 -0
- package/scripts/templates/playground-markdown.mustache +25 -0
- package/scripts/templates/playground.mustache +14 -0
- package/scripts/templates/property-table.mustache +30 -0
- package/scripts/templates/slot-table.mustache +14 -0
- package/scripts/templates/tags.mustache +9 -0
- package/scripts/templates/usage.mustache +3 -0
- package/scripts/typedoc-generator.ts +307 -0
- package/scripts/utils/docs-tags.ts +43 -0
- package/scripts/utils/escape.ts +54 -0
- package/scripts/utils/string-utils.ts +7 -0
- package/tsconfig.json +17 -0
- package/version-deployment.json +16 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* SPDX-FileCopyrightText: 2025 Siemens AG
|
|
3
|
+
*
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the MIT license found in the
|
|
7
|
+
* LICENSE file in the root directory of this source tree.
|
|
8
|
+
*/
|
|
9
|
+
import fs from 'fs-extra';
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
|
|
12
|
+
export function getExampleNameFromRelativePath(relativeExamplePath: string) {
|
|
13
|
+
const lastSegment = relativeExamplePath.split('/').pop();
|
|
14
|
+
if (!lastSegment) {
|
|
15
|
+
throw new Error(`Invalid example path: ${relativeExamplePath}`);
|
|
16
|
+
}
|
|
17
|
+
return lastSegment.replace('.html', '');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/*
|
|
21
|
+
* Generic helpers to de-duplicate logic across framework example collectors.
|
|
22
|
+
*/
|
|
23
|
+
export type BuildExampleFn = (
|
|
24
|
+
exampleName: string,
|
|
25
|
+
relativeExamplePath: string
|
|
26
|
+
) => Promise<{ exampleName: string; example: string } | null>;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Read and parse the usage JSON file which maps component tags to arrays of example paths.
|
|
30
|
+
*/
|
|
31
|
+
export async function readUsageJson(
|
|
32
|
+
componentUsageJsonPath: string
|
|
33
|
+
): Promise<Record<string, string[]>> {
|
|
34
|
+
const exampleUsage = await fs.readFile(componentUsageJsonPath, 'utf-8');
|
|
35
|
+
return JSON.parse(exampleUsage) as Record<string, string[]>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Collect examples for a tag using a provided build function.
|
|
40
|
+
* The build function is responsible for locating files and returning a markdown body.
|
|
41
|
+
*/
|
|
42
|
+
export async function collectExamplesForTag(
|
|
43
|
+
usageJsonPath: string,
|
|
44
|
+
tag: string,
|
|
45
|
+
buildExample: BuildExampleFn
|
|
46
|
+
): Promise<string> {
|
|
47
|
+
const usage = await readUsageJson(usageJsonPath);
|
|
48
|
+
const examples = usage[tag];
|
|
49
|
+
|
|
50
|
+
if (!examples) {
|
|
51
|
+
console.log(`No examples found for ${tag}`);
|
|
52
|
+
return '';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const markdown: string[] = [];
|
|
56
|
+
|
|
57
|
+
for (const relativeExamplePath of examples) {
|
|
58
|
+
const exampleName = getExampleNameFromRelativePath(relativeExamplePath);
|
|
59
|
+
const built = await buildExample(exampleName, relativeExamplePath);
|
|
60
|
+
if (!built) continue; // build function logged reason (e.g., file not found)
|
|
61
|
+
markdown.push(
|
|
62
|
+
[`### Example: ${built.exampleName}`, built.example].join('\n')
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return markdown.join('\n\n');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Helper to read file content if it exists; returns null when missing.
|
|
71
|
+
*/
|
|
72
|
+
export async function readIfExists(filePath: string): Promise<string | null> {
|
|
73
|
+
if (!fs.existsSync(filePath)) return null;
|
|
74
|
+
return fs.readFile(filePath, 'utf-8');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Compose fenced code blocks conveniently.
|
|
79
|
+
*/
|
|
80
|
+
export function fenced(lang: string, code: string): string {
|
|
81
|
+
return ['```' + lang, code, '```'].join('\n');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Build an example made of multiple named sections (e.g., Typescript / HTML / CSS)
|
|
86
|
+
*/
|
|
87
|
+
export function sectionedExample(
|
|
88
|
+
sections: Array<{
|
|
89
|
+
heading: string;
|
|
90
|
+
lang: string;
|
|
91
|
+
code: string | null;
|
|
92
|
+
}>
|
|
93
|
+
): string {
|
|
94
|
+
return sections
|
|
95
|
+
.filter((s) => s.code)
|
|
96
|
+
.map((s) =>
|
|
97
|
+
[`#### ${s.heading}`, fenced(s.lang, s.code as string)].join('\n')
|
|
98
|
+
)
|
|
99
|
+
.join('\n');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Resolve a file by base name + extension inside a root directory.
|
|
104
|
+
*/
|
|
105
|
+
export function resolveExampleFile(
|
|
106
|
+
root: string,
|
|
107
|
+
exampleBaseName: string,
|
|
108
|
+
extension: string
|
|
109
|
+
): string {
|
|
110
|
+
return path.join(root, `${exampleBaseName}.${extension}`);
|
|
111
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {SinceTag, DeprecatedTag} from '@site/src/components/UI/Tags';
|
|
2
|
+
import FrameworkSelection from '@site/src/components/UI/FrameworkSelection';
|
|
3
|
+
import ApiTable from '@site/src/components/ApiTable';
|
|
4
|
+
import ReactMarkdown from 'react-markdown';
|
|
5
|
+
|
|
6
|
+
## API for {{ tag }}{{#singleFramework}} ({{{ framework }}}){{/singleFramework}}
|
|
7
|
+
|
|
8
|
+
{{#hasProps}}
|
|
9
|
+
### Properties
|
|
10
|
+
|
|
11
|
+
{{{ properties }}}
|
|
12
|
+
{{/hasProps}}
|
|
13
|
+
|
|
14
|
+
{{#hasEvents}}
|
|
15
|
+
### Events
|
|
16
|
+
|
|
17
|
+
{{{ events }}}
|
|
18
|
+
{{/hasEvents}}
|
|
19
|
+
|
|
20
|
+
{{#hasSlots}}
|
|
21
|
+
### Slot
|
|
22
|
+
|
|
23
|
+
{{{ slots }}}
|
|
24
|
+
{{/hasSlots}}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{{#events}}
|
|
2
|
+
<ApiTable id="event-{{event}}">
|
|
3
|
+
<ApiTable.EventHeader name="{{event}}">
|
|
4
|
+
{{#docsTags}}
|
|
5
|
+
{{{ rTag }}}
|
|
6
|
+
{{/docsTags}}
|
|
7
|
+
</ApiTable.EventHeader>
|
|
8
|
+
|
|
9
|
+
<ApiTable.Text name="Description">
|
|
10
|
+
<ReactMarkdown>{`{{{ docs }}}`}</ReactMarkdown>
|
|
11
|
+
</ApiTable.Text>
|
|
12
|
+
|
|
13
|
+
<ApiTable.Code name="Event">
|
|
14
|
+
{`{{{ event }}}`}
|
|
15
|
+
</ApiTable.Code>
|
|
16
|
+
|
|
17
|
+
<ApiTable.Code name="Detail">
|
|
18
|
+
{`{{{ detail }}}`}
|
|
19
|
+
</ApiTable.Code>
|
|
20
|
+
</ApiTable>
|
|
21
|
+
{{/events}}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
react: {
|
|
2
|
+
<%#react%>
|
|
3
|
+
'<%key%>': '<%{value}%>',
|
|
4
|
+
<%/react%>
|
|
5
|
+
},
|
|
6
|
+
angular: {
|
|
7
|
+
<%#angular%>
|
|
8
|
+
'<%key%>': '<%{value}%>',
|
|
9
|
+
<%/angular%>
|
|
10
|
+
},
|
|
11
|
+
angular_standalone: {
|
|
12
|
+
<%#angular_standalone%>
|
|
13
|
+
'<%key%>': '<%{value}%>',
|
|
14
|
+
<%/angular_standalone%>
|
|
15
|
+
},
|
|
16
|
+
vue: {
|
|
17
|
+
<%#vue%>
|
|
18
|
+
'<%key%>': '<%{value}%>',
|
|
19
|
+
<%/vue%>
|
|
20
|
+
},
|
|
21
|
+
html: {
|
|
22
|
+
<%#html%>
|
|
23
|
+
'<%key%>': '<%{value}%>',
|
|
24
|
+
<%/html%>
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
react: {
|
|
2
|
+
<%#reactMarkdown%>
|
|
3
|
+
'<%key%>': <%{value}%>,
|
|
4
|
+
<%/reactMarkdown%>
|
|
5
|
+
},
|
|
6
|
+
angular: {
|
|
7
|
+
<%#angularMarkdown%>
|
|
8
|
+
'<%key%>': <%{value}%>,
|
|
9
|
+
<%/angularMarkdown%>
|
|
10
|
+
},
|
|
11
|
+
angular_standalone: {
|
|
12
|
+
<%#angularStandaloneMarkdown%>
|
|
13
|
+
'<%key%>': <%{value}%>,
|
|
14
|
+
<%/angularStandaloneMarkdown%>
|
|
15
|
+
},
|
|
16
|
+
vue: {
|
|
17
|
+
<%#vueMarkdown%>
|
|
18
|
+
'<%key%>': <%{value}%>,
|
|
19
|
+
<%/vueMarkdown%>
|
|
20
|
+
},
|
|
21
|
+
html: {
|
|
22
|
+
<%#htmlMarkdown%>
|
|
23
|
+
'<%key%>': <%{value}%>,
|
|
24
|
+
<%/htmlMarkdown%>
|
|
25
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import Playground from '@site/src/components/Playground'
|
|
2
|
+
|
|
3
|
+
<%#imports%>
|
|
4
|
+
<%{.}%>
|
|
5
|
+
<%/imports%>
|
|
6
|
+
|
|
7
|
+
<Playground
|
|
8
|
+
name="<%name%>"
|
|
9
|
+
<%#isPreviewAvailable%>noPreview<%/isPreviewAvailable%>
|
|
10
|
+
source={{<%> markdown%>}}
|
|
11
|
+
files={{<%> files%>}}
|
|
12
|
+
height={props.height}
|
|
13
|
+
onlyFramework={props.onlyFramework}
|
|
14
|
+
></Playground>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{{#props}}
|
|
2
|
+
<ApiTable id="property-{{name}}">
|
|
3
|
+
<ApiTable.PropertyHeader name="{{name}}" singleFramework="{{singleFramework}}">
|
|
4
|
+
{{#docsTags}}
|
|
5
|
+
{{{ rTag }}}
|
|
6
|
+
{{/docsTags}}
|
|
7
|
+
</ApiTable.PropertyHeader>
|
|
8
|
+
|
|
9
|
+
<ApiTable.Text name="Description">
|
|
10
|
+
<ReactMarkdown>{`{{{ docs }}}`}</ReactMarkdown>
|
|
11
|
+
</ApiTable.Text>
|
|
12
|
+
|
|
13
|
+
{{#attr}}
|
|
14
|
+
<ApiTable.Code name="Attribute">
|
|
15
|
+
{`{{{ attr }}}`}
|
|
16
|
+
</ApiTable.Code>
|
|
17
|
+
{{/attr}}
|
|
18
|
+
|
|
19
|
+
<ApiTable.Code name="Type">
|
|
20
|
+
{`{{{ type }}}`}
|
|
21
|
+
</ApiTable.Code>
|
|
22
|
+
|
|
23
|
+
{{#default}}
|
|
24
|
+
<ApiTable.Code name="Default">
|
|
25
|
+
{`{{{ default }}}`}
|
|
26
|
+
</ApiTable.Code>
|
|
27
|
+
{{/default}}
|
|
28
|
+
|
|
29
|
+
</ApiTable>
|
|
30
|
+
{{/props}}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{{#slots}}
|
|
2
|
+
<ApiTable id="slot-{{name}}">
|
|
3
|
+
<ApiTable.SlotHeader name="{{name}}">
|
|
4
|
+
{{#docsTags}}
|
|
5
|
+
{{{ rTag }}}
|
|
6
|
+
{{/docsTags}}
|
|
7
|
+
</ApiTable.SlotHeader>
|
|
8
|
+
|
|
9
|
+
<ApiTable.Text name="Description">
|
|
10
|
+
<ReactMarkdown>{ `{{{ docs }}}` }</ReactMarkdown>
|
|
11
|
+
</ApiTable.Text>
|
|
12
|
+
</ApiTable>
|
|
13
|
+
{{/slots}}
|
|
14
|
+
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPDX-FileCopyrightText: 2024 Siemens AG
|
|
3
|
+
*
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the MIT license found in the
|
|
7
|
+
* LICENSE file in the root directory of this source tree.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import fs from 'fs-extra';
|
|
12
|
+
import Mustache from 'mustache';
|
|
13
|
+
import {
|
|
14
|
+
Application,
|
|
15
|
+
IntrinsicType,
|
|
16
|
+
ReferenceType,
|
|
17
|
+
TSConfigReader,
|
|
18
|
+
UnionType,
|
|
19
|
+
} from 'typedoc';
|
|
20
|
+
import { toKebabCase } from './utils/string-utils';
|
|
21
|
+
|
|
22
|
+
export type TypeDocTarget = {
|
|
23
|
+
name: string;
|
|
24
|
+
properties: TypeDocProperty[];
|
|
25
|
+
type: 'Function' | 'Type';
|
|
26
|
+
source: string;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export type TypeDocProperty = {
|
|
30
|
+
name: string;
|
|
31
|
+
defaultValue?: string;
|
|
32
|
+
type: string;
|
|
33
|
+
comment: string;
|
|
34
|
+
tags: Array<{ tag: string; text?: string }>;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
async function generateDocsForEntrypoint(
|
|
38
|
+
entrypoint: string,
|
|
39
|
+
targetPath: string
|
|
40
|
+
) {
|
|
41
|
+
const __root = path.resolve(__dirname, '../');
|
|
42
|
+
const __templates = path.join(__dirname, 'templates');
|
|
43
|
+
const tsconfig = path.join(
|
|
44
|
+
__dirname,
|
|
45
|
+
'..',
|
|
46
|
+
'..',
|
|
47
|
+
'..',
|
|
48
|
+
'tsconfig.typedoc.json'
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const app = await Application.bootstrap({
|
|
52
|
+
tsconfig: tsconfig,
|
|
53
|
+
skipErrorChecking: true,
|
|
54
|
+
entryPoints: [entrypoint],
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
app.options.addReader(new TSConfigReader());
|
|
58
|
+
|
|
59
|
+
const project = await app.convert();
|
|
60
|
+
|
|
61
|
+
if (!project) {
|
|
62
|
+
throw new Error(`No project generated for ${entrypoint}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const types = processProjectChildren(project, __root);
|
|
66
|
+
await generateTypeDocs(types, targetPath, __templates);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function getPropertyType(property: any): string {
|
|
70
|
+
if (property.type instanceof IntrinsicType) {
|
|
71
|
+
return property.type.name;
|
|
72
|
+
} else if (property.type instanceof ReferenceType) {
|
|
73
|
+
return property.type.qualifiedName;
|
|
74
|
+
} else if (property.type instanceof UnionType) {
|
|
75
|
+
return property.type.types
|
|
76
|
+
.filter((t: any) => 'name' in t)
|
|
77
|
+
.map((t: any) => t.name)
|
|
78
|
+
.join(' | ');
|
|
79
|
+
} else {
|
|
80
|
+
console.log(`=== Type ${property.name} is unknown`);
|
|
81
|
+
return 'unknown';
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function extractCommentTags(
|
|
86
|
+
property: any
|
|
87
|
+
): Array<{ tag: string; text?: string }> {
|
|
88
|
+
const tags: Array<{ tag: string; text?: string }> = [];
|
|
89
|
+
|
|
90
|
+
if (!property.comment?.blockTags) {
|
|
91
|
+
return tags;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
for (const tag of property.comment.blockTags) {
|
|
95
|
+
const tagName = tag.tag.substring(1); // Remove @ symbol
|
|
96
|
+
const tagText = tag.content
|
|
97
|
+
.filter((content: any) => content.kind === 'text')
|
|
98
|
+
.map((content: any) => content.text)
|
|
99
|
+
.join('');
|
|
100
|
+
|
|
101
|
+
tags.push({ tag: tagName, text: tagText });
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return tags;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function getCommentSummary(property: any): string {
|
|
108
|
+
const summary =
|
|
109
|
+
property?.comment?.summary ?? property?.signatures?.[0]?.comment?.summary;
|
|
110
|
+
|
|
111
|
+
if (summary) {
|
|
112
|
+
return summary
|
|
113
|
+
.filter((summary: any) => summary.kind === 'text')
|
|
114
|
+
.map((summary: any) => summary.text)
|
|
115
|
+
.join('');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return '';
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function processProperties(child: any): TypeDocProperty[] {
|
|
122
|
+
const properties: TypeDocProperty[] = [];
|
|
123
|
+
|
|
124
|
+
if (!child?.children) {
|
|
125
|
+
return properties;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
for (const property of child.children) {
|
|
129
|
+
const type = getPropertyType(property);
|
|
130
|
+
const tags = extractCommentTags(property);
|
|
131
|
+
const comment = getCommentSummary(property);
|
|
132
|
+
|
|
133
|
+
properties.push({
|
|
134
|
+
name: property.name,
|
|
135
|
+
defaultValue: property.defaultValue,
|
|
136
|
+
type,
|
|
137
|
+
comment,
|
|
138
|
+
tags,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return properties;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function processProjectChildren(
|
|
146
|
+
project: any,
|
|
147
|
+
rootPath: string
|
|
148
|
+
): TypeDocTarget[] {
|
|
149
|
+
const types: TypeDocTarget[] = [];
|
|
150
|
+
|
|
151
|
+
if (!project.children) {
|
|
152
|
+
return types;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
for (const child of project.children) {
|
|
156
|
+
const source = path.relative(rootPath, child.sources![0].fullFileName);
|
|
157
|
+
|
|
158
|
+
const properties = processProperties(child);
|
|
159
|
+
|
|
160
|
+
types.push({
|
|
161
|
+
name: child.name,
|
|
162
|
+
properties,
|
|
163
|
+
type: 'Type',
|
|
164
|
+
source,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return types;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function determineFramework(source: string): string | undefined {
|
|
172
|
+
const frameworks = ['react', 'angular', 'vue'];
|
|
173
|
+
|
|
174
|
+
for (const framework of frameworks) {
|
|
175
|
+
if (source.includes(framework)) {
|
|
176
|
+
return framework;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return undefined;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
async function generateTypeDocs(
|
|
184
|
+
types: TypeDocTarget[],
|
|
185
|
+
targetPath: string,
|
|
186
|
+
templatesPath: string
|
|
187
|
+
) {
|
|
188
|
+
const utilsPath = path.join(targetPath, 'utils');
|
|
189
|
+
await fs.ensureDir(utilsPath);
|
|
190
|
+
|
|
191
|
+
for (const typedoc of types) {
|
|
192
|
+
const current_framework = determineFramework(typedoc.source);
|
|
193
|
+
const mdxContent = generateStructuredMDX(
|
|
194
|
+
typedoc,
|
|
195
|
+
templatesPath,
|
|
196
|
+
current_framework
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
const outputPath = path.join(utilsPath, `${toKebabCase(typedoc.name)}.mdx`);
|
|
200
|
+
console.log(`Generating TypeDoc: ${outputPath}`);
|
|
201
|
+
await fs.writeFile(outputPath, mdxContent);
|
|
202
|
+
|
|
203
|
+
if (global.gc) {
|
|
204
|
+
global.gc();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function convertTagsToTSXElements(tags: Array<{ tag: string; text?: string }>) {
|
|
210
|
+
return tags
|
|
211
|
+
.map((tag) => {
|
|
212
|
+
if (tag.tag === 'deprecated') {
|
|
213
|
+
return {
|
|
214
|
+
rTag: `<DeprecatedTag message={\`${escapeBackticks(
|
|
215
|
+
tag.text || ''
|
|
216
|
+
)}\`} />`,
|
|
217
|
+
};
|
|
218
|
+
} else if (tag.tag === 'since') {
|
|
219
|
+
return {
|
|
220
|
+
rTag: `<SinceTag version={\`${escapeBackticks(tag.text || '')}\`} />`,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
return null;
|
|
224
|
+
})
|
|
225
|
+
.filter(Boolean);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function generateStructuredMDX(
|
|
229
|
+
typedoc: TypeDocTarget,
|
|
230
|
+
templatesPath: string,
|
|
231
|
+
framework?: string
|
|
232
|
+
): string {
|
|
233
|
+
const propertyTemplate = fs.readFileSync(
|
|
234
|
+
path.join(templatesPath, 'property-table.mustache'),
|
|
235
|
+
'utf-8'
|
|
236
|
+
);
|
|
237
|
+
const apiTemplate = fs.readFileSync(
|
|
238
|
+
path.join(templatesPath, 'api.mustache'),
|
|
239
|
+
'utf-8'
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
const kebabName = `ix-${toKebabCase(typedoc.name)}`;
|
|
243
|
+
|
|
244
|
+
const formattedProps = typedoc.properties.map((prop) => {
|
|
245
|
+
return {
|
|
246
|
+
name: prop.name,
|
|
247
|
+
singleFramework: framework,
|
|
248
|
+
docs: escapeBackticks(prop.comment),
|
|
249
|
+
type: escapeBackticks(prop.type),
|
|
250
|
+
default: prop.defaultValue
|
|
251
|
+
? escapeBackticks(prop.defaultValue)
|
|
252
|
+
: undefined,
|
|
253
|
+
attr: prop.name,
|
|
254
|
+
docsTags: convertTagsToTSXElements(prop.tags),
|
|
255
|
+
};
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
const propertyOutput = Mustache.render(propertyTemplate, {
|
|
259
|
+
tag: kebabName,
|
|
260
|
+
props: formattedProps,
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
return Mustache.render(apiTemplate, {
|
|
264
|
+
tag: kebabName,
|
|
265
|
+
hasProps: typedoc.properties.length > 0,
|
|
266
|
+
hasEvents: false,
|
|
267
|
+
hasSlots: false,
|
|
268
|
+
singleFramework: framework,
|
|
269
|
+
framework: framework?.charAt(0).toUpperCase()! + framework?.slice(1),
|
|
270
|
+
properties: propertyOutput,
|
|
271
|
+
events: '',
|
|
272
|
+
slots: '',
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function escapeBackticks(str: string): string {
|
|
277
|
+
if (!str) return '';
|
|
278
|
+
return str.replace(/`/g, '\\`');
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export async function generateTypeScriptDocs(
|
|
282
|
+
classPaths: string[],
|
|
283
|
+
targetPath: string
|
|
284
|
+
) {
|
|
285
|
+
console.log('Generating TypeScript API docs');
|
|
286
|
+
|
|
287
|
+
const BATCH_SIZE = 5;
|
|
288
|
+
const batches = [];
|
|
289
|
+
|
|
290
|
+
for (let i = 0; i < classPaths.length; i += BATCH_SIZE) {
|
|
291
|
+
batches.push(classPaths.slice(i, i + BATCH_SIZE));
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
for (let i = 0; i < batches.length; i++) {
|
|
295
|
+
const batch = batches[i];
|
|
296
|
+
console.log(
|
|
297
|
+
`Processing batch ${i + 1}/${batches.length} (${batch.length} files)`
|
|
298
|
+
);
|
|
299
|
+
for (const classPath of batch) {
|
|
300
|
+
await generateDocsForEntrypoint(classPath, targetPath);
|
|
301
|
+
|
|
302
|
+
if (global.gc) {
|
|
303
|
+
global.gc();
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* SPDX-FileCopyrightText: 2024 Siemens AG
|
|
3
|
+
*
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the MIT license found in the
|
|
7
|
+
* LICENSE file in the root directory of this source tree.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { escapeMarkdown } from './escape';
|
|
11
|
+
|
|
12
|
+
export function convertDocsTagsToTSXElement(
|
|
13
|
+
tagName: string,
|
|
14
|
+
docsTags: {
|
|
15
|
+
name: string;
|
|
16
|
+
text?: string;
|
|
17
|
+
}[]
|
|
18
|
+
) {
|
|
19
|
+
return docsTags.map((tag) => {
|
|
20
|
+
const { name, text } = tag;
|
|
21
|
+
const escapedText = escapeMarkdown(text ?? '').replace(/`/g, '\\`');
|
|
22
|
+
let template = '';
|
|
23
|
+
if (name === 'since') {
|
|
24
|
+
template = `<SinceTag message={\`${escapedText}\`} />`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (name === 'deprecated') {
|
|
28
|
+
template = `<DeprecatedTag message={\`${escapedText}\`} />`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (name === 'form-ready') {
|
|
32
|
+
template = `<FormReady message={\`${escapedText}\`} />`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (template === '') {
|
|
36
|
+
console.warn(`Unknown tag: ${name} within ${tagName}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
rTag: template,
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* SPDX-FileCopyrightText: 2024 Siemens AG
|
|
3
|
+
*
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the MIT license found in the
|
|
7
|
+
* LICENSE file in the root directory of this source tree.
|
|
8
|
+
*/
|
|
9
|
+
export function escapeMarkdown(markdown: string) {
|
|
10
|
+
let replacedMarkdown = markdown;
|
|
11
|
+
const replacemenets: [RegExp, string][] = [
|
|
12
|
+
[/`/g, '\\`'],
|
|
13
|
+
[/\*/g, '\\*'],
|
|
14
|
+
[/#/g, '\\#'],
|
|
15
|
+
[/\//g, '\\/'],
|
|
16
|
+
[/\(/g, '\\('],
|
|
17
|
+
[/\)/g, '\\)'],
|
|
18
|
+
[/\[/g, '\\['],
|
|
19
|
+
[/\]/g, '\\]'],
|
|
20
|
+
[/</g, '<'],
|
|
21
|
+
[/>/g, '>'],
|
|
22
|
+
[/_/g, '\\_'],
|
|
23
|
+
[/`/g, '\\`'],
|
|
24
|
+
[/\|/g, '\uff5c'],
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
replacemenets.forEach((replace) => {
|
|
28
|
+
const [source, target] = replace;
|
|
29
|
+
replacedMarkdown = markdown.replace(source, target);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
return replacedMarkdown;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function removeTypescriptHeaderComments(str: string) {
|
|
36
|
+
return str.replaceAll(/\/\*[\s\S]*?\*\//g, '');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function removeHTMLComments(str: string) {
|
|
40
|
+
return str.replaceAll(/<!--[\s\S]*?-->/g, '');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function parseJSDocsToMarkdown(str: string) {
|
|
44
|
+
const linkRegex = /{\@link (.*?)}/g;
|
|
45
|
+
const markdown = str.replaceAll(linkRegex, (_, url) => {
|
|
46
|
+
return `[${url}](${url})`;
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
return markdown;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function escapeBackticks(str: string) {
|
|
53
|
+
return str.replaceAll(/`/g, '\\`');
|
|
54
|
+
}
|