@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,81 @@
1
+ /**
2
+ * `analyzeClass`: records the `@OpenApiDocument` class and the controllers carrying `@Api*`
3
+ * decorators, and reports misplaced decorators (ZNIGHT030). The operations are built in
4
+ * `validate`, from the route table of the http extension.
5
+ */
6
+ import type { AnalyzeContext, ClassInfo, DecoratorInfo } from '@znight/compiler'
7
+ import type { OpenApiStored } from './model.ts'
8
+
9
+ import { Codes, EXTENSION_NAME, HttpIds, Ids, ROUTE_DECORATORS } from './model.ts'
10
+
11
+ /** `analyzeClass` of the extension. */
12
+ export function analyzeOpenApiClass(cls: ClassInfo, ctx: AnalyzeContext<OpenApiStored>): void {
13
+ const owned = (decorators: readonly DecoratorInfo[]): DecoratorInfo[] =>
14
+ decorators.filter(decorator => decorator.owner === EXTENSION_NAME)
15
+ const document = cls.decorators.find(decorator => decorator.identity === Ids.OpenApiDocument)
16
+ const controller = cls.decorators.some(decorator => decorator.identity === HttpIds.Controller)
17
+ const members = [
18
+ ...cls.methods.map(method => ({ decorators: owned(method.decorators), method })),
19
+ ...cls.properties.map(property => ({ decorators: owned(property.decorators), method: undefined })),
20
+ ]
21
+ const misplaced = (decorator: DecoratorInfo, message: string, hints: readonly string[]): void => {
22
+ ctx.report({
23
+ code: Codes.InvalidOpenApiDefinition,
24
+ severity: 'error',
25
+ message,
26
+ location: decorator.location,
27
+ hints,
28
+ })
29
+ }
30
+ if (document !== undefined) {
31
+ if (controller) {
32
+ misplaced(document, `@OpenApiDocument goes on a class of its own, not on the controller ${cls.displayName}`, [
33
+ 'Declare it on an empty class: @OpenApiDocument({...}) export class Api {}',
34
+ ])
35
+ }
36
+ for (const decorator of owned(cls.decorators)) {
37
+ if (decorator !== document && !controller) {
38
+ misplaced(
39
+ decorator,
40
+ `@${decorator.name} applies to controllers and route handlers, not to the @OpenApiDocument class`,
41
+ [],
42
+ )
43
+ }
44
+ }
45
+ ctx.store({ kind: 'document', identity: cls.identity, displayName: cls.displayName, location: document.location })
46
+ if (!controller) return
47
+ }
48
+ if (!controller) {
49
+ const consumer = cls.decorators.some(decorator => decorator.identity === '@znight/messaging#Consumer')
50
+ const hints = consumer
51
+ ? ['Message consumers are not documented by OpenAPI (AsyncAPI is not supported in v0.1)']
52
+ : ['Add @Controller() to the class, or remove the decorator']
53
+ for (const decorator of owned(cls.decorators)) {
54
+ misplaced(decorator, `@${decorator.name} applies to controllers: ${cls.displayName} is not a @Controller`, hints)
55
+ }
56
+ for (const member of members) {
57
+ for (const decorator of member.decorators) {
58
+ misplaced(
59
+ decorator,
60
+ `@${decorator.name} applies to route handlers: ${cls.displayName} is not a @Controller`,
61
+ hints,
62
+ )
63
+ }
64
+ }
65
+ return
66
+ }
67
+ for (const member of members) {
68
+ const handler = member.method?.decorators.some(
69
+ decorator => decorator.identity !== undefined && ROUTE_DECORATORS.has(decorator.identity),
70
+ )
71
+ if (handler === true) continue
72
+ for (const decorator of member.decorators) {
73
+ misplaced(
74
+ decorator,
75
+ `@${decorator.name} applies to route handlers: ${cls.displayName}.${member.method?.name ?? 'this member'} has no route decorator (@Get, @Post...)`,
76
+ ['Add a route decorator, or move the decorator to a route handler'],
77
+ )
78
+ }
79
+ }
80
+ ctx.store({ kind: 'controller', identity: cls.identity, displayName: cls.displayName })
81
+ }