Skip to content

Commit d3eef0f

Browse files
committed
New method of generative types???
1 parent c86f9d0 commit d3eef0f

7 files changed

Lines changed: 1579 additions & 640 deletions

File tree

actions/gls-action/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,8 @@
1111
"test": "vitest run",
1212
"start": "node dist/main.js",
1313
"docs:generate": "npm run build && node dist/generateTypes.js > ../../docs/Actions/GLS/types.mdx"
14+
},
15+
"dependencies": {
16+
"ts-morph": "^27.0.2"
1417
}
1518
}

actions/gls-action/scripts/generateTypes.ts

Lines changed: 124 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
HerculesActionConfigurationDefinition,
44
HerculesDataType, HerculesFlowType, HerculesRegisterFunctionParameter,
55
} from "@code0-tech/hercules";
6+
import {Project, SymbolFlags, Type} from "ts-morph";
67

78

89
const state = {
@@ -60,77 +61,162 @@ async function run() {
6061
}
6162

6263
run().then(async () => {
63-
let typeContent = `---
64+
console.log(`---
6465
title: Datatypes
6566
description: All data types registered by the GLS Action — field references and descriptions.
6667
---
68+
import {TypeTable} from "fumadocs-ui/components/type-table";
6769
6870
# GLS Action Types
6971
7072
The GLS Action registers the following data types with the Hercules platform. These types are used as inputs and outputs
7173
of the GLS functions and can be referenced in your flows.
7274
7375
---
74-
`
75-
76+
`)
7677
state.dataTypes.forEach(value => {
7778
value.type = `export type ${value.identifier} = ${value.type}`
7879
.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;
90116
}
91117

92-
return `/**
93-
@fumadocsHref #type-table-temp.ts-${gls}
94-
**/
95-
${name}: ${gls}`;
96-
}
97-
);
118+
let typeText: string;
98119

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}`;
104122

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);
113125

114-
`
115-
})
116-
typeContent = typeContent.replace(" | undefined", "")
126+
map[newName] = `export type ${newName} = ${nestedType};`;
127+
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` : "";
117139

118-
console.log(typeContent)
119-
})
140+
lines.push(
141+
`${docPrefix}${name}${symbol.hasFlags(SymbolFlags.Optional) ? "?" : ""}: ${typeText};`
142+
);
143+
});
120144

145+
return `{\n${lines.map(l => " " + l).join("\n")}\n}`;
146+
}
121147

148+
const finalType = buildType(rootType, typeName);
122149

150+
map[typeName] = `export type ${typeName} = ${finalType};`;
151+
152+
return map;
153+
}
123154

124155

156+
const broke = breakDown(value.identifier, value.type)
157+
const entries = Object.entries(broke).reverse();
125158

159+
for (const [key, val] of entries) {
160+
let typeString = `
161+
`
126162

163+
const project = new Project({useInMemoryFileSystem: true});
164+
const sourceFile = project.createSourceFile("example.ts", val);
127165

128166

167+
const typeAlias = sourceFile.getTypeAliasOrThrow(key);
129168

130169

170+
let type = typeAlias.getType()
171+
const array = typeAlias.getType().isArray()
172+
if (array) {
173+
type = type.getArrayElementTypeOrThrow()
174+
}
131175

176+
type.getProperties().forEach(property => {
177+
const name = property.getName();
132178

179+
const currType = property.getTypeAtLocation(typeAlias);
180+
const currTypeText = currType.getText();
133181

182+
const docs = {
183+
description: "No description set",
184+
deprecated: false,
185+
default: undefined,
186+
link: undefined
187+
}
134188

135189

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+
})
136221

222+
})

actions/gls-action/src/types/glsAddress.ts

Lines changed: 13 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,60 +4,42 @@ import {singleZodSchemaToTypescriptDef} from "../helpers";
44

55
export const AddressSchema = z.object({
66
Name1: z.string().max(40).describe(`
7-
Primary name line (person or company).
8-
Max 40 characters.
7+
@description Primary name line (person or company). Max 40 characters.
98
`),
109
Name2: z.string().max(40).optional().describe(`
11-
Optional second name line (e.g., department or additional identifier).
12-
Max 40 characters.
10+
@description Optional second name line (e.g., department or additional identifier). Max 40 characters.
1311
`), Name3: z.string().max(40).optional().describe(`
14-
Optional third name line for extended address details.
15-
Max 40 characters.
12+
@description Optional third name line for extended address details. Max 40 characters.
1613
`),
1714
CountryCode: z.string().max(2).describe(`
18-
Two-letter ISO country code (e.g., DE, US).
15+
@description Two-letter ISO country code (e.g., DE, US).
1916
`),
2017
Province: z.string().max(40).optional().describe(`
21-
State, province, or region.
22-
Optional field.
23-
Max 40 characters.
18+
@description State, province, or region. Optional field. Max 40 characters.
2419
`),
2520
City: z.string().max(40).describe(`
26-
City or locality name.
27-
Max 40 characters.
21+
@description City or locality name. Max 40 characters.
2822
`),
2923
Street: z.string().min(4).describe(`
30-
Street name.
31-
Minimum 4 characters required.
24+
@description Street name. Minimum 4 characters required.
3225
`),
3326
StreetNumber: z.string().max(40).optional().describe(`
34-
House or building number.
35-
Optional field.
36-
Max 40 characters.
27+
@description House or building number. Optional field. Max 40 characters.
3728
`),
3829
ContactPerson: z.string().max(40).min(6).optional().describe(`
39-
Full name of a contact person.
40-
Optional field.
41-
Must be between 6 and 40 characters.
30+
@description Full name of a contact person. Optional field. Must be between 6 and 40 characters.
4231
`),
4332
FixedLinePhonenumber: z.string().max(35).min(4).optional().describe(`
44-
Landline phone number.
45-
Optional field.
46-
Must be between 4 and 35 characters.
33+
@description Landline phone number. Optional field. Must be between 4 and 35 characters.
4734
`),
4835
MobilePhonenumber: z.string().max(35).min(4).optional().describe(`
49-
Mobile phone number.
50-
Optional field.
51-
Must be between 4 and 35 characters.
36+
@description Mobile phone number. Optional field. Must be between 4 and 35 characters.
5237
`),
5338
eMail: z.string().max(80).optional().describe(`
54-
Email address.
55-
Optional field.
56-
Max 80 characters.
39+
@description Email address. Optional field. Max 80 characters.
5740
`),
5841
ZIPCode: z.string().max(10).describe(`
59-
Postal or ZIP code.
60-
Max 10 characters.
42+
@description Postal or ZIP code. Max 10 characters.
6143
`),
6244
})
6345
export type AddressSchema = z.infer<typeof AddressSchema>

actions/gls-action/src/types/glsUnitService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {ActionSdk} from "@code0-tech/hercules";
55

66
export const UnitServiceSchema = z.array(z.object({
77
Cash: z.object({
8-
Reason: z.string().max(160),
8+
Reason: z.string().max(160).describe("@description Test"),
99
Amount: z.number().min(1),
1010
Currency: z.string().max(3).min(3)
1111
}).optional(),

0 commit comments

Comments
 (0)