@kubb/ast 5.0.0-beta.61 → 5.0.0-beta.63
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/{defineMacro-BLIR6k-j.d.ts → defineMacro-BATi7xoC.d.ts} +11 -20
- package/dist/{defineMacro-Bv9R_9a2.cjs → defineMacro-CEZHaCXE.cjs} +13 -21
- package/dist/defineMacro-CEZHaCXE.cjs.map +1 -0
- package/dist/{defineMacro-BTXvS8nI.js → defineMacro-Shz8f6SG.js} +12 -19
- package/dist/defineMacro-Shz8f6SG.js.map +1 -0
- package/dist/factory.cjs +88 -28
- package/dist/factory.cjs.map +1 -0
- package/dist/factory.d.ts +6 -41
- package/dist/factory.js +58 -3
- package/dist/factory.js.map +1 -0
- package/dist/{index-BzjwdK2M.d.ts → index-B9cc8MBS.d.ts} +164 -194
- package/dist/index.cjs +144 -274
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +43 -37
- package/dist/index.js +109 -235
- package/dist/index.js.map +1 -1
- package/dist/macros.cjs +41 -28
- package/dist/macros.cjs.map +1 -1
- package/dist/macros.d.ts +14 -12
- package/dist/macros.js +34 -21
- package/dist/macros.js.map +1 -1
- package/dist/{operationParams-BZ07xDm0.d.ts → operationParams-k5CKwSWZ.d.ts} +9 -2
- package/dist/{visitor-DJ6ZEJvq.js → refs-BjNDuCBD.js} +116 -159
- package/dist/refs-BjNDuCBD.js.map +1 -0
- package/dist/{visitor-DpKZ9Tk0.cjs → refs-u5SDdyV7.cjs} +140 -195
- package/dist/refs-u5SDdyV7.cjs.map +1 -0
- package/dist/{response-hnSw2NKE.cjs → schema-BkvrrOAr.cjs} +496 -231
- package/dist/schema-BkvrrOAr.cjs.map +1 -0
- package/dist/{response-KUdWiDWw.js → schema-Cbnxmz4b.js} +472 -220
- package/dist/schema-Cbnxmz4b.js.map +1 -0
- package/dist/{types-DyDzizSf.d.ts → types-BB_xgRJ3.d.ts} +49 -123
- package/dist/types.d.ts +5 -6
- package/dist/{utils-BLJwyza-.cjs → utils-CEepwqmb.cjs} +76 -69
- package/dist/utils-CEepwqmb.cjs.map +1 -0
- package/dist/{utils-CF_-Pn_c.js → utils-DaXkewb1.js} +58 -51
- package/dist/utils-DaXkewb1.js.map +1 -0
- package/dist/utils.cjs +11 -11
- package/dist/utils.d.ts +53 -30
- package/dist/utils.js +3 -3
- package/package.json +1 -1
- package/src/constants.ts +3 -36
- package/src/defineMacro.ts +20 -13
- package/src/{node.ts → defineNode.ts} +12 -38
- package/src/{printer.ts → definePrinter.ts} +5 -3
- package/src/dialect.ts +52 -19
- package/src/factory.ts +7 -94
- package/src/index.ts +7 -9
- package/src/infer.ts +1 -1
- package/src/macros/macroDiscriminatorEnum.ts +7 -1
- package/src/macros/macroEnumName.ts +10 -2
- package/src/macros/macroSimplifyUnion.ts +29 -19
- package/src/nodes/code.ts +40 -80
- package/src/nodes/content.ts +2 -7
- package/src/nodes/file.ts +107 -18
- package/src/nodes/function.ts +46 -46
- package/src/nodes/index.ts +2 -3
- package/src/nodes/input.ts +13 -9
- package/src/nodes/operation.ts +8 -5
- package/src/nodes/output.ts +1 -1
- package/src/nodes/parameter.ts +5 -5
- package/src/nodes/property.ts +5 -5
- package/src/nodes/requestBody.ts +6 -13
- package/src/nodes/response.ts +93 -8
- package/src/nodes/schema.ts +5 -5
- package/src/optionality.ts +15 -0
- package/src/registry.ts +1 -1
- package/src/types.ts +4 -6
- package/src/utils/codegen.ts +6 -7
- package/src/utils/extractStringsFromNodes.ts +1 -0
- package/src/utils/fileMerge.ts +7 -8
- package/src/utils/operationParams.ts +9 -9
- package/src/utils/refs.ts +14 -18
- package/src/utils/schemaGraph.ts +41 -33
- package/src/utils/schemaMerge.ts +2 -2
- package/src/visitor.ts +3 -14
- package/dist/defineMacro-BTXvS8nI.js.map +0 -1
- package/dist/defineMacro-Bv9R_9a2.cjs.map +0 -1
- package/dist/extractStringsFromNodes-Cja-xxx5.js +0 -29
- package/dist/extractStringsFromNodes-Cja-xxx5.js.map +0 -1
- package/dist/extractStringsFromNodes-DKgDjFO0.cjs +0 -34
- package/dist/extractStringsFromNodes-DKgDjFO0.cjs.map +0 -1
- package/dist/extractStringsFromNodes-p4mX1TQD.d.ts +0 -14
- package/dist/factory-CZNOGI-N.js +0 -283
- package/dist/factory-CZNOGI-N.js.map +0 -1
- package/dist/factory-DG1CVkEb.cjs +0 -300
- package/dist/factory-DG1CVkEb.cjs.map +0 -1
- package/dist/response-KUdWiDWw.js.map +0 -1
- package/dist/response-hnSw2NKE.cjs.map +0 -1
- package/dist/utils-BLJwyza-.cjs.map +0 -1
- package/dist/utils-CF_-Pn_c.js.map +0 -1
- package/dist/visitor-DJ6ZEJvq.js.map +0 -1
- package/dist/visitor-DpKZ9Tk0.cjs.map +0 -1
- package/src/dedupe.ts +0 -239
- package/src/mocks.ts +0 -56
- package/src/nodes/http.ts +0 -85
package/src/dialect.ts
CHANGED
|
@@ -1,53 +1,86 @@
|
|
|
1
|
+
import type { Node } from './nodes/index.ts'
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* The spec-specific questions a schema parser answers while turning a source document into Kubb
|
|
3
5
|
* AST nodes. The rest of the pipeline is generic JSON Schema, so this is the one seam where
|
|
4
6
|
* OpenAPI, AsyncAPI, and plain JSON Schema differ.
|
|
5
7
|
*/
|
|
6
8
|
export type SchemaDialect<TSchema = unknown, TRef = TSchema, TDiscriminated = TSchema, TDocument = unknown> = {
|
|
7
|
-
/**
|
|
8
|
-
* Identifies the dialect in logs and diagnostics.
|
|
9
|
-
*/
|
|
10
|
-
name: string
|
|
11
9
|
/**
|
|
12
10
|
* Whether the schema is nullable.
|
|
13
11
|
*/
|
|
14
|
-
isNullable
|
|
12
|
+
isNullable(schema?: TSchema): boolean
|
|
15
13
|
/**
|
|
16
14
|
* Whether the value is a `$ref` pointer.
|
|
17
15
|
*/
|
|
18
|
-
isReference
|
|
16
|
+
isReference(value?: unknown): value is TRef
|
|
19
17
|
/**
|
|
20
18
|
* Whether the schema carries a discriminator for polymorphism.
|
|
21
19
|
*/
|
|
22
|
-
isDiscriminator
|
|
20
|
+
isDiscriminator(value?: unknown): value is TDiscriminated
|
|
23
21
|
/**
|
|
24
22
|
* Whether the schema is binary data, converted to a `blob` node.
|
|
25
23
|
*/
|
|
26
|
-
isBinary
|
|
24
|
+
isBinary(schema: TSchema): boolean
|
|
27
25
|
/**
|
|
28
26
|
* Resolves a local `$ref` against the document, or nullish when it cannot.
|
|
29
27
|
*/
|
|
30
|
-
resolveRef
|
|
28
|
+
resolveRef<TResolved>(document: TDocument, ref: string): TResolved | null | undefined
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* How a dialect collapses structurally identical schemas into shared definitions. The contract is
|
|
33
|
+
* generic over the plan and context types, which the adapter supplies. The mechanics live in the
|
|
34
|
+
* adapter, not here, so `@kubb/ast` carries no dedupe logic. The returned plan owns the rewriting
|
|
35
|
+
* behavior, so callers interact with one object.
|
|
36
|
+
*/
|
|
37
|
+
export type Dedupe<TPlan = unknown, TContext = unknown> = {
|
|
38
|
+
/**
|
|
39
|
+
* Scans a forest of nodes and produces a plan describing which shapes to share.
|
|
40
|
+
*/
|
|
41
|
+
plan(roots: ReadonlyArray<Node>, context: TContext): TPlan
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* A spec adapter's dialect. `name` identifies it in logs and diagnostics, `schema` holds the
|
|
46
|
+
* spec-specific schema questions the parser answers, and `dedupe` is the schema-sharing seam.
|
|
47
|
+
*/
|
|
48
|
+
export type Dialect<TSchema = unknown, TRef = TSchema, TDiscriminated = TSchema, TDocument = unknown, TDedupe extends Dedupe = Dedupe> = {
|
|
49
|
+
/**
|
|
50
|
+
* Identifies the dialect in logs and diagnostics.
|
|
51
|
+
*/
|
|
52
|
+
name: string
|
|
53
|
+
/**
|
|
54
|
+
* The spec-specific schema behavior. See {@link SchemaDialect}.
|
|
55
|
+
*/
|
|
56
|
+
schema: SchemaDialect<TSchema, TRef, TDiscriminated, TDocument>
|
|
57
|
+
/**
|
|
58
|
+
* The schema-sharing behavior. See {@link Dedupe}.
|
|
59
|
+
*/
|
|
60
|
+
dedupe: TDedupe
|
|
31
61
|
}
|
|
32
62
|
|
|
33
63
|
/**
|
|
34
|
-
* Types a {@link
|
|
64
|
+
* Types a {@link Dialect} for an adapter. Adds no runtime behavior and only pins the
|
|
35
65
|
* dialect's type for inference.
|
|
36
66
|
*
|
|
37
67
|
* @example
|
|
38
68
|
* ```ts
|
|
39
|
-
* export const oasDialect =
|
|
69
|
+
* export const oasDialect = defineDialect({
|
|
40
70
|
* name: 'oas',
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
71
|
+
* schema: {
|
|
72
|
+
* isNullable,
|
|
73
|
+
* isReference,
|
|
74
|
+
* isDiscriminator,
|
|
75
|
+
* isBinary: (schema) => schema.type === 'string' && schema.contentMediaType === 'application/octet-stream',
|
|
76
|
+
* resolveRef,
|
|
77
|
+
* },
|
|
78
|
+
* dedupe: { plan },
|
|
46
79
|
* })
|
|
47
80
|
* ```
|
|
48
81
|
*/
|
|
49
|
-
export function
|
|
50
|
-
dialect:
|
|
51
|
-
):
|
|
82
|
+
export function defineDialect<TSchema, TRef, TDiscriminated, TDocument, TDedupe extends Dedupe>(
|
|
83
|
+
dialect: Dialect<TSchema, TRef, TDiscriminated, TDocument, TDedupe>,
|
|
84
|
+
): Dialect<TSchema, TRef, TDiscriminated, TDocument, TDedupe> {
|
|
52
85
|
return dialect
|
|
53
86
|
}
|
package/src/factory.ts
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import path from 'node:path'
|
|
3
|
-
import { trimExtName } from '@internals/utils'
|
|
4
|
-
import type { FileNode, Node } from './nodes/index.ts'
|
|
5
|
-
import { extractStringsFromNodes } from './utils/extractStringsFromNodes.ts'
|
|
6
|
-
import { combineExports, combineImports, combineSources } from './utils/fileMerge.ts'
|
|
1
|
+
import type { Node } from './nodes/index.ts'
|
|
7
2
|
|
|
8
3
|
// Node constructors, grouped under the `factory` namespace the way the TypeScript compiler exposes
|
|
9
4
|
// `ts.factory.createX`. Aggregating them here lets `export * as factory from './factory.ts'` in the
|
|
10
5
|
// barrel surface every `createX` alongside the `createFile`/`update` helpers from a single module.
|
|
11
6
|
export { createArrowFunction, createBreak, createConst, createFunction, createJsx, createText, createType } from './nodes/code.ts'
|
|
12
7
|
export { createContent } from './nodes/content.ts'
|
|
13
|
-
export { createExport, createImport, createSource } from './nodes/file.ts'
|
|
8
|
+
export { createExport, createFile, createImport, createSource } from './nodes/file.ts'
|
|
9
|
+
export type { UserFileNode } from './nodes/file.ts'
|
|
14
10
|
export { createFunctionParameter, createFunctionParameters, createIndexedAccessType, createObjectBindingPattern, createTypeLiteral } from './nodes/function.ts'
|
|
15
11
|
export { createInput } from './nodes/input.ts'
|
|
16
12
|
export { createOperation } from './nodes/operation.ts'
|
|
@@ -26,10 +22,10 @@ export { createSchema } from './nodes/schema.ts'
|
|
|
26
22
|
* `changes` already equals (by reference) the current value, otherwise a new node
|
|
27
23
|
* with the changes applied.
|
|
28
24
|
*
|
|
29
|
-
* Mirrors the TypeScript compiler's `factory.updateX` contract
|
|
30
|
-
* structural sharing in {@link transform} so a no-op rewrite
|
|
31
|
-
* downstream passes can detect "nothing changed" by identity. Comparison is
|
|
32
|
-
*
|
|
25
|
+
* Mirrors the TypeScript compiler's `factory.updateX` contract. Pair it with the
|
|
26
|
+
* structural sharing in {@link transform} so a no-op rewrite does not allocate and
|
|
27
|
+
* downstream passes can detect "nothing changed" by identity. Comparison is shallow,
|
|
28
|
+
* so a structurally equal but newly allocated array or object counts as a change.
|
|
33
29
|
*
|
|
34
30
|
* @example
|
|
35
31
|
* ```ts
|
|
@@ -46,86 +42,3 @@ export function update<T extends Node>(node: T, changes: Partial<T>): T {
|
|
|
46
42
|
|
|
47
43
|
return node
|
|
48
44
|
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Input descriptor for {@link createFile}, before `id`, `name`, and `extname` are computed
|
|
52
|
-
* and `imports`/`exports`/`sources` are deduplicated.
|
|
53
|
-
*/
|
|
54
|
-
export type UserFileNode<TMeta extends object = object> = Omit<FileNode<TMeta>, 'kind' | 'id' | 'name' | 'extname' | 'imports' | 'exports' | 'sources'> &
|
|
55
|
-
Pick<Partial<FileNode<TMeta>>, 'imports' | 'exports' | 'sources'>
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Creates a fully resolved `FileNode` from a file input descriptor.
|
|
59
|
-
*
|
|
60
|
-
* Computes:
|
|
61
|
-
* - `id` SHA256 hash of the file path
|
|
62
|
-
* - `name` `baseName` without extension
|
|
63
|
-
* - `extname` extension extracted from `baseName`
|
|
64
|
-
*
|
|
65
|
-
* Deduplicates:
|
|
66
|
-
* - `sources` via `combineSources`
|
|
67
|
-
* - `exports` via `combineExports`
|
|
68
|
-
* - `imports` via `combineImports` (also filters unused imports)
|
|
69
|
-
*
|
|
70
|
-
* @throws {Error} when `baseName` has no extension.
|
|
71
|
-
*
|
|
72
|
-
* @example
|
|
73
|
-
* ```ts
|
|
74
|
-
* const file = createFile({
|
|
75
|
-
* baseName: 'petStore.ts',
|
|
76
|
-
* path: 'src/models/petStore.ts',
|
|
77
|
-
* sources: [createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')] })],
|
|
78
|
-
* imports: [createImport({ name: ['z'], path: 'zod' })],
|
|
79
|
-
* exports: [createExport({ name: ['Pet'], path: './petStore' })],
|
|
80
|
-
* })
|
|
81
|
-
* // file.id = SHA256 hash of 'src/models/petStore.ts'
|
|
82
|
-
* // file.name = 'petStore'
|
|
83
|
-
* // file.extname = '.ts'
|
|
84
|
-
* ```
|
|
85
|
-
*/
|
|
86
|
-
export function createFile<TMeta extends object = object>(input: UserFileNode<TMeta>): FileNode<TMeta> {
|
|
87
|
-
const rawExtname = path.extname(input.baseName)
|
|
88
|
-
// Handle dotfile basename like '.ts' where path.extname returns ''
|
|
89
|
-
const extname = (rawExtname || (input.baseName.startsWith('.') ? input.baseName : '')) as `.${string}`
|
|
90
|
-
if (!extname) {
|
|
91
|
-
throw new Error(`No extname found for ${input.baseName}`)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const source = (input.sources ?? [])
|
|
95
|
-
.flatMap((item) => item.nodes ?? [])
|
|
96
|
-
.map((node) => extractStringsFromNodes([node]))
|
|
97
|
-
.filter(Boolean)
|
|
98
|
-
.join('\n\n')
|
|
99
|
-
const resolvedExports = input.exports?.length ? combineExports(input.exports) : []
|
|
100
|
-
const combinedImports = input.imports?.length ? combineImports(input.imports, resolvedExports, source || undefined) : []
|
|
101
|
-
const localNames = new Set((input.sources ?? []).map((item) => item.name).filter((name): name is string => Boolean(name)))
|
|
102
|
-
const nameOf = (item: string | { propertyName: string; name?: string }): string => (typeof item === 'string' ? item : (item.name ?? item.propertyName))
|
|
103
|
-
// Drop self-imports. Consolidating output (`mode: 'file'`) can place a symbol's
|
|
104
|
-
// definition and a cross-file import of it in the same file. The first pass catches imports that
|
|
105
|
-
// resolve to this file's own path. The second drops imports of names the file already defines,
|
|
106
|
-
// the case consolidation produces when the import path no longer matches `input.path`. Sources
|
|
107
|
-
// stay intact, so the local definition remains. Bare specifiers like `'zod'` never match a path.
|
|
108
|
-
const resolvedImports = combinedImports
|
|
109
|
-
.filter((imp) => imp.path !== input.path)
|
|
110
|
-
.flatMap((imp) => {
|
|
111
|
-
if (!Array.isArray(imp.name)) {
|
|
112
|
-
return typeof imp.name === 'string' && localNames.has(imp.name) ? [] : [imp]
|
|
113
|
-
}
|
|
114
|
-
const kept = imp.name.filter((item) => !localNames.has(nameOf(item)))
|
|
115
|
-
if (!kept.length) return []
|
|
116
|
-
return [kept.length === imp.name.length ? imp : { ...imp, name: kept }]
|
|
117
|
-
})
|
|
118
|
-
const resolvedSources = input.sources?.length ? combineSources(input.sources) : []
|
|
119
|
-
|
|
120
|
-
return {
|
|
121
|
-
kind: 'File',
|
|
122
|
-
...input,
|
|
123
|
-
id: hash('sha256', input.path, 'hex'),
|
|
124
|
-
name: trimExtName(input.baseName),
|
|
125
|
-
extname,
|
|
126
|
-
imports: resolvedImports,
|
|
127
|
-
exports: resolvedExports,
|
|
128
|
-
sources: resolvedSources,
|
|
129
|
-
meta: input.meta ?? ({} as TMeta),
|
|
130
|
-
}
|
|
131
|
-
}
|
package/src/index.ts
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
3
|
-
export { defineSchemaDialect } from './dialect.ts'
|
|
4
|
-
export * as factory from './factory.ts'
|
|
1
|
+
export { schemaTypes } from './constants.ts'
|
|
2
|
+
export { defineDialect } from './dialect.ts'
|
|
5
3
|
export { isHttpOperationNode, narrowSchema } from './guards.ts'
|
|
6
4
|
export { applyMacros, composeMacros, defineMacro } from './defineMacro.ts'
|
|
7
|
-
export { defineNode } from './
|
|
8
|
-
export {
|
|
9
|
-
export
|
|
10
|
-
export { createPrinterFactory, definePrinter } from './printer.ts'
|
|
5
|
+
export { defineNode } from './defineNode.ts'
|
|
6
|
+
export { optionality } from './optionality.ts'
|
|
7
|
+
export { createPrinterFactory, definePrinter } from './definePrinter.ts'
|
|
11
8
|
export { signatureOf } from './signature.ts'
|
|
12
|
-
export { extractStringsFromNodes } from './utils/extractStringsFromNodes.ts'
|
|
13
9
|
export { collect, transform, walk } from './visitor.ts'
|
|
14
10
|
|
|
11
|
+
export * as factory from './factory.ts'
|
|
12
|
+
export * from './registry.ts'
|
|
15
13
|
export type * from './types.ts'
|
package/src/infer.ts
CHANGED
|
@@ -3,6 +3,12 @@ import { narrowSchema } from '../guards.ts'
|
|
|
3
3
|
import { createProperty } from '../nodes/property.ts'
|
|
4
4
|
import { createSchema } from '../nodes/schema.ts'
|
|
5
5
|
|
|
6
|
+
type Props = {
|
|
7
|
+
propertyName: string
|
|
8
|
+
values: Array<string>
|
|
9
|
+
enumName?: string
|
|
10
|
+
}
|
|
11
|
+
|
|
6
12
|
/**
|
|
7
13
|
* Builds a macro that replaces a discriminator property's schema with a string enum of the given
|
|
8
14
|
* values. Object schemas that lack the property are returned unchanged.
|
|
@@ -13,7 +19,7 @@ import { createSchema } from '../nodes/schema.ts'
|
|
|
13
19
|
* const next = applyMacros(objectSchema, [macro], { depth: 'shallow' })
|
|
14
20
|
* ```
|
|
15
21
|
*/
|
|
16
|
-
export function macroDiscriminatorEnum({ propertyName, values, enumName }:
|
|
22
|
+
export function macroDiscriminatorEnum({ propertyName, values, enumName }: Props) {
|
|
17
23
|
return defineMacro({
|
|
18
24
|
name: 'discriminator-enum',
|
|
19
25
|
schema(node) {
|
|
@@ -2,9 +2,15 @@ import { defineMacro } from '../defineMacro.ts'
|
|
|
2
2
|
import { narrowSchema } from '../guards.ts'
|
|
3
3
|
import { enumPropName } from '../utils/refs.ts'
|
|
4
4
|
|
|
5
|
+
type Props = {
|
|
6
|
+
parentName: string | null | undefined
|
|
7
|
+
propName: string
|
|
8
|
+
enumSuffix: string
|
|
9
|
+
}
|
|
10
|
+
|
|
5
11
|
/**
|
|
6
12
|
* Builds a macro that names an inline enum schema from its parent and property name. Boolean enums
|
|
7
|
-
* are left anonymous
|
|
13
|
+
* are left anonymous. Non-enum nodes are returned unchanged.
|
|
8
14
|
*
|
|
9
15
|
* @example
|
|
10
16
|
* ```ts
|
|
@@ -12,13 +18,15 @@ import { enumPropName } from '../utils/refs.ts'
|
|
|
12
18
|
* const named = applyMacros(propSchema, [macro], { depth: 'shallow' })
|
|
13
19
|
* ```
|
|
14
20
|
*/
|
|
15
|
-
export function macroEnumName({ parentName, propName, enumSuffix }:
|
|
21
|
+
export function macroEnumName({ parentName, propName, enumSuffix }: Props) {
|
|
16
22
|
return defineMacro({
|
|
17
23
|
name: 'enum-name',
|
|
18
24
|
schema(node) {
|
|
19
25
|
const enumNode = narrowSchema(node, 'enum')
|
|
26
|
+
|
|
20
27
|
if (enumNode?.primitive === 'boolean') return { ...node, name: null }
|
|
21
28
|
if (enumNode) return { ...node, name: enumPropName(parentName, propName, enumSuffix) }
|
|
29
|
+
|
|
22
30
|
return undefined
|
|
23
31
|
},
|
|
24
32
|
})
|
|
@@ -1,29 +1,17 @@
|
|
|
1
|
-
import { isScalarPrimitive } from '../constants.ts'
|
|
2
1
|
import { defineMacro } from '../defineMacro.ts'
|
|
3
2
|
import { narrowSchema } from '../guards.ts'
|
|
4
3
|
import type { SchemaNode } from '../nodes/schema.ts'
|
|
5
4
|
|
|
5
|
+
type ScalarPrimitive = 'string' | 'number' | 'integer' | 'bigint' | 'boolean'
|
|
6
|
+
|
|
6
7
|
/**
|
|
7
|
-
*
|
|
8
|
-
* sitting next to a plain `string`. Single-value enums are kept.
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* ```ts
|
|
12
|
-
* const next = applyMacros(unionSchema, [macroSimplifyUnion], { depth: 'shallow' })
|
|
13
|
-
* ```
|
|
8
|
+
* Scalar primitive schema types used for union simplification and type narrowing.
|
|
14
9
|
*/
|
|
15
|
-
|
|
16
|
-
name: 'simplify-union',
|
|
17
|
-
schema(node) {
|
|
18
|
-
const unionNode = narrowSchema(node, 'union')
|
|
19
|
-
if (!unionNode?.members?.length) return undefined
|
|
20
|
-
|
|
21
|
-
const simplified = simplifyUnionMembers(unionNode.members)
|
|
22
|
-
if (simplified.length === unionNode.members.length) return undefined
|
|
10
|
+
const SCALAR_PRIMITIVE_TYPES = new Set<ScalarPrimitive>(['string', 'number', 'integer', 'bigint', 'boolean'])
|
|
23
11
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
12
|
+
function isScalarPrimitive(type: string): type is ScalarPrimitive {
|
|
13
|
+
return SCALAR_PRIMITIVE_TYPES.has(type as ScalarPrimitive)
|
|
14
|
+
}
|
|
27
15
|
|
|
28
16
|
/**
|
|
29
17
|
* Filters union members, dropping enum members that a broader scalar primitive already covers.
|
|
@@ -48,3 +36,25 @@ function simplifyUnionMembers(members: Array<SchemaNode>): Array<SchemaNode> {
|
|
|
48
36
|
return true
|
|
49
37
|
})
|
|
50
38
|
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Removes union members a broader scalar primitive already covers, such as a multi-value string enum
|
|
42
|
+
* sitting next to a plain `string`. Single-value enums are kept.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts
|
|
46
|
+
* const next = applyMacros(unionSchema, [macroSimplifyUnion], { depth: 'shallow' })
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export const macroSimplifyUnion = defineMacro({
|
|
50
|
+
name: 'simplify-union',
|
|
51
|
+
schema(node) {
|
|
52
|
+
const unionNode = narrowSchema(node, 'union')
|
|
53
|
+
if (!unionNode?.members?.length) return undefined
|
|
54
|
+
|
|
55
|
+
const simplified = simplifyUnionMembers(unionNode.members)
|
|
56
|
+
if (simplified.length === unionNode.members.length) return undefined
|
|
57
|
+
|
|
58
|
+
return { ...unionNode, members: simplified }
|
|
59
|
+
},
|
|
60
|
+
})
|
package/src/nodes/code.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineNode } from '../
|
|
1
|
+
import { defineNode } from '../defineNode.ts'
|
|
2
2
|
import type { BaseNode } from './base.ts'
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -116,7 +116,10 @@ export type FunctionNode = BaseNode & {
|
|
|
116
116
|
*/
|
|
117
117
|
default?: boolean | null
|
|
118
118
|
/**
|
|
119
|
-
* Function parameter list
|
|
119
|
+
* Function parameter list as a pre-rendered string, written verbatim between the parentheses.
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* `'id: string, config: Config = {}'`
|
|
120
123
|
*/
|
|
121
124
|
params?: string | null
|
|
122
125
|
/**
|
|
@@ -164,55 +167,12 @@ export type FunctionNode = BaseNode & {
|
|
|
164
167
|
* // export const getPet = () => ...
|
|
165
168
|
* ```
|
|
166
169
|
*/
|
|
167
|
-
export type ArrowFunctionNode =
|
|
170
|
+
export type ArrowFunctionNode = Omit<FunctionNode, 'kind'> & {
|
|
168
171
|
kind: 'ArrowFunction'
|
|
169
|
-
/**
|
|
170
|
-
* Name of the arrow function (used as the `const` variable name).
|
|
171
|
-
*/
|
|
172
|
-
name: string
|
|
173
|
-
/**
|
|
174
|
-
* Whether the function is a default export.
|
|
175
|
-
*/
|
|
176
|
-
default?: boolean | null
|
|
177
|
-
/**
|
|
178
|
-
* Function parameter list rendered as a string (e.g. from `FunctionParams.toConstructor()`).
|
|
179
|
-
*/
|
|
180
|
-
params?: string | null
|
|
181
|
-
/**
|
|
182
|
-
* Whether the arrow function should be exported.
|
|
183
|
-
*/
|
|
184
|
-
export?: boolean | null
|
|
185
|
-
/**
|
|
186
|
-
* Whether the arrow function is async. When `true`, the return type is wrapped in `Promise<>`.
|
|
187
|
-
*/
|
|
188
|
-
async?: boolean | null
|
|
189
|
-
/**
|
|
190
|
-
* TypeScript generic type parameters.
|
|
191
|
-
*
|
|
192
|
-
* @example Constrained generics
|
|
193
|
-
* `['T', 'U extends string']`
|
|
194
|
-
*/
|
|
195
|
-
generics?: string | Array<string> | null
|
|
196
|
-
/**
|
|
197
|
-
* Return type annotation.
|
|
198
|
-
*
|
|
199
|
-
* @example Type reference
|
|
200
|
-
* `'Pet'`
|
|
201
|
-
*/
|
|
202
|
-
returnType?: string | null
|
|
203
|
-
/**
|
|
204
|
-
* JSDoc documentation metadata.
|
|
205
|
-
*/
|
|
206
|
-
JSDoc?: JSDocNode | null
|
|
207
172
|
/**
|
|
208
173
|
* Render the arrow function body as a single-line expression.
|
|
209
174
|
*/
|
|
210
175
|
singleLine?: boolean | null
|
|
211
|
-
/**
|
|
212
|
-
* Child nodes representing the function body (children of the `Function.Arrow` component).
|
|
213
|
-
* Each entry is a {@link CodeNode}. Use {@link TextNode} for raw string content.
|
|
214
|
-
*/
|
|
215
|
-
nodes?: Array<CodeNode>
|
|
216
176
|
}
|
|
217
177
|
|
|
218
178
|
/**
|
|
@@ -236,16 +196,16 @@ export type TextNode = BaseNode & {
|
|
|
236
196
|
}
|
|
237
197
|
|
|
238
198
|
/**
|
|
239
|
-
* AST node representing a line
|
|
199
|
+
* AST node representing a blank line in the source output.
|
|
240
200
|
*
|
|
241
|
-
* Corresponds to `<br/>` in JSX components.
|
|
242
|
-
*
|
|
201
|
+
* Corresponds to `<br/>` in JSX components. `printNodes` turns a `Break` between two
|
|
202
|
+
* statements into one blank line. Consecutive breaks, and breaks at the start or end of
|
|
203
|
+
* the list, are folded away, so a `Break` never produces more than one blank line.
|
|
243
204
|
*
|
|
244
205
|
* @example
|
|
245
206
|
* ```ts
|
|
246
207
|
* createBreak()
|
|
247
208
|
* // { kind: 'Break' }
|
|
248
|
-
* // prints as '' → blank line when surrounded by other nodes
|
|
249
209
|
* ```
|
|
250
210
|
*/
|
|
251
211
|
export type BreakNode = BaseNode & {
|
|
@@ -285,6 +245,36 @@ export type CodeNode = ConstNode | TypeNode | FunctionNode | ArrowFunctionNode |
|
|
|
285
245
|
*/
|
|
286
246
|
export const constDef = defineNode<ConstNode>({ kind: 'Const' })
|
|
287
247
|
|
|
248
|
+
/**
|
|
249
|
+
* Definition for the {@link TypeNode}.
|
|
250
|
+
*/
|
|
251
|
+
export const typeDef = defineNode<TypeNode>({ kind: 'Type' })
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Definition for the {@link FunctionNode}.
|
|
255
|
+
*/
|
|
256
|
+
export const functionDef = defineNode<FunctionNode>({ kind: 'Function' })
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Definition for the {@link ArrowFunctionNode}.
|
|
260
|
+
*/
|
|
261
|
+
export const arrowFunctionDef = defineNode<ArrowFunctionNode>({ kind: 'ArrowFunction' })
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Definition for the {@link TextNode}.
|
|
265
|
+
*/
|
|
266
|
+
export const textDef = defineNode<TextNode, string>({ kind: 'Text', build: (value) => ({ value }) })
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Definition for the {@link BreakNode}.
|
|
270
|
+
*/
|
|
271
|
+
export const breakDef = defineNode<BreakNode, void>({ kind: 'Break', build: () => ({}) })
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Definition for the {@link JsxNode}.
|
|
275
|
+
*/
|
|
276
|
+
export const jsxDef = defineNode<JsxNode, string>({ kind: 'Jsx', build: (value) => ({ value }) })
|
|
277
|
+
|
|
288
278
|
/**
|
|
289
279
|
* Creates a `ConstNode` representing a TypeScript `const` declaration.
|
|
290
280
|
*
|
|
@@ -296,11 +286,6 @@ export const constDef = defineNode<ConstNode>({ kind: 'Const' })
|
|
|
296
286
|
*/
|
|
297
287
|
export const createConst = constDef.create
|
|
298
288
|
|
|
299
|
-
/**
|
|
300
|
-
* Definition for the {@link TypeNode}.
|
|
301
|
-
*/
|
|
302
|
-
export const typeDef = defineNode<TypeNode>({ kind: 'Type' })
|
|
303
|
-
|
|
304
289
|
/**
|
|
305
290
|
* Creates a `TypeNode` representing a TypeScript `type` alias declaration.
|
|
306
291
|
*
|
|
@@ -312,11 +297,6 @@ export const typeDef = defineNode<TypeNode>({ kind: 'Type' })
|
|
|
312
297
|
*/
|
|
313
298
|
export const createType = typeDef.create
|
|
314
299
|
|
|
315
|
-
/**
|
|
316
|
-
* Definition for the {@link FunctionNode}.
|
|
317
|
-
*/
|
|
318
|
-
export const functionDef = defineNode<FunctionNode>({ kind: 'Function' })
|
|
319
|
-
|
|
320
300
|
/**
|
|
321
301
|
* Creates a `FunctionNode` representing a TypeScript `function` declaration.
|
|
322
302
|
*
|
|
@@ -328,11 +308,6 @@ export const functionDef = defineNode<FunctionNode>({ kind: 'Function' })
|
|
|
328
308
|
*/
|
|
329
309
|
export const createFunction = functionDef.create
|
|
330
310
|
|
|
331
|
-
/**
|
|
332
|
-
* Definition for the {@link ArrowFunctionNode}.
|
|
333
|
-
*/
|
|
334
|
-
export const arrowFunctionDef = defineNode<ArrowFunctionNode>({ kind: 'ArrowFunction' })
|
|
335
|
-
|
|
336
311
|
/**
|
|
337
312
|
* Creates an `ArrowFunctionNode` representing a TypeScript arrow function.
|
|
338
313
|
*
|
|
@@ -344,11 +319,6 @@ export const arrowFunctionDef = defineNode<ArrowFunctionNode>({ kind: 'ArrowFunc
|
|
|
344
319
|
*/
|
|
345
320
|
export const createArrowFunction = arrowFunctionDef.create
|
|
346
321
|
|
|
347
|
-
/**
|
|
348
|
-
* Definition for the {@link TextNode}.
|
|
349
|
-
*/
|
|
350
|
-
export const textDef = defineNode<TextNode, string>({ kind: 'Text', build: (value) => ({ value }) })
|
|
351
|
-
|
|
352
322
|
/**
|
|
353
323
|
* Creates a {@link TextNode} representing a raw string fragment in the source output.
|
|
354
324
|
*
|
|
@@ -360,11 +330,6 @@ export const textDef = defineNode<TextNode, string>({ kind: 'Text', build: (valu
|
|
|
360
330
|
*/
|
|
361
331
|
export const createText = textDef.create
|
|
362
332
|
|
|
363
|
-
/**
|
|
364
|
-
* Definition for the {@link BreakNode}.
|
|
365
|
-
*/
|
|
366
|
-
export const breakDef = defineNode<BreakNode, void>({ kind: 'Break', build: () => ({}) })
|
|
367
|
-
|
|
368
333
|
/**
|
|
369
334
|
* Creates a {@link BreakNode} representing a line break in the source output.
|
|
370
335
|
*
|
|
@@ -378,11 +343,6 @@ export function createBreak(): BreakNode {
|
|
|
378
343
|
return breakDef.create()
|
|
379
344
|
}
|
|
380
345
|
|
|
381
|
-
/**
|
|
382
|
-
* Definition for the {@link JsxNode}.
|
|
383
|
-
*/
|
|
384
|
-
export const jsxDef = defineNode<JsxNode, string>({ kind: 'Jsx', build: (value) => ({ value }) })
|
|
385
|
-
|
|
386
346
|
/**
|
|
387
347
|
* Creates a {@link JsxNode} representing a raw JSX fragment in the source output.
|
|
388
348
|
*
|
package/src/nodes/content.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineNode } from '../
|
|
1
|
+
import { defineNode } from '../defineNode.ts'
|
|
2
2
|
import type { BaseNode } from './base.ts'
|
|
3
3
|
import type { SchemaNode } from './schema.ts'
|
|
4
4
|
|
|
@@ -37,15 +37,10 @@ export type ContentNode = BaseNode & {
|
|
|
37
37
|
keysToOmit?: Array<string> | null
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
/**
|
|
41
|
-
* Loosely-typed content entry accepted by the builders, normalized into a {@link ContentNode}.
|
|
42
|
-
*/
|
|
43
|
-
export type UserContent = Omit<ContentNode, 'kind'>
|
|
44
|
-
|
|
45
40
|
/**
|
|
46
41
|
* Definition for the {@link ContentNode}.
|
|
47
42
|
*/
|
|
48
|
-
export const contentDef = defineNode<ContentNode
|
|
43
|
+
export const contentDef = defineNode<ContentNode>({
|
|
49
44
|
kind: 'Content',
|
|
50
45
|
children: ['schema'],
|
|
51
46
|
})
|