vona-module-a-web 5.0.20 → 5.0.22

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.
@@ -11,7 +11,7 @@ export default async function (options: IMetadataCustomGenerateOptions): Promise
11
11
  contentImports.push(`import type { ${className} } from '${fileNameJSRelative}';`);
12
12
  contentFields.push(`
13
13
  export interface ${opionsName} {
14
- fields?: TypeEntityOptionsFields<${className}, ${opionsName}['_fieldsMore_']>;
14
+ fields?: TypeEntityOptionsFields<${className}, ${opionsName}[TypeSymbolKeyFieldsMore]>;
15
15
  }`);
16
16
  }
17
17
  if (contentFields.length === 0) return '';
@@ -1,3 +1,30 @@
1
+ /** pipe: begin */
2
+ export * from '../bean/pipe.query.ts';
3
+ export * from '../bean/pipe.valid.ts';
4
+ import type { IPipeOptionsQuery } from '../bean/pipe.query.ts';
5
+ import type { IPipeOptionsValid } from '../bean/pipe.valid.ts';
6
+ import 'vona';
7
+ declare module 'vona-module-a-aspect' {
8
+ interface IPipeRecordLocal {
9
+ 'a-web:query': IPipeOptionsQuery;
10
+ 'a-web:valid': IPipeOptionsValid;
11
+ }
12
+ }
13
+ declare module 'vona-module-a-web' {
14
+ interface PipeQuery {
15
+ }
16
+ interface PipeQuery {
17
+ get $beanFullName(): 'a-web.pipe.query';
18
+ get $onionName(): 'a-web:query';
19
+ }
20
+ interface PipeValid {
21
+ }
22
+ interface PipeValid {
23
+ get $beanFullName(): 'a-web.pipe.valid';
24
+ get $onionName(): 'a-web:valid';
25
+ }
26
+ }
27
+ /** pipe: end */
1
28
  /** bean: begin */
2
29
  export * from '../bean/bean.router.ts';
3
30
  import 'vona';
