vona-module-a-openapi 5.0.25 → 5.0.26

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.
@@ -9,6 +9,10 @@ declare module 'vona-module-a-bean' {
9
9
  declare module 'vona-module-a-openapi' {
10
10
  interface ServiceOpenapi {
11
11
  }
12
+ interface ServiceOpenapi {
13
+ get $beanFullName(): 'a-openapi.service.openapi';
14
+ get $onionName(): 'a-openapi:openapi';
15
+ }
12
16
  }
13
17
  /** service: end */
14
18
  /** service: begin */
@@ -36,6 +40,10 @@ declare module 'vona-module-a-summer' {
36
40
  declare module 'vona-module-a-openapi' {
37
41
  interface SummerCacheJson {
38
42
  }
43
+ interface SummerCacheJson {
44
+ get $beanFullName(): 'a-openapi.summerCache.json';
45
+ get $onionName(): 'a-openapi:json';
46
+ }
39
47
  }
40
48
  /** summerCache: end */
41
49
  /** summerCache: begin */
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
- import { appMetadata, appResource, cast, BeanInfo, BeanBase, LocaleModuleNameSeparator, HttpStatus, BeanSimple, BeanScopeBase, isClassStrict, registerMappedClassMetadataKey, deepExtend } from 'vona';
1
+ import { registerMappedClassMetadataKey, appMetadata, appResource, cast, deepExtend, BeanInfo, BeanBase, LocaleModuleNameSeparator, HttpStatus, BeanSimple, BeanScopeBase } from 'vona';
2
2
  import { OpenApiGeneratorV3, OpenApiGeneratorV31, OpenAPIRegistry } from '@asteasolutions/zod-to-openapi';
3
3
  import * as ModuleInfo from '@cabloy/module-info';
4
- import { isEmptyObject, isNil } from '@cabloy/utils';
4
+ import { isClass, isEmptyObject, isNil } from '@cabloy/utils';
5
5
  import { toUpperCaseFirstChar } from '@cabloy/word-utils';
6
- import { getTypeName, coerceWithNil } from '@cabloy/zod-query';
6
+ import { getTypeName, ZodMetadata, coerceWithNil } from '@cabloy/zod-query';
7
7
  import { Service, Scope } from 'vona-module-a-bean';
8
8
  import { Caching } from 'vona-module-a-caching';
9
- import { SymbolDecoratorRule, SymbolOpenApiOptions, SymbolDecoratorRuleColumn } from 'vona-module-a-openapiutils';
9
+ import { SymbolDecoratorRule, SymbolDecoratorRuleColumn, SymbolOpenApiOptions } from 'vona-module-a-openapiutils';
10
10
  import { SymbolRequestMappingHandler } from 'vona-module-a-web';
11
11
  import { z } from 'zod';
12
12
  import { SummerCache, BeanSummerCacheBase } from 'vona-module-a-summer';
@@ -31,6 +31,82 @@ function bodySchemaWrapperDefault(bodySchema) {
31
31
  });
32
32
  }
33
33
 
