@znight/openapi 0.0.0-stage → 0.1.0

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.
Files changed (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +572 -2
  3. package/dist/build-BTUC96mY.d.mts +174 -0
  4. package/dist/build-DXunOzlI.mjs +733 -0
  5. package/dist/build-DXunOzlI.mjs.map +1 -0
  6. package/dist/compiler.d.mts +16 -0
  7. package/dist/compiler.mjs +2639 -0
  8. package/dist/compiler.mjs.map +1 -0
  9. package/dist/emit-child.d.mts +1 -0
  10. package/dist/emit-child.mjs +124 -0
  11. package/dist/emit-child.mjs.map +1 -0
  12. package/dist/emit.d.mts +2 -0
  13. package/dist/emit.mjs +252 -0
  14. package/dist/emit.mjs.map +1 -0
  15. package/dist/index-CqQ6IRnN.d.mts +60 -0
  16. package/dist/index.d.mts +260 -0
  17. package/dist/index.mjs +777 -0
  18. package/dist/index.mjs.map +1 -0
  19. package/dist/openapi-CQk5dHqc.mjs +39 -0
  20. package/dist/openapi-CQk5dHqc.mjs.map +1 -0
  21. package/dist/shared-BZxtyaB0.mjs +147 -0
  22. package/dist/shared-BZxtyaB0.mjs.map +1 -0
  23. package/dist/testing.d.mts +39 -0
  24. package/dist/testing.mjs +155 -0
  25. package/dist/testing.mjs.map +1 -0
  26. package/dist/types-VzBexMKj.d.mts +213 -0
  27. package/dist/vite.d.mts +24 -0
  28. package/dist/vite.mjs +64 -0
  29. package/dist/vite.mjs.map +1 -0
  30. package/package.json +115 -4
  31. package/src/build.ts +898 -0
  32. package/src/compiler/analyze.ts +81 -0
  33. package/src/compiler/document.ts +612 -0
  34. package/src/compiler/generate.ts +79 -0
  35. package/src/compiler/index.ts +47 -0
  36. package/src/compiler/model.ts +141 -0
  37. package/src/compiler/operations.ts +1475 -0
  38. package/src/compiler/schemas.ts +706 -0
  39. package/src/compiler/validate.ts +102 -0
  40. package/src/compiler/values.ts +81 -0
  41. package/src/converters.ts +137 -0
  42. package/src/decorators.ts +187 -0
  43. package/src/emit/child.ts +144 -0
  44. package/src/emit/index.ts +377 -0
  45. package/src/emit/protocol.ts +35 -0
  46. package/src/index.ts +94 -0
  47. package/src/metadata.ts +112 -0
  48. package/src/openapi.ts +55 -0
  49. package/src/plugin.ts +810 -0
  50. package/src/shared.ts +154 -0
  51. package/src/testing.ts +224 -0
  52. package/src/types.ts +240 -0
  53. package/src/ui.ts +215 -0
  54. package/src/vite.ts +126 -0
@@ -0,0 +1,47 @@
1
+ /**
2
+ * `@znight/openapi/compiler`: the compiler extension of `@znight/openapi` (architecture §6.5),
3
+ * loaded by `@znight/compiler` through `package.json#znight.compiler`.
4
+ *
5
+ * - `analyzeClass`: records the `@OpenApiDocument` class, checks where `@Api*` decorators are
6
+ * (ZNIGHT030);
7
+ * - `validate`: builds the operation model from the route table of `@znight/http/compiler`, the
8
+ * handler signatures, their JSDoc and the type shapes, and reports ZNIGHT030–036;
9
+ * - `generate`: `metadata.extensions.openapi` (README, "Compiler contract").
10
+ *
11
+ * This entry only `import type`s from `@znight/compiler` and `@znight/http/compiler` and never
12
+ * loads the runtime of `@znight/openapi`.
13
+ */
14
+ import type { CompilerExtension, DecoratorSpec } from '@znight/compiler'
15
+ import type { OpenApiStored } from './model.ts'
16
+
17
+ import { analyzeOpenApiClass } from './analyze.ts'
18
+ import { generateOpenApi } from './generate.ts'
19
+ import { EXTENSION_NAME, Ids } from './model.ts'
20
+ import { validateOpenApi } from './validate.ts'
21
+
22
+ export type { OpenApiStored } from './model.ts'
23
+
24
+ /** Decorators owned by the extension, by canonical identity (static / value arguments, §4.6). */
25
+ const decorators: Readonly<Record<string, DecoratorSpec>> = Object.freeze({
26
+ [Ids.OpenApiDocument]: { targets: ['class'], params: ['value'] },
27
+ [Ids.ApiOperation]: { targets: ['method'], params: ['static'] },
28
+ [Ids.ApiTags]: { targets: ['class', 'method'], params: [], rest: 'static' },
29
+ [Ids.ApiResponse]: { targets: ['method'], params: ['static', 'value'] },
30
+ [Ids.ApiBody]: { targets: ['method'], params: ['value'] },
31
+ [Ids.ApiQuery]: { targets: ['method'], params: ['static', 'static'] },
32
+ [Ids.ApiHeader]: { targets: ['class', 'method'], params: ['static', 'static'] },
33
+ [Ids.ApiSecurity]: { targets: ['class', 'method'], params: [], rest: 'value' },
34
+ [Ids.ApiExclude]: { targets: ['class', 'method'], params: [] },
35
+ })
36
+
37
+ /** The `@znight/openapi` compiler extension. */
38
+ const openapi: CompilerExtension<OpenApiStored> = Object.freeze({
39
+ apiVersion: 1,
40
+ name: EXTENSION_NAME,
41
+ decorators,
42
+ analyzeClass: analyzeOpenApiClass,
43
+ validate: validateOpenApi,
44
+ generate: generateOpenApi,
45
+ })
46
+
47
+ export default openapi
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Identities, codes and the data model of the `@znight/openapi` compiler extension. Pure: types and
3
+ * constants only.
4
+ */
5
+ import type { Location, ValueRef } from '@znight/compiler'
6
+
7
+ /** Name of the extension (key of `metadata.extensions`). */
8
+ export const EXTENSION_NAME = 'openapi'
9
+
10
+ /** Canonical identities of the decorators and functions of `@znight/openapi`. */
11
+ export const Ids: {
12
+ readonly OpenApiDocument: string
13
+ readonly ApiOperation: string
14
+ readonly ApiTags: string
15
+ readonly ApiResponse: string
16
+ readonly ApiBody: string
17
+ readonly ApiQuery: string
18
+ readonly ApiHeader: string
19
+ readonly ApiSecurity: string
20
+ readonly ApiExclude: string
21
+ readonly securityScheme: string
22
+ } = Object.freeze({
23
+ OpenApiDocument: '@znight/openapi#OpenApiDocument',
24
+ ApiOperation: '@znight/openapi#ApiOperation',
25
+ ApiTags: '@znight/openapi#ApiTags',
26
+ ApiResponse: '@znight/openapi#ApiResponse',
27
+ ApiBody: '@znight/openapi#ApiBody',
28
+ ApiQuery: '@znight/openapi#ApiQuery',
29
+ ApiHeader: '@znight/openapi#ApiHeader',
30
+ ApiSecurity: '@znight/openapi#ApiSecurity',
31
+ ApiExclude: '@znight/openapi#ApiExclude',
32
+ securityScheme: '@znight/openapi#securityScheme',
33
+ })
34
+
35
+ /** Identities of `@znight/http` read by the extension. */
36
+ export const HttpIds: {
37
+ readonly Controller: string
38
+ readonly createRouteDecorator: string
39
+ readonly HttpResponse: string
40
+ readonly FileBody: string
41
+ readonly SseEvent: string
42
+ readonly SseBody: string
43
+ } = Object.freeze({
44
+ Controller: '@znight/http#Controller',
45
+ createRouteDecorator: '@znight/http#createRouteDecorator',
46
+ HttpResponse: '@znight/http#HttpResponse',
47
+ FileBody: '@znight/http#FileBody',
48
+ SseEvent: '@znight/http#SseEvent',
49
+ SseBody: '@znight/http#SseBody',
50
+ })
51
+
52
+ /** Route method decorators of `@znight/http` (a method carrying one is a route handler). */
53
+ export const ROUTE_DECORATORS: ReadonlySet<string> = new Set([
54
+ '@znight/http#Get',
55
+ '@znight/http#Post',
56
+ '@znight/http#Put',
57
+ '@znight/http#Patch',
58
+ '@znight/http#Delete',
59
+ '@znight/http#Head',
60
+ '@znight/http#Options',
61
+ '@znight/http#All',
62
+ '@znight/http#Sse',
63
+ ])
64
+
65
+ /** Error codes used by the extension (see `ErrorCode` in `@znight/core`). */
66
+ export const Codes: {
67
+ readonly InvalidDecorator: 'ZNIGHT005'
68
+ readonly InvalidOpenApiDefinition: 'ZNIGHT030'
69
+ readonly UndocumentedResponse: 'ZNIGHT031'
70
+ readonly UnrepresentableType: 'ZNIGHT032'
71
+ readonly DuplicateOperationId: 'ZNIGHT033'
72
+ readonly SchemaNameConflict: 'ZNIGHT034'
73
+ readonly InconsistentOperation: 'ZNIGHT035'
74
+ readonly InvalidSecurityRequirement: 'ZNIGHT036'
75
+ } = Object.freeze({
76
+ InvalidDecorator: 'ZNIGHT005',
77
+ InvalidOpenApiDefinition: 'ZNIGHT030',
78
+ UndocumentedResponse: 'ZNIGHT031',
79
+ UnrepresentableType: 'ZNIGHT032',
80
+ DuplicateOperationId: 'ZNIGHT033',
81
+ SchemaNameConflict: 'ZNIGHT034',
82
+ InconsistentOperation: 'ZNIGHT035',
83
+ InvalidSecurityRequirement: 'ZNIGHT036',
84
+ })
85
+
86
+ /** Generic aliases meaning "the Standard Schema S" (`z.output<typeof S>`), checked against the installed libraries. */
87
+ export const SCHEMA_ALIASES: Readonly<Record<string, 'input' | 'output'>> = Object.freeze({
88
+ 'zod#output': 'output',
89
+ 'zod#infer': 'output',
90
+ 'zod#input': 'input',
91
+ 'zod/v4#output': 'output',
92
+ 'zod/v4#infer': 'output',
93
+ 'zod/v4#input': 'input',
94
+ 'valibot#InferOutput': 'output',
95
+ 'valibot#InferInput': 'input',
96
+ '@znight/http#InferSchemaOutput': 'output',
97
+ '@znight/http#InferSchemaInput': 'input',
98
+ '@standard-schema/spec#StandardSchemaV1.InferOutput': 'output',
99
+ '@standard-schema/spec#StandardSchemaV1.InferInput': 'input',
100
+ })
101
+
102
+ /** ArkType: `typeof S.infer` / `typeof S.inferIn`. */
103
+ export const SCHEMA_MEMBERS: Readonly<Record<string, 'input' | 'output'>> = Object.freeze({
104
+ infer: 'output',
105
+ inferIn: 'input',
106
+ })
107
+
108
+ /** Types kept as references by the shape resolver (bodies of special responses). */
109
+ export const KEEP: readonly string[] = Object.freeze([
110
+ HttpIds.HttpResponse,
111
+ HttpIds.FileBody,
112
+ HttpIds.SseEvent,
113
+ HttpIds.SseBody,
114
+ 'globalThis#AsyncIterable',
115
+ 'globalThis#AsyncIterableIterator',
116
+ 'globalThis#AsyncGenerator',
117
+ 'globalThis#Response',
118
+ ])
119
+
120
+ /** Data stored by `analyzeClass`. */
121
+ export type OpenApiStored =
122
+ | {
123
+ readonly kind: 'document'
124
+ readonly identity: string
125
+ readonly displayName: string
126
+ readonly location: Location
127
+ }
128
+ | {
129
+ readonly kind: 'controller'
130
+ readonly identity: string
131
+ readonly displayName: string
132
+ }
133
+
134
+ /** A Standard Schema to convert at assembly. */
135
+ export interface SlotData {
136
+ readonly name: string
137
+ readonly ref: ValueRef
138
+ readonly io: Set<'input' | 'output'>
139
+ /** The declaration of the schema (the reference when it cannot be found). */
140
+ readonly location: Location
141
+ }