@@ -28,6 +55,10 @@ declare module 'vona-module-a-bean' {
28
55
  declare module 'vona-module-a-web' {
29
56
  interface ServiceWeb {
30
57
  }
58
+ interface ServiceWeb {
59
+ get $beanFullName(): 'a-web.service.web';
60
+ get $onionName(): 'a-web:web';
61
+ }
31
62
  }
32
63
  /** service: end */
33
64
  /** service: begin */
@@ -55,6 +86,10 @@ declare module 'vona-module-a-startup' {
55
86
  declare module 'vona-module-a-web' {
56
87
  interface StartupListen {
57
88
  }
89
+ interface StartupListen {
90
+ get $beanFullName(): 'a-web.startup.listen';
91
+ get $onionName(): 'a-web:listen';
92
+ }
58
93
  }
59
94
  /** startup: end */
60
95
  /** config: begin */
@@ -0,0 +1,29 @@
1
+ import type { VonaContext } from 'vona';
2
+ import type { IDecoratorPipeOptions, IDecoratorPipeOptionsArgument, IPipeTransform } from 'vona-module-a-aspect';
3
+ import type { ISchemaObjectExtensionField, RouteHandlerArgumentMeta } from 'vona-module-a-openapi';
4
+ import type { IQueryParams } from 'vona-module-a-orm';
5
+ import type { ValidatorOptions } from 'vona-module-a-validation';
6
+ import type z from 'zod';
7
+ import { BeanBase } from 'vona';
8
+ export interface IPipeOptionsQuery extends IDecoratorPipeOptions, IDecoratorPipeOptionsArgument, ValidatorOptions {
9
+ transform?: TypePipeOptionsQueryTransform;
10
+ }
11
+ export interface IPipeOptionsQueryTransformInfo {
12
+ params: IQueryParams;
13
+ query: any;
14
+ options: IPipeOptionsQuery;
15
+ originalName: string;
16
+ fullName: string;
17
+ key: string;
18
+ value: any;
19
+ schema: z.ZodSchema;
20
+ openapi?: ISchemaObjectExtensionField;
21
+ }
22
+ export type TypePipeOptionsQueryTransform = (ctx: VonaContext, info: IPipeOptionsQueryTransformInfo) => boolean | undefined;
23
+ export declare class PipeQuery extends BeanBase implements IPipeTransform<any> {
24
+ transform(value: any, metadata: RouteHandlerArgumentMeta, options: IPipeOptionsQuery): Promise<any>;
25
+ private _transform;
26
+ private _transformSystem;
27
+ private _transformFields;
28
+ }
29
+ export declare const ArgQuery: (options?: Partial<IPipeOptionsQuery> | undefined) => any;
@@ -0,0 +1,10 @@
1
+ import type { IDecoratorPipeOptions, IDecoratorPipeOptionsArgument, IPipeTransform } from 'vona-module-a-aspect';
2
+ import type { RouteHandlerArgumentMeta } from 'vona-module-a-openapi';
3
+ import type { ValidatorOptions } from 'vona-module-a-validation';
4
+ import { BeanBase } from 'vona';
5
+ export interface IPipeOptionsValid extends IDecoratorPipeOptions, IDecoratorPipeOptionsArgument, ValidatorOptions {
6
+ }
7
+ export declare class PipeValid extends BeanBase implements IPipeTransform<any> {
8
+ transform(value: any, metadata: RouteHandlerArgumentMeta, options: IPipeOptionsValid): Promise<any>;
9
+ }
10
+ export declare const ArgValid: (options?: Partial<IPipeOptionsValid> | undefined) => any;
package/dist/index.js CHANGED
@@ -1,16 +1,155 @@
1
- import { appMetadata, BeanInfo, BeanBase, appResource, deepExtend, compose, cast, BeanSimple, BeanScopeBase, createBeanDecorator } from 'vona';
1
+ import { HttpStatus, BeanInfo, BeanBase, appMetadata, appResource, deepExtend, compose, cast, BeanSimple, BeanScopeBase, createBeanDecorator } from 'vona';
2
+ import { isNil, combineParamsAndQuery } from '@cabloy/utils';
3
+ import { ZodMetadata } from '@cabloy/zod-query';
4
+ import { Pipe, createArgumentPipe, setArgumentPipe } from 'vona-module-a-aspect';
2
5
  import * as ModuleInfo from '@cabloy/module-info';
3
6
  import { Bean, Service, Scope } from 'vona-module-a-bean';
4
7
  import { SymbolUseOnionOptions } from 'vona-module-a-onion';
5
- import { SymbolRouteHandlersArgumentsValue, SymbolRouteHandlersArgumentsMeta, mergeFieldsOpenapiMetadata } from 'vona-module-a-openapi';
6
- import { valid } from 'vona-module-a-validation';
8
+ import { SymbolRouteHandlersArgumentsValue, SymbolRouteHandlersArgumentsMeta, makeSchemaLikes, $schema, mergeFieldsOpenapiMetadata } from 'vona-module-a-openapi';
7
9
  import { SymbolUploadValue } from 'vona-module-a-upload';
8
10
  import http from 'node:http';
9
11
  import { Startup } from 'vona-module-a-startup';
10
12
  import Router from 'find-my-way';
11
13
  import { SymbolRouterMiddleware } from 'vona-module-a-executor';
14
+ import { z } from 'zod';
12
15
  import { SymbolOpenApiOptions } from 'vona-module-a-openapiutils';
13
- import { combineParamsAndQuery } from '@cabloy/utils';
16
+
17
+ var _dec$5, _dec2$5, _class$5;
18
+ const __FieldsSystem = ['columns', 'where', 'orders', 'pageNo', 'pageSize'];
19
+ let PipeQuery = (_dec$5 = Pipe({
20
+ // ValidatorOptions
21
+ disableErrorMessages: false,
22
+ errorHttpStatusCode: HttpStatus.BAD_REQUEST,
23
+ passthrough: false,
24
+ strict: false
25
+ }), _dec2$5 = BeanInfo({
26
+ module: "a-web"
27
+ }), _dec$5(_class$5 = _dec2$5(_class$5 = class PipeQuery extends BeanBase {
28
+ async transform(value, metadata, options) {
29
+ if (!options.schema) throw new Error(`should specify the schema of pipeQuery: ${metadata.controller.name}.${metadata.method}#${metadata.index}`);
30
+ // validateSchema
31
+ value = await this.bean.validator.validateSchema(options.schema, value, options, metadata.field);
32
+ // transform
33
+ value = this._transform(value, options);
34
+ // ok
35
+ return value;
36
+ }
37
+ _transform(value, options) {
38
+ // 1. system: columns/where/orders/pageNo/pageSize
39
+ const params = this._transformSystem(value);
40
+ // 2. fields
41
+ return this._transformFields(params, value, options);
42
+ }
43
+
44
+ // system: columns/where/orders/pageNo/pageSize
45
+ _transformSystem(value) {
46
+ const params = {};
47
+ // columns
48
+ if (!isNil(value.columns)) params.columns = value.columns;
49
+ // where
50
+ params.where = value.where ?? {};
51
+ // orders
52
+ if (!isNil(value.orders)) {
53
+ if (typeof value.orders === 'string') {
54
+ if (value.orders.startsWith('[') && value.orders.endsWith(']')) {
55
+ params.orders = JSON.parse(value.orders);
56
+ } else {
57
+ params.orders = [value.orders.split(',')];
58
+ }
59
+ } else {
60
+ params.orders = value.orders;
61
+ }
62
+ }
63
+ // pageNo/pageSize
64
+ if (!isNil(value.pageNo) && !isNil(value.pageSize)) {
65
+ params.offset = (value.pageNo - 1) * value.pageSize;
66
+ params.limit = value.pageSize;
67
+ }
68
+ // ok
69
+ return params;
70
+ }
71
+ _transformFields(params, value, options) {
72
+ for (const key in value) {
73
+ if (__FieldsSystem.includes(key)) continue;
74
+ const fieldSchema = ZodMetadata.unwrapChained(ZodMetadata.getFieldSchema(options.schema, key));
75
+ if (!fieldSchema) continue;
76
+ // openapi
77
+ const openapi = ZodMetadata.getOpenapiMetadata(fieldSchema);
78
+ // name
79
+ const originalName = openapi?.query?.originalName ?? key;
80
+ let fullName;
81
+ // joins
82
+ if (openapi?.query?.join) {
83
+ if (!params.joins) params.joins = [];
84
+ const joinType = openapi.query.join.type ?? 'innerJoin';
85
+ const joinTable = openapi.query.join.table;
86
+ const joinOn = openapi.query.join.on;
87
+ if (params.joins.findIndex(item => item[1] === joinTable) === -1) {
88
+ params.joins.push([joinType, joinTable, joinOn]);
89
+ }
90
+ fullName = `${joinTable}.${originalName}`;
91
+ } else {
92
+ fullName = originalName;
93
+ }
94
+ // check where
95
+ if (params.where[fullName]) continue;
96
+ // custom transform
97
+ if (options.transform) {
98
+ const res = options.transform(this.ctx, {
99
+ params,
100
+ query: value,
101
+ options,
102
+ originalName,
103
+ fullName,
104
+ key,
105
+ value: value[key],
106
+ schema: fieldSchema,
107
+ openapi
108
+ });
109
+ if (res === true || res === false) continue;
110
+ }
111
+ // default transform
112
+ let op = openapi?.query?.op;
113
+ if (!op) {
114
+ const typeName = fieldSchema._def.typeName;
115
+ if (typeName === 'ZodString') {
116
+ op = '_includesI_';
117
+ } else {
118
+ op = '_eq_';
119
+ }
120
+ }
121
+ if (op === '_eq_') {
122
+ params.where[fullName] = value[key];
123
+ } else {
124
+ params.where[fullName] = {
125
+ [op]: value[key]
126
+ };
127
+ }
128
+ }
129
+ return params;
130
+ }
131
+ }) || _class$5) || _class$5);
132
+ const ArgQuery = createArgumentPipe('a-web:query');
133
+
134
+ var _dec$4, _dec2$4, _class$4;
135
+ let PipeValid = (_dec$4 = Pipe({
136
+ // ValidatorOptions
137
+ disableErrorMessages: false,
138
+ errorHttpStatusCode: HttpStatus.BAD_REQUEST,
139
+ passthrough: false,
140
+ strict: false
141
+ }), _dec2$4 = BeanInfo({
142
+ module: "a-web"
143
+ }), _dec$4(_class$4 = _dec2$4(_class$4 = class PipeValid extends BeanBase {
144
+ async transform(value, metadata, options) {
145
+ if (options.schema) {
146
+ // validateSchema
147
+ return await this.bean.validator.validateSchema(options.schema, value, options, metadata.field);
148
+ }
149
+ return value;
150
+ }
151
+ }) || _class$4) || _class$4);
152
+ const ArgValid = createArgumentPipe('a-web:valid');
14
153
 
15
154
  async function middlewareGuard(ctx, next) {
16
155
  // check handler
@@ -35,6 +174,7 @@ function extractValue(ctx, argMeta) {
35
174
  return exchangeKeyForValue(ctx, argMeta.type, argMeta.field);
36
175
  }
37
176
  function exchangeKeyForValue(ctx, type, field) {
177
+ if (!type) throw new Error('argument type should not empty');
38
178
  const req = ctx.request;
39
179
  const res = ctx.response;
40
180
  const modes = {
@@ -99,7 +239,7 @@ async function _transformArguments(ctx, controller, handler) {
99
239
  length: paramtypes.length
100
240
  });
101
241
  for (let index = args.length - 1; index >= 0; index--) {
102
- const argMeta = argsMeta.find(item => item.index === index);
242
+ const argMeta = argsMeta.find(item => item?.index === index);
103
243
  if (!argMeta) continue;
104
244
  // extractValue
105
245
  const value = await _extractArgumentValue(ctx, argMeta);
@@ -171,11 +311,6 @@ function composePipes(ctx, argMeta, executeCustom) {
171
311
  function _collectArgumentMiddlewares(onionPipe, argMeta) {
172
312
  if (!argMeta.pipes) return;
173
313
  return argMeta.pipes.map(pipe => {
174
- if (typeof pipe !== 'function') {
175
- pipe = valid({
176
- schema: pipe
177
- });
178
- }
179
314
  const {
180
315
  pipeName,
181
316
  options
@@ -514,6 +649,85 @@ let ScopeModuleAWeb = (_dec = Scope(), _dec2 = BeanInfo({
514
649
 
515
650
  /** scope: end */
516
651
 
652
+ function createPipesArgumentDecorator(paramType, extractValue) {
653
+ return function (field, ...schemaLikes) {
654
+ return function (target, prop, index) {
655
+ const hasParamField = typeof field === 'string';
656
+ const paramField = hasParamField ? field : undefined;
657
+ const paramSchemaLikes = hasParamField ? schemaLikes : [field, ...schemaLikes].filter(item => !!item);
658
+ const paramtypes = appMetadata.getMetadata('design:paramtypes', target, prop);
659
+ let metaType;
660
+ if (paramType === 'file') {
661
+ metaType = z.string().openapi({
662
+ format: 'binary'
663
+ });
664
+ } else if (paramType === 'files') {
665
+ metaType = z.array(z.string().openapi({
666
+ format: 'binary'
667
+ }));
668
+ } else {
669
+ metaType = paramtypes[index];
670
+ }
671
+ const argSchema = makeSchemaLikes(paramSchemaLikes, metaType);
672
+ setArgumentPipe('a-web:valid', {
673
+ type: paramType,
674
+ field: paramField,
675
+ schema: argSchema,
676
+ extractValue
677
+ }, target, prop, index);
678
+ };
679
+ };
680
+ }
681
+
682
+ function Param(property, ...schemaLikes) {
683
+ return createPipesArgumentDecorator('param')(property, ...schemaLikes);
684
+ }
685
+ function Query(property, ...schemaLikes) {
686
+ return createPipesArgumentDecorator('query')(property, ...schemaLikes);
687
+ }
688
+ function Body(property, ...schemaLikes) {
689
+ return createPipesArgumentDecorator('body')(property, ...schemaLikes);
690
+ }
691
+ function Headers(property, ...schemaLikes) {
692
+ return createPipesArgumentDecorator('headers')(property, ...schemaLikes);
693
+ }
694
+ function Fields(property, ...schemaLikes) {
695
+ return createPipesArgumentDecorator('fields')(property, ...schemaLikes);
696
+ }
697
+ function Field(property, ...schemaLikes) {
698
+ return createPipesArgumentDecorator('field')(property, ...schemaLikes);
699
+ }
700
+ function Files(property, ...schemaLikes) {
701
+ return createPipesArgumentDecorator('files')(property, ...schemaLikes);
702
+ }
703
+ function File(property, ...schemaLikes) {
704
+ return createPipesArgumentDecorator('file')(property, ...schemaLikes);
705
+ }
706
+ function User(...schemaLikes) {
707
+ return createPipesArgumentDecorator('user')(undefined, ...schemaLikes);
708
+ }
709
+ function ArgQueryPro(schemaLike) {
710
+ return function (target, prop, index) {
711
+ const schema = $schema(schemaLike);
712
+ setArgumentPipe('a-web:query', {
713
+ type: 'query',
714
+ schema
715
+ }, target, prop, index);
716
+ };
717
+ }
718
+ const Arg = {
719
+ param: Param,
720
+ query: Query,
721
+ body: Body,
722
+ headers: Headers,
723
+ fields: Fields,
724
+ field: Field,
725
+ files: Files,
726
+ file: File,
727
+ user: User,
728
+ queryPro: ArgQueryPro
729
+ };
730
+
517
731
  function Controller(path, options) {
518
732
  if (typeof path === 'string') {
519
733
  options = Object.assign({}, options, {
@@ -522,7 +736,7 @@ function Controller(path, options) {
522
736
  } else {
523
737
  options = path || {};
524
738
  }
525
- return createBeanDecorator('controller', options, false, false, target => {
739
+ return createBeanDecorator('controller', options, false, target => {
526
740
  // beanOptions
527
741
  const beanOptions = appResource.getBean(target);
528
742
  // IOpenApiOptions
@@ -536,7 +750,7 @@ function Controller(path, options) {
536
750
  });
537
751
  }
538
752
  function Dto(options) {
539
- return createBeanDecorator('dto', options, false, false, target => {
753
+ return createBeanDecorator('dto', options, false, target => {
540
754
  mergeFieldsOpenapiMetadata(target);
541
755
  });
542
756
  }
@@ -611,4 +825,4 @@ function $apiPathAndCombineParamsAndQuery(path, options) {
611
825
  return combineParamsAndQuery(path, options);
612
826
  }
613
827
 
614
- export { $apiPath, $apiPathAndCombineParamsAndQuery, BeanRouter, Controller, Dto, Main, RequestMapping, ScopeModuleAWeb, ServiceWeb, StartupListen, SymbolRequestMappingHandler, Web, config, mergeActionsOpenapiMetadata };
828
+ export { $apiPath, $apiPathAndCombineParamsAndQuery, Arg, ArgQuery, ArgValid, BeanRouter, Controller, Dto, Main, PipeQuery, PipeValid, RequestMapping, ScopeModuleAWeb, ServiceWeb, StartupListen, SymbolRequestMappingHandler, Web, config, createPipesArgumentDecorator, mergeActionsOpenapiMetadata };
@@ -0,0 +1,42 @@
1
+ import type { Constructable } from 'vona';
2
+ import type { SchemaLike } from 'vona-module-a-openapiutils';
3
+ import type z from 'zod';
4
+ declare function Param(): ParameterDecorator;
5
+ declare function Param(...schemaLikes: SchemaLike[]): ParameterDecorator;
6
+ declare function Param(property: string, ...schemaLikes: SchemaLike[]): ParameterDecorator;
7
+ declare function Query(): ParameterDecorator;
8
+ declare function Query(...schemaLikes: SchemaLike[]): ParameterDecorator;
9
+ declare function Query(property: string, ...schemaLikes: SchemaLike[]): ParameterDecorator;
10
+ declare function Body(): ParameterDecorator;
11
+ declare function Body(...schemaLikes: SchemaLike[]): ParameterDecorator;
12
+ declare function Body(property: string, ...schemaLikes: SchemaLike[]): ParameterDecorator;
13
+ declare function Headers(): ParameterDecorator;
14
+ declare function Headers(...schemaLikes: SchemaLike[]): ParameterDecorator;
15
+ declare function Headers(property: string, ...schemaLikes: SchemaLike[]): ParameterDecorator;
16
+ declare function Fields(): ParameterDecorator;
17
+ declare function Fields(...schemaLikes: SchemaLike[]): ParameterDecorator;
18
+ declare function Fields(property: string, ...schemaLikes: SchemaLike[]): ParameterDecorator;
19
+ declare function Field(): ParameterDecorator;
20
+ declare function Field(...schemaLikes: SchemaLike[]): ParameterDecorator;
21
+ declare function Field(property: string, ...schemaLikes: SchemaLike[]): ParameterDecorator;
22
+ declare function Files(): ParameterDecorator;
23
+ declare function Files(...schemaLikes: SchemaLike[]): ParameterDecorator;
24
+ declare function Files(property: string, ...schemaLikes: SchemaLike[]): ParameterDecorator;
25
+ declare function File(): ParameterDecorator;
26
+ declare function File(...schemaLikes: SchemaLike[]): ParameterDecorator;
27
+ declare function File(property: string, ...schemaLikes: SchemaLike[]): ParameterDecorator;
28
+ declare function User(...schemaLikes: SchemaLike[]): ParameterDecorator;
29
+ declare function ArgQueryPro(schemaLike: z.ZodSchema | Constructable): any;
30
+ export declare const Arg: {
31
+ param: typeof Param;
32
+ query: typeof Query;
33
+ body: typeof Body;
34
+ headers: typeof Headers;
35
+ fields: typeof Fields;
36
+ field: typeof Field;
37
+ files: typeof Files;
38
+ file: typeof File;
39
+ user: typeof User;
40
+ queryPro: typeof ArgQueryPro;
41
+ };
42
+ export {};
@@ -3,5 +3,5 @@ import type { IDecoratorControllerOptions } from '../../types/controller.ts';
3
3
  import type { IDecoratorDtoOptions } from '../../types/dto.ts';
4
4
  export declare function Controller<T extends IDecoratorControllerOptions>(options?: T): ClassDecorator;
5
5
  export declare function Controller<T extends IDecoratorControllerOptions>(path?: string, options?: Omit<T, 'path'>): ClassDecorator;
6
- export declare function Dto<T extends IDecoratorDtoOptions<any>>(options?: Omit<T, '_fieldsMore_'>): ClassDecorator;
6
+ export declare function Dto<T extends IDecoratorDtoOptions<any>>(options?: T): ClassDecorator;
7
7
  export declare function mergeActionsOpenapiMetadata(target: Constructable): void;
@@ -1,3 +1,5 @@
1
+ export * from './arguments.ts';
1
2
  export * from './bean.ts';
3
+ export * from './pipesArgument.ts';
2
4
  export * from './request.ts';
3
5
  export * from './response.ts';
@@ -0,0 +1,3 @@
1
+ import type { RouteHandlerArgumentType, TypeExtractValue } from 'vona-module-a-openapi';
2
+ import type { SchemaLike } from 'vona-module-a-openapiutils';
3
+ export declare function createPipesArgumentDecorator(paramType: RouteHandlerArgumentType, extractValue?: TypeExtractValue): (field?: string | SchemaLike, ...schemaLikes: SchemaLike[]) => ParameterDecorator;
@@ -1,12 +1,13 @@
1
1
  import type { OmitNever } from 'vona';
2
2
  import type { ServiceOnion } from 'vona-module-a-onion';
3
3
  import type { TypeOpenapiMetadata } from 'vona-module-a-openapi';
4
+ import type { SymbolKeyFieldsMore } from 'vona-module-a-orm';
4
5
  export interface IDtoRecord {
5
6
  }
6
7
  export interface IDecoratorDtoOptions<FieldsMore = never> {
8
+ [SymbolKeyFieldsMore]?: FieldsMore;
7
9
  independent?: boolean;
8
10
  openapi?: TypeOpenapiMetadata;
9
- _fieldsMore_?: FieldsMore;
10
11
  }
11
12
  declare module 'vona-module-a-onion' {
12
13
  interface BeanOnion {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "vona-module-a-web",
3
3
  "type": "module",
4
- "version": "5.0.20",
4
+ "version": "5.0.22",
5
5
  "title": "a-web",
6
6
  "vonaModule": {
7
7
  "capabilities": {
@@ -11,7 +11,6 @@
11
11
  "onions": {
12
12
  "dto": {
13
13
  "sceneIsolate": true,
14
- "optionsCustomInterfaceTemplate": "Omit<{{optionsCustomInterface}}, '_fieldsMore_'>",
15
14
  "optionsGlobalInterfaceName": "IDecoratorDtoOptions",
16
15
  "optionsGlobalInterfaceFrom": "vona-module-a-web",
17
16
  "boilerplate": "cli/dto/boilerplate",