34
+ function getTargetDecoratorRules(target) {
35
+ registerMappedClassMetadataKey(target, SymbolDecoratorRule, {
36
+ partialClass: meta => {
37
+ return meta.optional();
38
+ }
39
+ });
40
+ return appMetadata.getOwnMetadataMap(true, SymbolDecoratorRule, target);
41
+ }
42
+ function getTargetDecoratorRuleColumns(target) {
43
+ registerMappedClassMetadataKey(target, SymbolDecoratorRuleColumn);
44
+ return appMetadata.getOwnMetadataMap(true, SymbolDecoratorRuleColumn, target);
45
+ }
46
+ function mergeFieldsOpenapiMetadata(target) {
47
+ // rules
48
+ const rules = getTargetDecoratorRules(target.prototype);
49
+ // beanOptions
50
+ const beanOptions = appResource.getBean(target);
51
+ const fields = cast(beanOptions?.options)?.fields;
52
+ if (!fields) return;
53
+ for (const key in fields) {
54
+ const field = fields[key];
55
+ if (!field) continue;
56
+ const schemaCurrent = rules[key];
57
+ if (Object.prototype.hasOwnProperty.call(field, 'parseAsync')) {
58
+ const schema = field;
59
+ rules[key] = schema.openapi(deepExtend({}, schemaCurrent?._def.openapi?.metadata, schema._def.openapi?.metadata));
60
+ } else {
61
+ // use deepExtend for sure strict
62
+ if (schemaCurrent) {
63
+ rules[key] = schemaCurrent.openapi(deepExtend({}, schemaCurrent._def.openapi?.metadata, field));
64
+ } else {
65
+ rules[key] = z.any().openapi(deepExtend({}, field));
66
+ }
67
+ }
68
+ }
69
+ }
70
+ function prepareClassType(classType) {
71
+ return isClass(classType) ? classType : cast(classType)();
72
+ }
73
+
74
+ function makeSchemaLikes(schemaLikes, typeInit) {
75
+ // default schema
76
+ let argSchema = $schema(typeInit);
77
+ // loop
78
+ for (let index = schemaLikes.length - 1; index >= 0; index--) {
79
+ const schemaLike = schemaLikes[index];
80
+ argSchema = makeSchemaLike(schemaLike, argSchema);
81
+ }
82
+ return argSchema;
83
+ }
84
+ function makeSchemaLike(schemaLike, schemaPrevious) {
85
+ if (!schemaLike) return schemaPrevious;
86
+ if (Object.prototype.hasOwnProperty.call(schemaLike, 'parseAsync')) {
87
+ // schema
88
+ return schemaLike;
89
+ } else if (isClass(schemaLike) || ['String', 'Number', 'Boolean', 'Date', 'BigInt', 'Array'].includes(cast(schemaLike).name)) {
90
+ // class
91
+ return $schema(cast(schemaLike));
92
+ } else {
93
+ // function
94
+ return cast(schemaLike)(schemaPrevious);
95
+ }
96
+ }
97
+
98
+ const __schemasDynamic = {};
99
+ const SymbolSchemaDynamicRefId = Symbol('SymbolSchemaDynamicRefId');
100
+ function addSchemaDynamic(dynamicName, classType) {
101
+ __schemasDynamic[dynamicName] = classType;
102
+ }
103
+ function getSchemaDynamic(dynamicName) {
104
+ return __schemasDynamic[dynamicName];
105
+ }
106
+ function getSchemasDynamic() {
107
+ return __schemasDynamic;
108
+ }
109
+
34
110
  function $schema(classType, options) {
35
111
  if (!classType) return z.any();
36
112
  if (classType.parseAsync) return classType;
@@ -47,15 +123,37 @@ function $schema(classType, options) {
47
123
  return z.any();
48
124
  }
49
125
  // object
126
+ let schema = _createSchemaObject(rules, options);
127
+ // refId
128
+ const schemaDynamicRefId = classType[SymbolSchemaDynamicRefId];
129
+ if (schemaDynamicRefId) {
130
+ // dynamic
131
+ schema = schema.openapi(schemaDynamicRefId);
132
+ } else {
133
+ // static
134
+ const beanOptions = appResource.getBean(classType);
135
+ if (beanOptions) {
136
+ const openapi = cast(beanOptions.options)?.openapi;
137
+ schema = schema.openapi(beanOptions.beanFullName, openapi);
138
+ }
139
+ }
140
+ return schema;
141
+ }
142
+ function $schemaLazy(...schemaLikes) {
143
+ return z.lazy(() => {
144
+ return _createSchemaLazy(schemaLikes);
145
+ });
146
+ }
147
+ function _createSchemaLazy(schemaLikes) {
148
+ const classType = schemaLikes[schemaLikes.length - 1];
149
+ schemaLikes = schemaLikes.slice(0, schemaLikes.length - 1);
150
+ const classType2 = prepareClassType(classType);
151
+ return makeSchemaLikes(schemaLikes, $schema(classType2));
152
+ }
153
+ function _createSchemaObject(rules, options) {
50
154
  let schema = z.object(rules);
51
155
  if (options?.passthrough) schema = schema.passthrough();
52
156
  if (options?.strict) schema = schema.strict();
53
- // refId
54
- const beanOptions = appResource.getBean(classType);
55
- if (beanOptions) {
56
- const openapi = cast(beanOptions.options)?.openapi;
57
- schema = schema.openapi(beanOptions.beanFullName, openapi);
58
- }
59
157
  return schema;
60
158
  }
61
159
 
@@ -456,10 +554,39 @@ function errorsAdapter(app) {
456
554
  });
457
555
  }
458
556
 
