clanka 0.0.1
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/README.md +3 -0
- package/dist/Agent.d.ts +119 -0
- package/dist/Agent.d.ts.map +1 -0
- package/dist/Agent.js +240 -0
- package/dist/Agent.js.map +1 -0
- package/dist/AgentTools.d.ts +246 -0
- package/dist/AgentTools.d.ts.map +1 -0
- package/dist/AgentTools.js +374 -0
- package/dist/AgentTools.js.map +1 -0
- package/dist/AgentTools.test.d.ts +2 -0
- package/dist/AgentTools.test.d.ts.map +1 -0
- package/dist/AgentTools.test.js +147 -0
- package/dist/AgentTools.test.js.map +1 -0
- package/dist/ApplyPatch.d.ts +27 -0
- package/dist/ApplyPatch.d.ts.map +1 -0
- package/dist/ApplyPatch.js +343 -0
- package/dist/ApplyPatch.js.map +1 -0
- package/dist/ApplyPatch.test.d.ts +2 -0
- package/dist/ApplyPatch.test.d.ts.map +1 -0
- package/dist/ApplyPatch.test.js +99 -0
- package/dist/ApplyPatch.test.js.map +1 -0
- package/dist/Codex.d.ts +11 -0
- package/dist/Codex.d.ts.map +1 -0
- package/dist/Codex.js +14 -0
- package/dist/Codex.js.map +1 -0
- package/dist/CodexAuth.d.ts +68 -0
- package/dist/CodexAuth.d.ts.map +1 -0
- package/dist/CodexAuth.js +270 -0
- package/dist/CodexAuth.js.map +1 -0
- package/dist/CodexAuth.test.d.ts +2 -0
- package/dist/CodexAuth.test.d.ts.map +1 -0
- package/dist/CodexAuth.test.js +425 -0
- package/dist/CodexAuth.test.js.map +1 -0
- package/dist/Executor.d.ts +20 -0
- package/dist/Executor.d.ts.map +1 -0
- package/dist/Executor.js +76 -0
- package/dist/Executor.js.map +1 -0
- package/dist/OutputFormatter.d.ts +11 -0
- package/dist/OutputFormatter.d.ts.map +1 -0
- package/dist/OutputFormatter.js +5 -0
- package/dist/OutputFormatter.js.map +1 -0
- package/dist/ToolkitRenderer.d.ts +17 -0
- package/dist/ToolkitRenderer.d.ts.map +1 -0
- package/dist/ToolkitRenderer.js +25 -0
- package/dist/ToolkitRenderer.js.map +1 -0
- package/dist/TypeBuilder.d.ts +11 -0
- package/dist/TypeBuilder.d.ts.map +1 -0
- package/dist/TypeBuilder.js +383 -0
- package/dist/TypeBuilder.js.map +1 -0
- package/dist/TypeBuilder.test.d.ts +2 -0
- package/dist/TypeBuilder.test.d.ts.map +1 -0
- package/dist/TypeBuilder.test.js +243 -0
- package/dist/TypeBuilder.test.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/package.json +72 -0
- package/src/Agent.ts +398 -0
- package/src/AgentTools.test.ts +215 -0
- package/src/AgentTools.ts +507 -0
- package/src/ApplyPatch.test.ts +154 -0
- package/src/ApplyPatch.ts +473 -0
- package/src/Codex.ts +14 -0
- package/src/CodexAuth.test.ts +729 -0
- package/src/CodexAuth.ts +571 -0
- package/src/Executor.ts +129 -0
- package/src/OutputFormatter.ts +17 -0
- package/src/ToolkitRenderer.ts +39 -0
- package/src/TypeBuilder.test.ts +508 -0
- package/src/TypeBuilder.ts +670 -0
- package/src/index.ts +29 -0
|
@@ -0,0 +1,670 @@
|
|
|
1
|
+
import { Schema, SchemaAST as AST } from "effect"
|
|
2
|
+
|
|
3
|
+
const resolveDocumentation = AST.resolveAt<string>("documentation")
|
|
4
|
+
const identifierPattern = /^[$A-Z_a-z][$0-9A-Z_a-z]*$/u
|
|
5
|
+
|
|
6
|
+
const Precedence = {
|
|
7
|
+
Union: 0,
|
|
8
|
+
TypeOperator: 1,
|
|
9
|
+
Postfix: 2,
|
|
10
|
+
Primary: 3,
|
|
11
|
+
} as const
|
|
12
|
+
|
|
13
|
+
type Precedence = (typeof Precedence)[keyof typeof Precedence]
|
|
14
|
+
|
|
15
|
+
export type PrinterOptions = {
|
|
16
|
+
readonly newLine?: "\n" | "\r\n"
|
|
17
|
+
readonly omitTrailingSemicolon?: boolean
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type PrintableNode = {
|
|
21
|
+
readonly text: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type RenderContext = {
|
|
25
|
+
activeNodes: Set<AST.AST>
|
|
26
|
+
options: Required<PrinterOptions>
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
type RenderedType = PrintableNode & {
|
|
30
|
+
readonly precedence: Precedence
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
type TemplateLiteralSpan = {
|
|
34
|
+
readonly type: string
|
|
35
|
+
text: string
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
type TemplateLiteralState = {
|
|
39
|
+
head: string
|
|
40
|
+
currentText: string
|
|
41
|
+
spans: Array<TemplateLiteralSpan>
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const normalizeOptions = (
|
|
45
|
+
options?: PrinterOptions,
|
|
46
|
+
): Required<PrinterOptions> => ({
|
|
47
|
+
newLine: options?.newLine ?? "\n",
|
|
48
|
+
omitTrailingSemicolon: options?.omitTrailingSemicolon ?? false,
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
const indent = (level: number): string => " ".repeat(level)
|
|
52
|
+
|
|
53
|
+
const prefixFirstLine = (
|
|
54
|
+
text: string,
|
|
55
|
+
prefix: string,
|
|
56
|
+
newLine: string,
|
|
57
|
+
): string => {
|
|
58
|
+
const lines = text.split(newLine)
|
|
59
|
+
const [firstLine, ...restLines] = lines
|
|
60
|
+
|
|
61
|
+
return [prefix + (firstLine ?? ""), ...restLines].join(newLine)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const appendSuffix = (
|
|
65
|
+
text: string,
|
|
66
|
+
suffix: string,
|
|
67
|
+
newLine: string,
|
|
68
|
+
): string => {
|
|
69
|
+
if (suffix.length === 0) {
|
|
70
|
+
return text
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const lines = text.split(newLine)
|
|
74
|
+
const lastIndex = lines.length - 1
|
|
75
|
+
|
|
76
|
+
lines[lastIndex] = `${lines[lastIndex] ?? ""}${suffix}`
|
|
77
|
+
|
|
78
|
+
return lines.join(newLine)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const renderJsDoc = (
|
|
82
|
+
documentation: string,
|
|
83
|
+
indentLevel: number,
|
|
84
|
+
options: Required<PrinterOptions>,
|
|
85
|
+
): string => {
|
|
86
|
+
const safeDocumentation = documentation.replaceAll("*/", "*\\/")
|
|
87
|
+
const indentation = indent(indentLevel)
|
|
88
|
+
const lines = safeDocumentation.split(/\r?\n/u)
|
|
89
|
+
|
|
90
|
+
if (lines.length === 1) {
|
|
91
|
+
return `${indentation}/** ${lines[0]} */`
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return [
|
|
95
|
+
`${indentation}/**`,
|
|
96
|
+
...lines.map((line) => `${indentation} * ${line}`),
|
|
97
|
+
`${indentation} */`,
|
|
98
|
+
].join(options.newLine)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const parenthesize = (text: string): string => `(${text})`
|
|
102
|
+
|
|
103
|
+
const withParenthesesIfNeeded = (
|
|
104
|
+
rendered: RenderedType,
|
|
105
|
+
minimumPrecedence: Precedence,
|
|
106
|
+
): string =>
|
|
107
|
+
rendered.precedence < minimumPrecedence
|
|
108
|
+
? parenthesize(rendered.text)
|
|
109
|
+
: rendered.text
|
|
110
|
+
|
|
111
|
+
const unknownTypeNode = (): RenderedType => ({
|
|
112
|
+
text: "unknown",
|
|
113
|
+
precedence: Precedence.Primary,
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
const primitiveTypeNode = (keyword: string): RenderedType => ({
|
|
117
|
+
text: keyword,
|
|
118
|
+
precedence: Precedence.Primary,
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
const readonlyTypeNode = (rendered: RenderedType, context: RenderContext) => ({
|
|
122
|
+
text: prefixFirstLine(rendered.text, "readonly ", context.options.newLine),
|
|
123
|
+
precedence: Precedence.TypeOperator,
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
const nullTypeNode = (): RenderedType => ({
|
|
127
|
+
text: "null",
|
|
128
|
+
precedence: Precedence.Primary,
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
const stringLiteralTypeNode = (value: string): RenderedType => ({
|
|
132
|
+
text: JSON.stringify(value),
|
|
133
|
+
precedence: Precedence.Primary,
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
const referenceTypeNode = (
|
|
137
|
+
identifier: string,
|
|
138
|
+
typeArguments?: ReadonlyArray<RenderedType>,
|
|
139
|
+
): RenderedType => ({
|
|
140
|
+
text:
|
|
141
|
+
typeArguments === undefined || typeArguments.length === 0
|
|
142
|
+
? identifier
|
|
143
|
+
: `${identifier}<${typeArguments.map((type) => type.text).join(", ")}>`,
|
|
144
|
+
precedence: Precedence.Primary,
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
const cycleTypeNode = (ast: AST.AST): RenderedType => {
|
|
148
|
+
const visitedSuspends = new Set<AST.Suspend>()
|
|
149
|
+
let current: AST.AST = ast
|
|
150
|
+
|
|
151
|
+
while (true) {
|
|
152
|
+
const identifier = AST.resolveIdentifier(current)
|
|
153
|
+
|
|
154
|
+
if (identifier !== undefined) {
|
|
155
|
+
return referenceTypeNode(identifier)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (current._tag !== "Suspend" || visitedSuspends.has(current)) {
|
|
159
|
+
return unknownTypeNode()
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
visitedSuspends.add(current)
|
|
163
|
+
current = current.thunk()
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const literalText = (value: AST.Literal["literal"]): string => String(value)
|
|
168
|
+
|
|
169
|
+
const numberLiteralTypeNode = (value: number): RenderedType => ({
|
|
170
|
+
text: Object.is(value, -0) || value < 0 ? `-${-value}` : `${value}`,
|
|
171
|
+
precedence: Precedence.Primary,
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
const bigintLiteralTypeNode = (value: bigint): RenderedType => ({
|
|
175
|
+
text: value < 0n ? `-${-value}n` : `${value}n`,
|
|
176
|
+
precedence: Precedence.Primary,
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
const literalTypeNode = (ast: AST.Literal): RenderedType => {
|
|
180
|
+
switch (typeof ast.literal) {
|
|
181
|
+
case "string":
|
|
182
|
+
return stringLiteralTypeNode(ast.literal)
|
|
183
|
+
case "number":
|
|
184
|
+
return numberLiteralTypeNode(ast.literal)
|
|
185
|
+
case "boolean":
|
|
186
|
+
return primitiveTypeNode(ast.literal ? "true" : "false")
|
|
187
|
+
case "bigint":
|
|
188
|
+
return bigintLiteralTypeNode(ast.literal)
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const unionOfTypeNodes = (types: ReadonlyArray<RenderedType>): RenderedType => {
|
|
193
|
+
const [firstType, ...restTypes] = types
|
|
194
|
+
|
|
195
|
+
if (firstType === undefined) {
|
|
196
|
+
return primitiveTypeNode("never")
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
text:
|
|
201
|
+
restTypes.length === 0
|
|
202
|
+
? firstType.text
|
|
203
|
+
: types.map((type) => type.text).join(" | "),
|
|
204
|
+
precedence:
|
|
205
|
+
restTypes.length === 0 ? firstType.precedence : Precedence.Union,
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const uniqueSymbolTypeNode = (ast: AST.UniqueSymbol): RenderedType => {
|
|
210
|
+
const description = ast.symbol.description
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
text:
|
|
214
|
+
description === undefined
|
|
215
|
+
? "unique symbol"
|
|
216
|
+
: `typeof Symbol.for(${JSON.stringify(description)})`,
|
|
217
|
+
precedence: Precedence.TypeOperator,
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const symbolExpression = (symbol: symbol): string => {
|
|
222
|
+
const description = symbol.description
|
|
223
|
+
|
|
224
|
+
return description === undefined
|
|
225
|
+
? "Symbol()"
|
|
226
|
+
: `Symbol.for(${JSON.stringify(description)})`
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const propertyName = (name: PropertyKey): string => {
|
|
230
|
+
switch (typeof name) {
|
|
231
|
+
case "string":
|
|
232
|
+
return identifierPattern.test(name) ? name : JSON.stringify(name)
|
|
233
|
+
case "number":
|
|
234
|
+
return `${name}`
|
|
235
|
+
case "symbol":
|
|
236
|
+
return `[${symbolExpression(name)}]`
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const rootDocumentation = (ast: AST.AST): string | undefined => {
|
|
241
|
+
const visitedSuspends = new Set<AST.Suspend>()
|
|
242
|
+
let current: AST.AST = ast
|
|
243
|
+
|
|
244
|
+
while (true) {
|
|
245
|
+
const documentation = resolveDocumentation(current)
|
|
246
|
+
|
|
247
|
+
if (documentation !== undefined) {
|
|
248
|
+
return documentation
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (current._tag !== "Suspend" || visitedSuspends.has(current)) {
|
|
252
|
+
return undefined
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
visitedSuspends.add(current)
|
|
256
|
+
current = current.thunk()
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const propertySignatureTypeElement = (
|
|
261
|
+
propertySignature: AST.PropertySignature,
|
|
262
|
+
context: RenderContext,
|
|
263
|
+
indentLevel: number,
|
|
264
|
+
): string => {
|
|
265
|
+
const readonlyModifier =
|
|
266
|
+
propertySignature.type.context?.isMutable === true ? "" : "readonly "
|
|
267
|
+
const optionalMarker = AST.isOptional(propertySignature.type) ? "?" : ""
|
|
268
|
+
const propertyType = toTypeNode(propertySignature.type, context, indentLevel)
|
|
269
|
+
const propertyText = prefixFirstLine(
|
|
270
|
+
appendSuffix(
|
|
271
|
+
propertyType.text,
|
|
272
|
+
context.options.omitTrailingSemicolon ? "" : ";",
|
|
273
|
+
context.options.newLine,
|
|
274
|
+
),
|
|
275
|
+
`${indent(indentLevel)}${readonlyModifier}${propertyName(propertySignature.name)}${optionalMarker}: `,
|
|
276
|
+
context.options.newLine,
|
|
277
|
+
)
|
|
278
|
+
const documentation = resolveDocumentation(propertySignature.type)
|
|
279
|
+
|
|
280
|
+
return documentation === undefined
|
|
281
|
+
? propertyText
|
|
282
|
+
: `${renderJsDoc(documentation, indentLevel, context.options)}${context.options.newLine}${propertyText}`
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const indexSignatureTypeElement = (
|
|
286
|
+
indexSignature: AST.IndexSignature,
|
|
287
|
+
context: RenderContext,
|
|
288
|
+
indentLevel: number,
|
|
289
|
+
): string => {
|
|
290
|
+
const parameterType = toTypeNode(
|
|
291
|
+
indexSignature.parameter,
|
|
292
|
+
context,
|
|
293
|
+
indentLevel,
|
|
294
|
+
)
|
|
295
|
+
const valueType = toTypeNode(indexSignature.type, context, indentLevel)
|
|
296
|
+
|
|
297
|
+
return prefixFirstLine(
|
|
298
|
+
appendSuffix(
|
|
299
|
+
valueType.text,
|
|
300
|
+
context.options.omitTrailingSemicolon ? "" : ";",
|
|
301
|
+
context.options.newLine,
|
|
302
|
+
),
|
|
303
|
+
`${indent(indentLevel)}[x: ${parameterType.text}]: `,
|
|
304
|
+
context.options.newLine,
|
|
305
|
+
)
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const objectsTypeNode = (
|
|
309
|
+
ast: AST.Objects,
|
|
310
|
+
context: RenderContext,
|
|
311
|
+
indentLevel: number,
|
|
312
|
+
): RenderedType => {
|
|
313
|
+
const members = [
|
|
314
|
+
...ast.propertySignatures.map((propertySignature) =>
|
|
315
|
+
propertySignatureTypeElement(propertySignature, context, indentLevel + 1),
|
|
316
|
+
),
|
|
317
|
+
...ast.indexSignatures.map((indexSignature) =>
|
|
318
|
+
indexSignatureTypeElement(indexSignature, context, indentLevel + 1),
|
|
319
|
+
),
|
|
320
|
+
]
|
|
321
|
+
|
|
322
|
+
return {
|
|
323
|
+
text:
|
|
324
|
+
members.length === 0
|
|
325
|
+
? "{}"
|
|
326
|
+
: ["{", ...members, `${indent(indentLevel)}}`].join(
|
|
327
|
+
context.options.newLine,
|
|
328
|
+
),
|
|
329
|
+
precedence: Precedence.Primary,
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const unionTypeNode = (
|
|
334
|
+
ast: AST.Union,
|
|
335
|
+
context: RenderContext,
|
|
336
|
+
indentLevel: number,
|
|
337
|
+
): RenderedType =>
|
|
338
|
+
unionOfTypeNodes(
|
|
339
|
+
ast.types.map((type) => toTypeNode(type, context, indentLevel)),
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
const enumTypeNode = (ast: AST.Enum): RenderedType =>
|
|
343
|
+
unionOfTypeNodes(
|
|
344
|
+
ast.enums.map(([, value]) =>
|
|
345
|
+
typeof value === "string"
|
|
346
|
+
? stringLiteralTypeNode(value)
|
|
347
|
+
: numberLiteralTypeNode(value),
|
|
348
|
+
),
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
const pushTemplateLiteralInterpolation = (
|
|
352
|
+
state: TemplateLiteralState,
|
|
353
|
+
type: string,
|
|
354
|
+
): void => {
|
|
355
|
+
const lastSpan = state.spans[state.spans.length - 1]
|
|
356
|
+
|
|
357
|
+
if (lastSpan === undefined) {
|
|
358
|
+
state.head = state.currentText
|
|
359
|
+
} else {
|
|
360
|
+
lastSpan.text = state.currentText
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
state.spans.push({ type, text: "" })
|
|
364
|
+
state.currentText = ""
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const visitTemplateLiteralPart = (
|
|
368
|
+
state: TemplateLiteralState,
|
|
369
|
+
ast: AST.AST,
|
|
370
|
+
context: RenderContext,
|
|
371
|
+
indentLevel: number,
|
|
372
|
+
): void => {
|
|
373
|
+
switch (ast._tag) {
|
|
374
|
+
case "Literal":
|
|
375
|
+
state.currentText += literalText(ast.literal)
|
|
376
|
+
return
|
|
377
|
+
case "TemplateLiteral":
|
|
378
|
+
for (const part of ast.parts) {
|
|
379
|
+
visitTemplateLiteralPart(state, part, context, indentLevel)
|
|
380
|
+
}
|
|
381
|
+
return
|
|
382
|
+
default:
|
|
383
|
+
pushTemplateLiteralInterpolation(
|
|
384
|
+
state,
|
|
385
|
+
toTypeNode(ast, context, indentLevel).text,
|
|
386
|
+
)
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const escapeTemplateLiteralText = (text: string): string =>
|
|
391
|
+
text.replaceAll("\\", "\\\\").replaceAll("`", "\\`").replaceAll("${", "\\${")
|
|
392
|
+
|
|
393
|
+
const templateLiteralTypeNode = (
|
|
394
|
+
ast: AST.TemplateLiteral,
|
|
395
|
+
context: RenderContext,
|
|
396
|
+
indentLevel: number,
|
|
397
|
+
): RenderedType => {
|
|
398
|
+
const state: TemplateLiteralState = {
|
|
399
|
+
head: "",
|
|
400
|
+
currentText: "",
|
|
401
|
+
spans: [],
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
for (const part of ast.parts) {
|
|
405
|
+
visitTemplateLiteralPart(state, part, context, indentLevel)
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (state.spans.length === 0) {
|
|
409
|
+
return stringLiteralTypeNode(state.currentText)
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
const lastSpan = state.spans[state.spans.length - 1]
|
|
413
|
+
|
|
414
|
+
if (lastSpan !== undefined) {
|
|
415
|
+
lastSpan.text = state.currentText
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return {
|
|
419
|
+
text: `\`${escapeTemplateLiteralText(state.head)}${state.spans
|
|
420
|
+
.map((span) => `\${${span.type}}${escapeTemplateLiteralText(span.text)}`)
|
|
421
|
+
.join("")}\``,
|
|
422
|
+
precedence: Precedence.Primary,
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const stripOptionalTupleUndefined = (ast: AST.AST): AST.AST => {
|
|
427
|
+
if (!AST.isOptional(ast) || ast._tag !== "Union") {
|
|
428
|
+
return ast
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const definedTypes = ast.types.filter((type) => type._tag !== "Undefined")
|
|
432
|
+
const [definedType] = definedTypes
|
|
433
|
+
|
|
434
|
+
if (definedTypes.length === ast.types.length) {
|
|
435
|
+
return ast
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
return definedTypes.length === 1 && definedType !== undefined
|
|
439
|
+
? definedType
|
|
440
|
+
: new AST.Union(
|
|
441
|
+
definedTypes,
|
|
442
|
+
ast.mode,
|
|
443
|
+
ast.annotations,
|
|
444
|
+
ast.checks,
|
|
445
|
+
ast.encoding,
|
|
446
|
+
ast.context,
|
|
447
|
+
)
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
const tupleElementTypeNode = (
|
|
451
|
+
ast: AST.AST,
|
|
452
|
+
context: RenderContext,
|
|
453
|
+
indentLevel: number,
|
|
454
|
+
): string => {
|
|
455
|
+
const type = toTypeNode(
|
|
456
|
+
stripOptionalTupleUndefined(ast),
|
|
457
|
+
context,
|
|
458
|
+
indentLevel,
|
|
459
|
+
)
|
|
460
|
+
const optionalSuffix = AST.isOptional(ast) ? "?" : ""
|
|
461
|
+
const typeText = AST.isOptional(ast)
|
|
462
|
+
? withParenthesesIfNeeded(type, Precedence.TypeOperator)
|
|
463
|
+
: type.text
|
|
464
|
+
|
|
465
|
+
return prefixFirstLine(
|
|
466
|
+
appendSuffix(typeText, optionalSuffix, context.options.newLine),
|
|
467
|
+
indent(indentLevel),
|
|
468
|
+
context.options.newLine,
|
|
469
|
+
)
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
const restTupleElementTypeNode = (
|
|
473
|
+
ast: AST.AST,
|
|
474
|
+
context: RenderContext,
|
|
475
|
+
indentLevel: number,
|
|
476
|
+
): string => {
|
|
477
|
+
const type = toTypeNode(ast, context, indentLevel)
|
|
478
|
+
|
|
479
|
+
return prefixFirstLine(
|
|
480
|
+
appendSuffix(
|
|
481
|
+
withParenthesesIfNeeded(type, Precedence.Postfix),
|
|
482
|
+
"[]",
|
|
483
|
+
context.options.newLine,
|
|
484
|
+
),
|
|
485
|
+
`${indent(indentLevel)}...`,
|
|
486
|
+
context.options.newLine,
|
|
487
|
+
)
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
const arraysTypeNode = (
|
|
491
|
+
ast: AST.Arrays,
|
|
492
|
+
context: RenderContext,
|
|
493
|
+
indentLevel: number,
|
|
494
|
+
): RenderedType => {
|
|
495
|
+
const [restHead, ...restTail] = ast.rest
|
|
496
|
+
|
|
497
|
+
if (
|
|
498
|
+
ast.elements.length === 0 &&
|
|
499
|
+
ast.rest.length === 1 &&
|
|
500
|
+
restHead !== undefined
|
|
501
|
+
) {
|
|
502
|
+
const arrayType = toTypeNode(restHead, context, indentLevel)
|
|
503
|
+
const renderedArray = {
|
|
504
|
+
text: appendSuffix(
|
|
505
|
+
withParenthesesIfNeeded(arrayType, Precedence.Postfix),
|
|
506
|
+
"[]",
|
|
507
|
+
context.options.newLine,
|
|
508
|
+
),
|
|
509
|
+
precedence: Precedence.Postfix,
|
|
510
|
+
} satisfies RenderedType
|
|
511
|
+
|
|
512
|
+
return ast.isMutable
|
|
513
|
+
? renderedArray
|
|
514
|
+
: readonlyTypeNode(renderedArray, context)
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
const tupleMembers = [
|
|
518
|
+
...ast.elements.map((element) =>
|
|
519
|
+
tupleElementTypeNode(element, context, indentLevel + 1),
|
|
520
|
+
),
|
|
521
|
+
...(restHead === undefined
|
|
522
|
+
? []
|
|
523
|
+
: [
|
|
524
|
+
restTupleElementTypeNode(restHead, context, indentLevel + 1),
|
|
525
|
+
...restTail.map((element) =>
|
|
526
|
+
tupleElementTypeNode(element, context, indentLevel + 1),
|
|
527
|
+
),
|
|
528
|
+
]),
|
|
529
|
+
]
|
|
530
|
+
const tupleLines = tupleMembers.map((member, index) =>
|
|
531
|
+
appendSuffix(
|
|
532
|
+
member,
|
|
533
|
+
index === tupleMembers.length - 1 ? "" : ",",
|
|
534
|
+
context.options.newLine,
|
|
535
|
+
),
|
|
536
|
+
)
|
|
537
|
+
|
|
538
|
+
return {
|
|
539
|
+
text:
|
|
540
|
+
tupleLines.length === 0
|
|
541
|
+
? ast.isMutable
|
|
542
|
+
? "[]"
|
|
543
|
+
: "readonly []"
|
|
544
|
+
: [
|
|
545
|
+
ast.isMutable ? "[" : "readonly [",
|
|
546
|
+
...tupleLines,
|
|
547
|
+
`${indent(indentLevel)}]`,
|
|
548
|
+
].join(context.options.newLine),
|
|
549
|
+
precedence: ast.isMutable ? Precedence.Primary : Precedence.TypeOperator,
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
const declarationTypeNode = (
|
|
554
|
+
ast: AST.Declaration,
|
|
555
|
+
context: RenderContext,
|
|
556
|
+
indentLevel: number,
|
|
557
|
+
): RenderedType => {
|
|
558
|
+
const identifier = AST.resolveIdentifier(ast)
|
|
559
|
+
|
|
560
|
+
if (identifier === undefined) {
|
|
561
|
+
return unknownTypeNode()
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
const typeArguments = ast.typeParameters.map((typeParameter) =>
|
|
565
|
+
toTypeNode(typeParameter, context, indentLevel),
|
|
566
|
+
)
|
|
567
|
+
|
|
568
|
+
return referenceTypeNode(identifier, typeArguments)
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
const suspendTypeNode = (
|
|
572
|
+
ast: AST.Suspend,
|
|
573
|
+
context: RenderContext,
|
|
574
|
+
indentLevel: number,
|
|
575
|
+
): RenderedType => toTypeNode(ast.thunk(), context, indentLevel)
|
|
576
|
+
|
|
577
|
+
const toTypeNode = (
|
|
578
|
+
ast: AST.AST,
|
|
579
|
+
context: RenderContext,
|
|
580
|
+
indentLevel: number,
|
|
581
|
+
): RenderedType => {
|
|
582
|
+
if (context.activeNodes.has(ast)) {
|
|
583
|
+
return cycleTypeNode(ast)
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
context.activeNodes.add(ast)
|
|
587
|
+
|
|
588
|
+
try {
|
|
589
|
+
switch (ast._tag) {
|
|
590
|
+
case "String":
|
|
591
|
+
return primitiveTypeNode("string")
|
|
592
|
+
case "Number":
|
|
593
|
+
return primitiveTypeNode("number")
|
|
594
|
+
case "Boolean":
|
|
595
|
+
return primitiveTypeNode("boolean")
|
|
596
|
+
case "BigInt":
|
|
597
|
+
return primitiveTypeNode("bigint")
|
|
598
|
+
case "Symbol":
|
|
599
|
+
return primitiveTypeNode("symbol")
|
|
600
|
+
case "Any":
|
|
601
|
+
return primitiveTypeNode("any")
|
|
602
|
+
case "Unknown":
|
|
603
|
+
return unknownTypeNode()
|
|
604
|
+
case "Void":
|
|
605
|
+
return primitiveTypeNode("void")
|
|
606
|
+
case "Never":
|
|
607
|
+
return primitiveTypeNode("never")
|
|
608
|
+
case "Undefined":
|
|
609
|
+
return primitiveTypeNode("undefined")
|
|
610
|
+
case "Null":
|
|
611
|
+
return nullTypeNode()
|
|
612
|
+
case "ObjectKeyword":
|
|
613
|
+
return primitiveTypeNode("object")
|
|
614
|
+
case "Literal":
|
|
615
|
+
return literalTypeNode(ast)
|
|
616
|
+
case "UniqueSymbol":
|
|
617
|
+
return uniqueSymbolTypeNode(ast)
|
|
618
|
+
case "Declaration":
|
|
619
|
+
return declarationTypeNode(ast, context, indentLevel)
|
|
620
|
+
case "Enum":
|
|
621
|
+
return enumTypeNode(ast)
|
|
622
|
+
case "TemplateLiteral":
|
|
623
|
+
return templateLiteralTypeNode(ast, context, indentLevel)
|
|
624
|
+
case "Objects":
|
|
625
|
+
return objectsTypeNode(ast, context, indentLevel)
|
|
626
|
+
case "Arrays":
|
|
627
|
+
return arraysTypeNode(ast, context, indentLevel)
|
|
628
|
+
case "Union":
|
|
629
|
+
return unionTypeNode(ast, context, indentLevel)
|
|
630
|
+
case "Suspend":
|
|
631
|
+
return suspendTypeNode(ast, context, indentLevel)
|
|
632
|
+
default:
|
|
633
|
+
return unknownTypeNode()
|
|
634
|
+
}
|
|
635
|
+
} finally {
|
|
636
|
+
context.activeNodes.delete(ast)
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
export const printNode = (
|
|
641
|
+
node: PrintableNode,
|
|
642
|
+
_options?: PrinterOptions,
|
|
643
|
+
): string => node.text
|
|
644
|
+
|
|
645
|
+
export const render = (
|
|
646
|
+
schema: Schema.Top,
|
|
647
|
+
options?: PrinterOptions,
|
|
648
|
+
): string => {
|
|
649
|
+
const printerOptions = normalizeOptions(options)
|
|
650
|
+
const ast = AST.toType(schema.ast)
|
|
651
|
+
const rendered = toTypeNode(
|
|
652
|
+
ast,
|
|
653
|
+
{
|
|
654
|
+
activeNodes: new Set(),
|
|
655
|
+
options: printerOptions,
|
|
656
|
+
},
|
|
657
|
+
0,
|
|
658
|
+
)
|
|
659
|
+
const documentation = rootDocumentation(ast)
|
|
660
|
+
|
|
661
|
+
return printNode(
|
|
662
|
+
{
|
|
663
|
+
text:
|
|
664
|
+
documentation === undefined
|
|
665
|
+
? rendered.text
|
|
666
|
+
: `${renderJsDoc(documentation, 0, printerOptions)}${printerOptions.newLine}${rendered.text}`,
|
|
667
|
+
},
|
|
668
|
+
printerOptions,
|
|
669
|
+
)
|
|
670
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @since 1.0.0
|
|
3
|
+
*/
|
|
4
|
+
export * as Agent from "./Agent.ts"
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @since 1.0.0
|
|
8
|
+
*/
|
|
9
|
+
export * as AgentTools from "./AgentTools.ts"
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @since 1.0.0
|
|
13
|
+
*/
|
|
14
|
+
export * as Codex from "./Codex.ts"
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @since 1.0.0
|
|
18
|
+
*/
|
|
19
|
+
export * as Executor from "./Executor.ts"
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @since 1.0.0
|
|
23
|
+
*/
|
|
24
|
+
export * as ToolkitRenderer from "./ToolkitRenderer.ts"
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @since 1.0.0
|
|
28
|
+
*/
|
|
29
|
+
export * as TypeBuilder from "./TypeBuilder.ts"
|