|
3 | 3 | HerculesActionConfigurationDefinition, |
4 | 4 | HerculesDataType, HerculesFlowType, HerculesRegisterFunctionParameter, |
5 | 5 | } from "@code0-tech/hercules"; |
| 6 | +import {Project, SymbolFlags, ts, Type, TypeFormatFlags} from "ts-morph"; |
6 | 7 |
|
7 | 8 |
|
8 | 9 | const state = { |
@@ -60,77 +61,172 @@ async function run() { |
60 | 61 | } |
61 | 62 |
|
62 | 63 | run().then(async () => { |
63 | | - let typeContent = `--- |
| 64 | + console.log(`--- |
64 | 65 | title: Datatypes |
65 | 66 | description: All data types registered by the GLS Action — field references and descriptions. |
66 | 67 | --- |
| 68 | +import {TypeTable} from "fumadocs-ui/components/type-table"; |
67 | 69 |
|
68 | 70 | # GLS Action Types |
69 | 71 |
|
70 | 72 | The GLS Action registers the following data types with the Hercules platform. These types are used as inputs and outputs |
71 | 73 | of the GLS functions and can be referenced in your flows. |
72 | 74 |
|
73 | 75 | --- |
74 | | - ` |
75 | | - |
| 76 | + `) |
76 | 77 | state.dataTypes.forEach(value => { |
77 | 78 | value.type = `export type ${value.identifier} = ${value.type}` |
78 | 79 | .replace(/ \| undefined/g, "") |
79 | | - .replace(/\/\*\*/g, "/**\n") |
80 | | - .replace(/\*\//g, "\n**/") |
81 | | - .replace( |
82 | | - /(\w+)(\?)?:\s*(GLS_\w+);/g, |
83 | | - (match, name, optionalMark, gls) => { |
84 | | - if (optionalMark) { |
85 | | - return `/** |
86 | | - Optional. |
87 | | - @fumadocsHref #type-table-temp.ts-${gls} |
88 | | -**/ |
89 | | -${name}: ${gls}`; |
| 80 | + |
| 81 | + |
| 82 | + function breakDown( |
| 83 | + typeName: string, |
| 84 | + code: string |
| 85 | + ): Record<string, string> { |
| 86 | + const map: Record<string, string> = {}; |
| 87 | + |
| 88 | + const project = new Project({useInMemoryFileSystem: true}); |
| 89 | + const sourceFile = project.createSourceFile("example.ts", code); |
| 90 | + |
| 91 | + const typeAlias = sourceFile.getTypeAliasOrThrow(typeName); |
| 92 | + let rootType = typeAlias.getType(); |
| 93 | + |
| 94 | + if (rootType.isArray()) { |
| 95 | + rootType = rootType.getArrayElementTypeOrThrow(); |
| 96 | + } |
| 97 | + |
| 98 | + function buildType(type: Type, currentName: string): string { |
| 99 | + const props = type.getProperties(); |
| 100 | + |
| 101 | + const lines: string[] = []; |
| 102 | + |
| 103 | + props.forEach(symbol => { |
| 104 | + const name = symbol.getName(); |
| 105 | + const decl = symbol.getDeclarations()[0]; |
| 106 | + if (!decl) return; |
| 107 | + |
| 108 | + |
| 109 | + let propType = symbol.getTypeAtLocation(decl); |
| 110 | + |
| 111 | + // unwrap arrays |
| 112 | + let isArray = false; |
| 113 | + if (propType.isArray()) { |
| 114 | + propType = propType.getArrayElementTypeOrThrow(); |
| 115 | + isArray = true; |
90 | 116 | } |
91 | 117 |
|
92 | | - return `/** |
93 | | - @fumadocsHref #type-table-temp.ts-${gls} |
94 | | -**/ |
95 | | -${name}: ${gls}`; |
96 | | - } |
97 | | - ); |
| 118 | + let typeText: string; |
98 | 119 |
|
99 | | - let array = false |
100 | | - if (value.type.endsWith("[];")) { |
101 | | - value.type = value.type.slice(0, -3) + ";" |
102 | | - array = true |
103 | | - } |
| 120 | + if (propType.getText().startsWith("{")) { |
| 121 | + const newName = `${currentName}$${name}`; |
104 | 122 |
|
105 | | - typeContent += ` |
106 | | -# ${value.identifier}${array ? " (array)" : ""} |
107 | | - |
108 | | -<AutoTypeTable type={\` |
109 | | - |
110 | | -${value.type} |
111 | | - |
112 | | -\`} name="${value.identifier}"/> |
| 123 | + // recurse first |
| 124 | + const nestedType = buildType(propType, newName); |
113 | 125 |
|
114 | | -` |
115 | | - }) |
116 | | - typeContent = typeContent.replace(" | undefined", "") |
| 126 | + map[newName] = `export type ${newName} = ${nestedType};`; |
117 | 127 |
|
118 | | - console.log(typeContent) |
119 | | -}) |
| 128 | + typeText = isArray ? `${newName}[]` : newName; |
| 129 | + } else { |
| 130 | + typeText = propType.getText(decl); |
| 131 | + } |
| 132 | + |
| 133 | + // JSDoc |
| 134 | + const jsDocs = (decl as any).getJsDocs?.() |
| 135 | + ?.map(d => d.getText()) |
| 136 | + .join("\n"); |
| 137 | + |
| 138 | + const docPrefix = jsDocs ? `${jsDocs}\n` : ""; |
120 | 139 |
|
| 140 | + lines.push( |
| 141 | + `${docPrefix}${name}${symbol.hasFlags(SymbolFlags.Optional) ? "?" : ""}: ${typeText};` |
| 142 | + ); |
| 143 | + }); |
121 | 144 |
|
| 145 | + return `{\n${lines.map(l => " " + l).join("\n")}\n}`; |
| 146 | + } |
122 | 147 |
|
| 148 | + const finalType = buildType(rootType, typeName); |
123 | 149 |
|
| 150 | + map[typeName] = `export type ${typeName} = ${finalType};`; |
| 151 | + |
| 152 | + return map; |
| 153 | + } |
124 | 154 |
|
125 | 155 |
|
| 156 | + const broke = breakDown(value.identifier, value.type) |
| 157 | + const entries = Object.entries(broke).reverse(); |
126 | 158 |
|
| 159 | + for (let [key, val] of entries) { |
| 160 | + let typeString = ` |
| 161 | + ` |
127 | 162 |
|
| 163 | + const project = new Project({useInMemoryFileSystem: true}); |
| 164 | + const sourceFile = project.createSourceFile("example.ts", val); |
128 | 165 |
|
129 | 166 |
|
| 167 | + let typeAlias = sourceFile.getTypeAliasOrThrow(key); |
130 | 168 |
|
131 | 169 |
|
| 170 | + let type = typeAlias.getType() |
| 171 | + let array = typeAlias.getType().isArray() |
| 172 | + if (array) { |
| 173 | + type = type.getArrayElementTypeOrThrow() |
| 174 | + } |
132 | 175 |
|
| 176 | + type.getProperties().forEach(property => { |
| 177 | + const name = property.getName(); |
133 | 178 |
|
| 179 | + let currType = property.getTypeAtLocation(typeAlias); |
| 180 | + let currTypeText = currType.getText(); |
134 | 181 |
|
| 182 | + const docs = { |
| 183 | + description: "No description set", |
| 184 | + deprecated: false, |
| 185 | + default: undefined, |
| 186 | + link: undefined |
| 187 | + } |
135 | 188 |
|
136 | 189 |
|
| 190 | + property.getJsDocTags().forEach(info => { |
| 191 | + info.getText().forEach(part => { |
| 192 | + docs[info.getName()] = part.text.trim() |
| 193 | + }) |
| 194 | + }) |
| 195 | + if (currTypeText.startsWith("GLS_")) { |
| 196 | + docs.link = currTypeText.toLowerCase() |
| 197 | + .replace(/-/g, "_") |
| 198 | + .replace(/\$/g, "") |
| 199 | + .replace("[]", "") |
| 200 | + } |
| 201 | + typeString += `${name}: { |
| 202 | + description: '${docs.description}', |
| 203 | + deprecated: ${docs.deprecated}, |
| 204 | + required: ${!property.isOptional()}, ${docs.link ? `\ntypeDescriptionLink: '#${docs.link}',` : ""} |
| 205 | + type: '${currTypeText}', ${docs.default ? `\ndefault: ${docs.default}` : ""} |
| 206 | + }, |
| 207 | + ` |
| 208 | + |
| 209 | + }) |
| 210 | + |
| 211 | + const table = `<TypeTable type={{${typeString}}} |
| 212 | +/>` |
| 213 | + console.log(`# ${key}`) |
| 214 | + console.log(table) |
| 215 | + } |
| 216 | + // console.log(` |
| 217 | +// # ${value.identifier} ${array ? "[]" : ""} |
| 218 | +// `) |
| 219 | +// console.log(table) |
| 220 | + }) |
| 221 | + |
| 222 | +}) |
| 223 | +function reverseRecord(obj: Record<string, string>) { |
| 224 | + const result: Record<string, string> = {}; |
| 225 | + |
| 226 | + for (const key in obj) { |
| 227 | + const value = obj[key]; |
| 228 | + result[value] = key; |
| 229 | + } |
| 230 | + |
| 231 | + return result; |
| 232 | +} |
0 commit comments