557
+ function schemaRefCustomAdapter(_app) {
558
+ const registry = new OpenAPIRegistry();
559
+ const generator31 = new OpenApiGeneratorV31(registry.definitions);
560
+ _patchGenerator(generator31);
561
+ }
562
+ function _patchGenerator(generator) {
563
+ const gen = Object.getPrototypeOf(cast(generator).generator);
564
+ gen.generateSchemaWithRef = function (zodSchema) {
565
+ // schema ref
566
+ const lazySchema = ZodMetadata.getLazySchema(zodSchema);
567
+ if (lazySchema) {
568
+ zodSchema = lazySchema();
569
+ }
570
+ const refId = ZodMetadata.getRefId(zodSchema);
571
+ if (!refId) {
572
+ return this.generateSimpleSchema(zodSchema);
573
+ }
574
+ if (this.schemaRefs[refId] === undefined) {
575
+ this.schemaRefs[refId] = null;
576
+ const result = this.generateSimpleSchema(zodSchema);
577
+ this.schemaRefs[refId] = result;
578
+ }
579
+ return {
580
+ $ref: this.generateSchemaRef(refId)
581
+ };
582
+ };
583
+ }
584
+
459
585
  class Main extends BeanSimple {
460
586
  async moduleLoading() {}
461
587
  async moduleLoaded() {
462
588
  errorsAdapter(this.app);
589
+ schemaRefCustomAdapter(this.app);
463
590
  }
464
591
  async configLoaded(_config) {}
465
592
  }
@@ -477,67 +604,6 @@ function $locale(key) {
477
604
  }
478
605
  /** scope: end */
479
606
 
