@kubb/ast 5.0.0-beta.61 → 5.0.0-beta.62
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-Bv9R_9a2.cjs → defineMacro-BryDiuQl.cjs} +12 -20
- package/dist/defineMacro-BryDiuQl.cjs.map +1 -0
- package/dist/{defineMacro-BTXvS8nI.js → defineMacro-CNkUpxia.js} +12 -19
- package/dist/defineMacro-CNkUpxia.js.map +1 -0
- package/dist/{defineMacro-BLIR6k-j.d.ts → defineMacro-Vw-xQvq7.d.ts} +9 -17
- package/dist/factory.cjs +64 -4
- package/dist/factory.cjs.map +1 -0
- package/dist/factory.d.ts +2 -37
- package/dist/factory.js +58 -3
- package/dist/factory.js.map +1 -0
- package/dist/{index-BzjwdK2M.d.ts → index-CTaN_ee_.d.ts} +235 -198
- package/dist/index.cjs +19 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +36 -37
- package/dist/index.js +19 -17
- package/dist/index.js.map +1 -1
- package/dist/macros.cjs +33 -20
- package/dist/macros.cjs.map +1 -1
- package/dist/macros.d.ts +13 -11
- package/dist/macros.js +33 -20
- package/dist/macros.js.map +1 -1
- package/dist/{operationParams-BZ07xDm0.d.ts → operationParams-B44p6EQy.d.ts} +2 -2
- package/dist/{response-hnSw2NKE.cjs → response-BeG6hq2D.cjs} +394 -147
- package/dist/response-BeG6hq2D.cjs.map +1 -0
- package/dist/{response-KUdWiDWw.js → response-Rd1uisM1.js} +376 -136
- package/dist/response-Rd1uisM1.js.map +1 -0
- package/dist/{types-DyDzizSf.d.ts → types-DQTgVSwE.d.ts} +4 -54
- package/dist/types.d.ts +5 -6
- package/dist/{utils-BLJwyza-.cjs → utils-BDI3kXlb.cjs} +5 -5
- package/dist/{utils-BLJwyza-.cjs.map → utils-BDI3kXlb.cjs.map} +1 -1
- package/dist/{utils-CF_-Pn_c.js → utils-DW9rnfsD.js} +5 -5
- package/dist/{utils-CF_-Pn_c.js.map → utils-DW9rnfsD.js.map} +1 -1
- package/dist/utils.cjs +4 -4
- package/dist/utils.d.ts +11 -3
- package/dist/utils.js +3 -3
- package/dist/{visitor-DpKZ9Tk0.cjs → visitor-B7Zlnp4c.cjs} +3 -53
- package/dist/visitor-B7Zlnp4c.cjs.map +1 -0
- package/dist/{visitor-DJ6ZEJvq.js → visitor-DepQEKyp.js} +4 -42
- package/dist/visitor-DepQEKyp.js.map +1 -0
- package/package.json +1 -1
- package/src/constants.ts +0 -30
- package/src/dedupe.ts +1 -9
- package/src/defineMacro.ts +19 -12
- package/src/{node.ts → defineNode.ts} +19 -42
- package/src/dialect.ts +42 -19
- package/src/factory.ts +3 -90
- package/src/index.ts +6 -8
- package/src/macros/macroDiscriminatorEnum.ts +7 -1
- package/src/macros/macroEnumName.ts +9 -1
- package/src/macros/macroSimplifyUnion.ts +29 -19
- package/src/nodes/code.ts +32 -75
- package/src/nodes/content.ts +2 -7
- package/src/nodes/file.ts +102 -14
- 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 +5 -5
- package/src/nodes/output.ts +1 -1
- package/src/nodes/parameter.ts +6 -6
- package/src/nodes/property.ts +6 -6
- package/src/nodes/requestBody.ts +6 -13
- package/src/nodes/response.ts +93 -8
- package/src/nodes/schema.ts +1 -1
- package/src/registry.ts +1 -1
- package/src/types.ts +4 -5
- package/src/utils/extractStringsFromNodes.ts +1 -0
- package/src/utils/operationParams.ts +1 -1
- package/src/visitor.ts +2 -13
- 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/visitor-DJ6ZEJvq.js.map +0 -1
- package/dist/visitor-DpKZ9Tk0.cjs.map +0 -1
- package/src/mocks.ts +0 -56
- package/src/nodes/http.ts +0 -85
- /package/src/{printer.ts → definePrinter.ts} +0 -0
|
@@ -1,11 +1,16 @@
|
|
|
1
|
+
import type { Dialect } from './dialect.ts'
|
|
1
2
|
import type { BaseNode, NodeKind } from './nodes/base.ts'
|
|
2
|
-
import type { SchemaNode } from './nodes/index.ts'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Visitor callback names, one per traversable node kind
|
|
6
|
-
* keys of `Visitor` in `visitor.ts`.
|
|
5
|
+
* Visitor callback names, one per traversable node kind, in traversal order.
|
|
6
|
+
* Kept in sync with the keys of `Visitor` in `visitor.ts`.
|
|
7
7
|
*/
|
|
8
|
-
|
|
8
|
+
export const visitorKeys = ['input', 'output', 'operation', 'schema', 'property', 'parameter', 'response'] as const
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* One of the {@link visitorKeys} callback names.
|
|
12
|
+
*/
|
|
13
|
+
export type VisitorKey = (typeof visitorKeys)[number]
|
|
9
14
|
|
|
10
15
|
/**
|
|
11
16
|
* Distributive `Omit` that preserves each member of a union.
|
|
@@ -27,25 +32,6 @@ function isKind<T extends BaseNode>(kind: NodeKind) {
|
|
|
27
32
|
return (node: unknown): node is T => (node as BaseNode).kind === kind
|
|
28
33
|
}
|
|
29
34
|
|
|
30
|
-
/**
|
|
31
|
-
* Updates a schema's `optional` and `nullish` flags from a parent's `required`
|
|
32
|
-
* value and the schema's own `nullable`. Mirrors how OpenAPI parameters and
|
|
33
|
-
* object properties combine "required" and "nullable" into a single AST.
|
|
34
|
-
*
|
|
35
|
-
* - Non-required + non-nullable → `optional: true`.
|
|
36
|
-
* - Non-required + nullable → `nullish: true`.
|
|
37
|
-
* - Required → both flags cleared.
|
|
38
|
-
*/
|
|
39
|
-
export function syncOptionality(schema: SchemaNode, required: boolean): SchemaNode {
|
|
40
|
-
const nullable = schema.nullable ?? false
|
|
41
|
-
|
|
42
|
-
return {
|
|
43
|
-
...schema,
|
|
44
|
-
optional: !required && !nullable ? true : undefined,
|
|
45
|
-
nullish: !required && nullable ? true : undefined,
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
35
|
/**
|
|
50
36
|
* The single definition derived from one {@link defineNode} call: the node's
|
|
51
37
|
* `create` builder, its `is` guard, and the traversal metadata the registry
|
|
@@ -57,9 +43,11 @@ export type NodeDef<TNode extends BaseNode = BaseNode, TInput = never> = {
|
|
|
57
43
|
*/
|
|
58
44
|
kind: NodeKind
|
|
59
45
|
/**
|
|
60
|
-
* Builds a node from its input, applying `defaults` and the optional `build` hook.
|
|
46
|
+
* Builds a node from its input, applying `defaults` and the optional `build` hook. An
|
|
47
|
+
* optional `dialect` is forwarded to `build` so nodes can derive spec-specific fields
|
|
48
|
+
* (e.g. a schema's `optional`/`nullish`) through `dialect.schema.optionality` when one is given.
|
|
61
49
|
*/
|
|
62
|
-
create: (input: TInput) => TNode
|
|
50
|
+
create: (input: TInput, dialect?: Dialect) => TNode
|
|
63
51
|
/**
|
|
64
52
|
* Type guard matching this node kind.
|
|
65
53
|
*/
|
|
@@ -72,20 +60,14 @@ export type NodeDef<TNode extends BaseNode = BaseNode, TInput = never> = {
|
|
|
72
60
|
* Visitor callback name. Feeds `VISITOR_KEY_BY_KIND`.
|
|
73
61
|
*/
|
|
74
62
|
visitorKey?: VisitorKey
|
|
75
|
-
/**
|
|
76
|
-
* When `true`, `create` is rerun after children are rebuilt so computed fields
|
|
77
|
-
* stay in sync. Feeds `nodeRebuilders`.
|
|
78
|
-
*/
|
|
79
|
-
rebuild?: boolean
|
|
80
63
|
}
|
|
81
64
|
|
|
82
65
|
type DefineNodeConfig<TNode extends BaseNode, TInput, TBuilt extends object> = {
|
|
83
66
|
kind: TNode['kind']
|
|
84
67
|
defaults?: Partial<TNode>
|
|
85
|
-
build?: (input: TInput) => TBuilt
|
|
68
|
+
build?: (input: TInput, dialect?: Dialect) => TBuilt
|
|
86
69
|
children?: ReadonlyArray<string>
|
|
87
70
|
visitorKey?: VisitorKey
|
|
88
|
-
rebuild?: boolean
|
|
89
71
|
}
|
|
90
72
|
|
|
91
73
|
/**
|
|
@@ -93,36 +75,31 @@ type DefineNodeConfig<TNode extends BaseNode, TInput, TBuilt extends object> = {
|
|
|
93
75
|
* metadata. `create` merges `defaults`, the `build` hook (or the raw input), and the
|
|
94
76
|
* `kind`, so node construction lives in one place without scattered `as` casts.
|
|
95
77
|
*
|
|
96
|
-
* Set `rebuild: true` when the `build` hook derives fields from children. After a
|
|
97
|
-
* transform rewrites those children, the registry reruns `create` so the derived
|
|
98
|
-
* fields stay correct.
|
|
99
|
-
*
|
|
100
78
|
* @example Simple node
|
|
101
79
|
* ```ts
|
|
102
80
|
* const importDef = defineNode<ImportNode>({ kind: 'Import' })
|
|
103
81
|
* const createImport = importDef.create
|
|
104
82
|
* ```
|
|
105
83
|
*
|
|
106
|
-
* @example Node with a build hook
|
|
84
|
+
* @example Node with a build hook
|
|
107
85
|
* ```ts
|
|
108
86
|
* const propertyDef = defineNode<PropertyNode, UserPropertyNode>({
|
|
109
87
|
* kind: 'Property',
|
|
110
88
|
* build: (props) => ({ ...props, required: props.required ?? false }),
|
|
111
89
|
* children: ['schema'],
|
|
112
90
|
* visitorKey: 'property',
|
|
113
|
-
* rebuild: true,
|
|
114
91
|
* })
|
|
115
92
|
* ```
|
|
116
93
|
*/
|
|
117
94
|
export function defineNode<TNode extends BaseNode, TInput = Omit<TNode, 'kind'>, TBuilt extends object = Omit<TNode, 'kind'>>(
|
|
118
95
|
config: DefineNodeConfig<TNode, TInput, TBuilt>,
|
|
119
96
|
): NodeDef<TNode, TInput> {
|
|
120
|
-
const { kind, defaults, build, children, visitorKey
|
|
97
|
+
const { kind, defaults, build, children, visitorKey } = config
|
|
121
98
|
|
|
122
|
-
function create(input: TInput): TNode {
|
|
123
|
-
const base = build ? build(input) : input
|
|
99
|
+
function create(input: TInput, dialect?: Dialect): TNode {
|
|
100
|
+
const base = build ? build(input, dialect) : input
|
|
124
101
|
return { ...defaults, ...(base as object), kind } as TNode
|
|
125
102
|
}
|
|
126
103
|
|
|
127
|
-
return { kind, create, is: isKind<TNode>(kind), children, visitorKey
|
|
104
|
+
return { kind, create, is: isKind<TNode>(kind), children, visitorKey }
|
|
128
105
|
}
|
package/src/dialect.ts
CHANGED
|
@@ -1,53 +1,76 @@
|
|
|
1
|
+
import type { SchemaNode } 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
|
+
* Derives a schema's `optional`/`nullish` flags from a parent's `required` value and the
|
|
31
|
+
* schema's own `nullable`. How "required" and "nullable" combine is spec-specific, so the
|
|
32
|
+
* dialect owns it. Method syntax keeps a concrete dialect assignable to the base
|
|
33
|
+
* `SchemaDialect` (bivariant parameters).
|
|
34
|
+
*/
|
|
35
|
+
optionality(schema: SchemaNode, required: boolean): SchemaNode
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* A spec adapter's dialect. `name` identifies it in logs and diagnostics; `schema` holds the
|
|
40
|
+
* spec-specific schema questions the parser answers.
|
|
41
|
+
*/
|
|
42
|
+
export type Dialect<TSchema = unknown, TRef = TSchema, TDiscriminated = TSchema, TDocument = unknown> = {
|
|
43
|
+
/**
|
|
44
|
+
* Identifies the dialect in logs and diagnostics.
|
|
45
|
+
*/
|
|
46
|
+
name: string
|
|
47
|
+
/**
|
|
48
|
+
* The spec-specific schema behavior. See {@link SchemaDialect}.
|
|
49
|
+
*/
|
|
50
|
+
schema: SchemaDialect<TSchema, TRef, TDiscriminated, TDocument>
|
|
31
51
|
}
|
|
32
52
|
|
|
33
53
|
/**
|
|
34
|
-
* Types a {@link
|
|
54
|
+
* Types a {@link Dialect} for an adapter. Adds no runtime behavior and only pins the
|
|
35
55
|
* dialect's type for inference.
|
|
36
56
|
*
|
|
37
57
|
* @example
|
|
38
58
|
* ```ts
|
|
39
|
-
* export const oasDialect =
|
|
59
|
+
* export const oasDialect = defineDialect({
|
|
40
60
|
* name: 'oas',
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
61
|
+
* schema: {
|
|
62
|
+
* isNullable,
|
|
63
|
+
* isReference,
|
|
64
|
+
* isDiscriminator,
|
|
65
|
+
* isBinary: (schema) => schema.type === 'string' && schema.contentMediaType === 'application/octet-stream',
|
|
66
|
+
* resolveRef,
|
|
67
|
+
* optionality,
|
|
68
|
+
* },
|
|
46
69
|
* })
|
|
47
70
|
* ```
|
|
48
71
|
*/
|
|
49
|
-
export function
|
|
50
|
-
dialect:
|
|
51
|
-
):
|
|
72
|
+
export function defineDialect<TSchema, TRef, TDiscriminated, TDocument>(
|
|
73
|
+
dialect: Dialect<TSchema, TRef, TDiscriminated, TDocument>,
|
|
74
|
+
): Dialect<TSchema, TRef, TDiscriminated, TDocument> {
|
|
52
75
|
return dialect
|
|
53
76
|
}
|
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'
|
|
@@ -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 {
|
|
1
|
+
export { schemaTypes } from './constants.ts'
|
|
2
2
|
export { applyDedupe, buildDedupePlan } from './dedupe.ts'
|
|
3
|
-
export {
|
|
4
|
-
export * as factory from './factory.ts'
|
|
3
|
+
export { defineDialect } from './dialect.ts'
|
|
5
4
|
export { isHttpOperationNode, narrowSchema } from './guards.ts'
|
|
6
5
|
export { applyMacros, composeMacros, defineMacro } from './defineMacro.ts'
|
|
7
|
-
export { defineNode } from './
|
|
8
|
-
export {
|
|
9
|
-
export * from './registry.ts'
|
|
10
|
-
export { createPrinterFactory, definePrinter } from './printer.ts'
|
|
6
|
+
export { defineNode } from './defineNode.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'
|
|
@@ -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,6 +2,12 @@ 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
13
|
* are left anonymous; non-enum nodes are returned unchanged.
|
|
@@ -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
|
/**
|
|
@@ -164,55 +164,12 @@ export type FunctionNode = BaseNode & {
|
|
|
164
164
|
* // export const getPet = () => ...
|
|
165
165
|
* ```
|
|
166
166
|
*/
|
|
167
|
-
export type ArrowFunctionNode =
|
|
167
|
+
export type ArrowFunctionNode = Omit<FunctionNode, 'kind'> & {
|
|
168
168
|
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
169
|
/**
|
|
208
170
|
* Render the arrow function body as a single-line expression.
|
|
209
171
|
*/
|
|
210
172
|
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
173
|
}
|
|
217
174
|
|
|
218
175
|
/**
|
|
@@ -285,6 +242,36 @@ export type CodeNode = ConstNode | TypeNode | FunctionNode | ArrowFunctionNode |
|
|
|
285
242
|
*/
|
|
286
243
|
export const constDef = defineNode<ConstNode>({ kind: 'Const' })
|
|
287
244
|
|
|
245
|
+
/**
|
|
246
|
+
* Definition for the {@link TypeNode}.
|
|
247
|
+
*/
|
|
248
|
+
export const typeDef = defineNode<TypeNode>({ kind: 'Type' })
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Definition for the {@link FunctionNode}.
|
|
252
|
+
*/
|
|
253
|
+
export const functionDef = defineNode<FunctionNode>({ kind: 'Function' })
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Definition for the {@link ArrowFunctionNode}.
|
|
257
|
+
*/
|
|
258
|
+
export const arrowFunctionDef = defineNode<ArrowFunctionNode>({ kind: 'ArrowFunction' })
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Definition for the {@link TextNode}.
|
|
262
|
+
*/
|
|
263
|
+
export const textDef = defineNode<TextNode, string>({ kind: 'Text', build: (value) => ({ value }) })
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Definition for the {@link BreakNode}.
|
|
267
|
+
*/
|
|
268
|
+
export const breakDef = defineNode<BreakNode, void>({ kind: 'Break', build: () => ({}) })
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Definition for the {@link JsxNode}.
|
|
272
|
+
*/
|
|
273
|
+
export const jsxDef = defineNode<JsxNode, string>({ kind: 'Jsx', build: (value) => ({ value }) })
|
|
274
|
+
|
|
288
275
|
/**
|
|
289
276
|
* Creates a `ConstNode` representing a TypeScript `const` declaration.
|
|
290
277
|
*
|
|
@@ -296,11 +283,6 @@ export const constDef = defineNode<ConstNode>({ kind: 'Const' })
|
|
|
296
283
|
*/
|
|
297
284
|
export const createConst = constDef.create
|
|
298
285
|
|
|
299
|
-
/**
|
|
300
|
-
* Definition for the {@link TypeNode}.
|
|
301
|
-
*/
|
|
302
|
-
export const typeDef = defineNode<TypeNode>({ kind: 'Type' })
|
|
303
|
-
|
|
304
286
|
/**
|
|
305
287
|
* Creates a `TypeNode` representing a TypeScript `type` alias declaration.
|
|
306
288
|
*
|
|
@@ -312,11 +294,6 @@ export const typeDef = defineNode<TypeNode>({ kind: 'Type' })
|
|
|
312
294
|
*/
|
|
313
295
|
export const createType = typeDef.create
|
|
314
296
|
|
|
315
|
-
/**
|
|
316
|
-
* Definition for the {@link FunctionNode}.
|
|
317
|
-
*/
|
|
318
|
-
export const functionDef = defineNode<FunctionNode>({ kind: 'Function' })
|
|
319
|
-
|
|
320
297
|
/**
|
|
321
298
|
* Creates a `FunctionNode` representing a TypeScript `function` declaration.
|
|
322
299
|
*
|
|
@@ -328,11 +305,6 @@ export const functionDef = defineNode<FunctionNode>({ kind: 'Function' })
|
|
|
328
305
|
*/
|
|
329
306
|
export const createFunction = functionDef.create
|
|
330
307
|
|
|
331
|
-
/**
|
|
332
|
-
* Definition for the {@link ArrowFunctionNode}.
|
|
333
|
-
*/
|
|
334
|
-
export const arrowFunctionDef = defineNode<ArrowFunctionNode>({ kind: 'ArrowFunction' })
|
|
335
|
-
|
|
336
308
|
/**
|
|
337
309
|
* Creates an `ArrowFunctionNode` representing a TypeScript arrow function.
|
|
338
310
|
*
|
|
@@ -344,11 +316,6 @@ export const arrowFunctionDef = defineNode<ArrowFunctionNode>({ kind: 'ArrowFunc
|
|
|
344
316
|
*/
|
|
345
317
|
export const createArrowFunction = arrowFunctionDef.create
|
|
346
318
|
|
|
347
|
-
/**
|
|
348
|
-
* Definition for the {@link TextNode}.
|
|
349
|
-
*/
|
|
350
|
-
export const textDef = defineNode<TextNode, string>({ kind: 'Text', build: (value) => ({ value }) })
|
|
351
|
-
|
|
352
319
|
/**
|
|
353
320
|
* Creates a {@link TextNode} representing a raw string fragment in the source output.
|
|
354
321
|
*
|
|
@@ -360,11 +327,6 @@ export const textDef = defineNode<TextNode, string>({ kind: 'Text', build: (valu
|
|
|
360
327
|
*/
|
|
361
328
|
export const createText = textDef.create
|
|
362
329
|
|
|
363
|
-
/**
|
|
364
|
-
* Definition for the {@link BreakNode}.
|
|
365
|
-
*/
|
|
366
|
-
export const breakDef = defineNode<BreakNode, void>({ kind: 'Break', build: () => ({}) })
|
|
367
|
-
|
|
368
330
|
/**
|
|
369
331
|
* Creates a {@link BreakNode} representing a line break in the source output.
|
|
370
332
|
*
|
|
@@ -378,11 +340,6 @@ export function createBreak(): BreakNode {
|
|
|
378
340
|
return breakDef.create()
|
|
379
341
|
}
|
|
380
342
|
|
|
381
|
-
/**
|
|
382
|
-
* Definition for the {@link JsxNode}.
|
|
383
|
-
*/
|
|
384
|
-
export const jsxDef = defineNode<JsxNode, string>({ kind: 'Jsx', build: (value) => ({ value }) })
|
|
385
|
-
|
|
386
343
|
/**
|
|
387
344
|
* Creates a {@link JsxNode} representing a raw JSX fragment in the source output.
|
|
388
345
|
*
|
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
|
})
|