480
- function makeSchemaLikes(schemaLikes, typeInit) {
481
- // default schema
482
- let argSchema = $schema(typeInit);
483
- // loop
484
- for (let index = schemaLikes.length - 1; index >= 0; index--) {
485
- const schemaLike = schemaLikes[index];
486
- argSchema = makeSchemaLike(schemaLike, argSchema);
487
- }
488
- return argSchema;
489
- }
490
- function makeSchemaLike(schemaLike, schemaPrevious) {
491
- if (!schemaLike) return schemaPrevious;
492
- if (Object.prototype.hasOwnProperty.call(schemaLike, 'parseAsync')) {
493
- // schema
494
- return schemaLike;
495
- } else if (isClassStrict(schemaLike) || ['String', 'Number', 'Boolean', 'Date', 'BigInt', 'Array'].includes(cast(schemaLike).name)) {
496
- // class
497
- return $schema(cast(schemaLike));
498
- } else {
499
- // function
500
- return cast(schemaLike)(schemaPrevious);
501
- }
502
- }
503
-
504
- function getTargetDecoratorRules(target) {
505
- registerMappedClassMetadataKey(target, SymbolDecoratorRule, {
506
- partialClass: meta => {
507
- return meta.optional();
508
- }
509
- });
510
- return appMetadata.getOwnMetadataMap(true, SymbolDecoratorRule, target);
511
- }
512
- function getTargetDecoratorRuleColumns(target) {
513
- registerMappedClassMetadataKey(target, SymbolDecoratorRuleColumn);
514
- return appMetadata.getOwnMetadataMap(true, SymbolDecoratorRuleColumn, target);
515
- }
516
- function mergeFieldsOpenapiMetadata(target) {
517
- // rules
518
- const rules = getTargetDecoratorRules(target.prototype);
519
- // beanOptions
520
- const beanOptions = appResource.getBean(target);
521
- const fields = cast(beanOptions?.options)?.fields;
522
- if (!fields) return;
523
- for (const key in fields) {
524
- const field = fields[key];
525
- if (!field) continue;
526
- const schemaCurrent = rules[key];
527
- if (Object.prototype.hasOwnProperty.call(field, 'parseAsync')) {
528
- const schema = field;
529
- rules[key] = schema.openapi(deepExtend({}, schemaCurrent?._def.openapi?.metadata, schema._def.openapi?.metadata));
530
- } else {
531
- // use deepExtend for sure strict
532
- if (schemaCurrent) {
533
- rules[key] = schemaCurrent.openapi(deepExtend({}, schemaCurrent._def.openapi?.metadata, field));
534
- } else {
535
- rules[key] = z.any().openapi(deepExtend({}, field));
536
- }
537
- }
538
- }
539
- }
540
-
541
607
  function Field$1(...schemaLikes) {
542
608
  return function (target, prop) {
543
609
  // rules
@@ -751,6 +817,11 @@ function schemaTableIdentity() {
751
817
  return z.union([z.string(), z.number()]);
752
818
  };
753
819
  }
820
+ function schemaBigNumber() {
821
+ return function (_schema) {
822
+ return z.union([z.string(), z.number()]);
823
+ };
824
+ }
754
825
 
755
826
  function schemaOpenapi(refId, metadata) {
756
827
  return function (schema) {
@@ -789,6 +860,11 @@ function schemaOptional() {
789
860
  return schema.optional();
790
861
  };
791
862
  }
863
+ function schemaLazy(...schemaLikes) {
864
+ return function (_schema) {
865
+ return $schemaLazy(...schemaLikes);
866
+ };
867
+ }
792
868
  function schemaObject(classType, options) {
793
869
  return function (_schema) {
794
870
  return $schema(classType, options);
@@ -809,6 +885,7 @@ function schemaArray(schemaLike, params) {
809
885
  }
810
886
 
811
887
  const v = {
888
+ lazy: schemaLazy,
812
889
  array: schemaArray,
813
890
  default: schemaDefault,
814
891
  object: schemaObject,
@@ -821,6 +898,7 @@ const v = {
821
898
  min: schemaMin,
822
899
  max: schemaMax,
823
900
  tableIdentity: schemaTableIdentity,
901
+ bigNumber: schemaBigNumber,
824
902
  // openapi
825
903
  openapi: schemaOpenapi,
826
904
  title: schemaTitle,
@@ -833,4 +911,4 @@ const OrderBusinessBase = 1000;
833
911
  const OrderUnknownBase = 10000;
834
912
  const OrderMaxBase = 100000;
835
913
 
836
- export { $locale, $schema, Api, Arg, Main, OrderBusinessBase, OrderCoreBase, OrderMaxBase, OrderUnknownBase, ScopeModuleAOpenapi, ServiceOpenapi, SummerCacheJson, SymbolRouteHandlersArgumentsMeta, SymbolRouteHandlersArgumentsValue, bodySchemaWrapperDefault, config, createPipesArgumentDecorator, errorsAdapter, getTargetDecoratorRuleColumns, getTargetDecoratorRules, locales, makeSchemaLike, makeSchemaLikes, mergeFieldsOpenapiMetadata, v };
914
+ export { $locale, $schema, $schemaLazy, Api, Arg, Main, OrderBusinessBase, OrderCoreBase, OrderMaxBase, OrderUnknownBase, ScopeModuleAOpenapi, ServiceOpenapi, SummerCacheJson, SymbolRouteHandlersArgumentsMeta, SymbolRouteHandlersArgumentsValue, SymbolSchemaDynamicRefId, addSchemaDynamic, bodySchemaWrapperDefault, config, createPipesArgumentDecorator, errorsAdapter, getSchemaDynamic, getSchemasDynamic, getTargetDecoratorRuleColumns, getTargetDecoratorRules, locales, makeSchemaLike, makeSchemaLikes, mergeFieldsOpenapiMetadata, prepareClassType, schemaRefCustomAdapter, v };
@@ -1,4 +1,5 @@
1
1
  export * from './bodySchemaWrapper.ts';
2
2
  export * from './makeSchemaLikes.ts';
3
3
  export * from './schema.ts';
4
+ export * from './schemaDynamic.ts';
4
5
  export * from './v.ts';
@@ -1,4 +1,5 @@
1
1
  import type { Constructable } from 'vona';
2
+ import type { SchemaLike } from 'vona-module-a-openapiutils';
2
3
  import type { ISchemaObjectOptions } from '../../types/decorator.ts';
3
4
  import { z } from 'zod';
4
5
  export declare function $schema(schemaLike: z.ZodSchema): z.ZodSchema;
@@ -9,3 +10,4 @@ export declare function $schema(classType: DateConstructor): z.ZodDate;
9
10
  export declare function $schema(classType: BigIntConstructor): z.ZodBigInt;
10
11
  export declare function $schema(classType: ArrayConstructor): z.ZodArray<z.ZodAny>;
11
12
  export declare function $schema<T>(classType: Constructable<T>, options?: ISchemaObjectOptions): z.ZodSchema<T>;
13
+ export declare function $schemaLazy<T>(...schemaLikes: SchemaLike[]): z.ZodSchema<T>;
@@ -0,0 +1,5 @@
1
+ import type { Constructable } from 'vona';
2
+ export declare const SymbolSchemaDynamicRefId: unique symbol;
3
+ export declare function addSchemaDynamic(dynamicName: string, classType: Constructable): void;
4
+ export declare function getSchemaDynamic(dynamicName: string): Constructable;
5
+ export declare function getSchemasDynamic(): Record<string, Constructable>;
@@ -11,3 +11,4 @@ export declare function schemaIp(options?: string | {
11
11
  export declare function schemaMin(min: number, message?: errorUtil.ErrMessage): (schema: any) => any;
12
12
  export declare function schemaMax(max: number, message?: errorUtil.ErrMessage): (schema: any) => any;
13
13
  export declare function schemaTableIdentity(): (_schema: any) => any;
14
+ export declare function schemaBigNumber(): (_schema: any) => any;
@@ -2,9 +2,10 @@ import type { Constructable } from 'vona';
2
2
  import type { SchemaLike } from 'vona-module-a-openapiutils';
3
3
  import type { ISchemaObjectOptions } from '../../../types/decorator.ts';
4
4
  import { z } from 'zod';
5
- export declare function schemaDefault<T>(defaultValue: T): (schema: z.ZodSchema) => z.ZodSchema;
5
+ export declare function schemaDefault(defaultValue: any | Function): (schema: z.ZodSchema) => z.ZodSchema;
6
6
  export declare function schemaOptional(): (schema: z.ZodSchema) => z.ZodSchema;
7
- export declare function schemaObject<T>(classType: Constructable<T>, options?: ISchemaObjectOptions): (_schema: z.ZodSchema) => z.ZodSchema<T>;
7
+ export declare function schemaLazy<T>(...schemaLikes: SchemaLike[]): (_schema?: z.ZodSchema) => z.ZodSchema<T>;
8
+ export declare function schemaObject<T>(classType: Constructable<T>, options?: ISchemaObjectOptions): (_schema?: z.ZodSchema) => z.ZodSchema<T>;
8
9
  export declare function schemaArray(schemaLike?: SchemaLike, params?: z.RawCreateParams & {
9
10
  separator?: string;
10
11
  }): (schema: z.ZodSchema) => z.ZodSchema;
@@ -1,7 +1,8 @@
1
- import { schemaEmail, schemaIp, schemaMax, schemaMin, schemaTableIdentity, schemaUrl, schemaUuid } from './v/helpers.ts';
1
+ import { schemaBigNumber, schemaEmail, schemaIp, schemaMax, schemaMin, schemaTableIdentity, schemaUrl, schemaUuid } from './v/helpers.ts';
2
2
  import { schemaDescription, schemaExample, schemaOpenapi, schemaTitle } from './v/openapi.ts';
3
- import { schemaArray, schemaDefault, schemaObject, schemaOptional } from './v/system.ts';
3
+ import { schemaArray, schemaDefault, schemaLazy, schemaObject, schemaOptional } from './v/system.ts';
4
4
  export declare const v: {
5
+ lazy: typeof schemaLazy;
5
6
  array: typeof schemaArray;
6
7
  default: typeof schemaDefault;
7
8
  object: typeof schemaObject;
@@ -13,6 +14,7 @@ export declare const v: {
13
14
  min: typeof schemaMin;
14
15
  max: typeof schemaMax;
15
16
  tableIdentity: typeof schemaTableIdentity;
17
+ bigNumber: typeof schemaBigNumber;
16
18
  openapi: typeof schemaOpenapi;
17
19
  title: typeof schemaTitle;
18
20
  description: typeof schemaDescription;
@@ -2,3 +2,4 @@ import type { Constructable } from 'vona';
2
2
  export declare function getTargetDecoratorRules(target: object): Record<PropertyKey, unknown>;
3
3
  export declare function getTargetDecoratorRuleColumns(target: object): Record<PropertyKey, unknown>;
4
4
  export declare function mergeFieldsOpenapiMetadata(target: Constructable): void;
5
+ export declare function prepareClassType<T>(classType: (() => Constructable<T>) | Constructable<T>): Constructable<T>;
@@ -1,2 +1,3 @@
1
1
  export * from './errorsAdapter.ts';
2
2
  export * from './errorUtil.ts';
3
+ export * from './schemaRefCustomAdapter.ts';
@@ -0,0 +1,2 @@
1
+ import type { VonaApplication } from 'vona';
2
+ export declare function schemaRefCustomAdapter(_app: VonaApplication): void;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "vona-module-a-openapi",
3
3
  "type": "module",
4
- "version": "5.0.25",
4
+ "version": "5.0.26",
5
5
  "title": "a-openapi",
6
6
  "vonaModule": {
7
7
  "capabilities": {
@@ -35,7 +35,7 @@
35
35
  "dependencies": {
36
36
  "@asteasolutions/zod-to-openapi": "^7.3.0",
37
37
  "@cabloy/zod-errors-custom": "^1.0.13",
38
- "@cabloy/zod-query": "^1.0.15",
38
+ "@cabloy/zod-query": "^1.0.16",
39
39
  "@zhennann/currency": "^2.0.0",
40
40
  "openapi3-ts": "^4.4.0",
41
41
  "zod": "^3.25.58"