mushroom-cli 1.2.0-alpha.18 → 1.2.0-alpha.19

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/README.md CHANGED
@@ -132,6 +132,14 @@ npx mushroom-cli parameters --no-check-update
132
132
 
133
133
  ## Version
134
134
 
135
+ ### 1.2.0-alpha.19
136
+
137
+ Improvement:
138
+
139
+ - gen-ts:
140
+ - generate type for custom methods of action
141
+ - generate description for fields, entities
142
+
135
143
  ### 1.2.0-alpha.17
136
144
 
137
145
  Improvement:
@@ -38,9 +38,6 @@ function getCSharpTypeFromMushroomType(type) {
38
38
  switch (type) {
39
39
  case 'string':
40
40
  return 'string';
41
- case 'object':
42
- case 'array':
43
- return '';
44
41
  case 'boolean':
45
42
  return 'boolean';
46
43
  case 'integer':
@@ -52,32 +49,73 @@ function getCSharpTypeFromMushroomType(type) {
52
49
  case 'IdRef':
53
50
  case 'AutoId':
54
51
  return 'IdValue';
52
+ default:
53
+ return 'any';
55
54
  }
56
- return 'UNKNOWN_TYPE_' + type;
57
55
  }
58
56
  function generateTypescriptClass(objectDefination, className, options) {
59
57
  let childrenCode = '';
60
58
  let code = `export interface ${className} {\n`;
61
59
  for (const fieldName in objectDefination) {
62
- const optionalMark = options?.checkRequired && objectDefination[fieldName].required ? '' : '?';
60
+ const field = objectDefination[fieldName];
61
+ if (!field)
62
+ continue;
63
+ if (field.description) {
64
+ code += ` /**\n * ${field.description.replace(/\r/, '').split('\n').map(line => line.includes('*/') ? line.replace(/\*\//g, "* /") : line).join('\n * ')}\n */\n`;
65
+ }
66
+ const optionalMark = options?.checkRequired && (field.required || field.validation?.required) ? '' : '?';
63
67
  const nullType = optionalMark ? ' | null' : '';
64
- if (objectDefination[fieldName].type == 'object') {
68
+ if (field.type == 'object') {
65
69
  const fieldClassName = className + '_' + toTypeScriptClassName(fieldName);
66
70
  code += ` ${fieldName}${optionalMark}: ${fieldClassName}${nullType};\n`;
67
- childrenCode += generateTypescriptClass(objectDefination[fieldName].fields ?? {}, fieldClassName);
71
+ childrenCode += generateTypescriptClass(field.fields ?? {}, fieldClassName, options);
68
72
  }
69
- else if (objectDefination[fieldName].type == 'array') {
70
- if (objectDefination[fieldName].items?.type == 'object') {
73
+ else if (field.type == 'keyValue') {
74
+ const valueNullType = options?.checkRequired && (field.values.required || field.values.validation?.required) ? '' : ' | null | undefined';
75
+ if (field.values?.type == 'object') {
71
76
  const fieldClassName = className + '_' + toTypeScriptClassName(fieldName);
72
- code += ` ${fieldName}${optionalMark}: ${fieldClassName}[]${nullType};\n`;
73
- childrenCode += generateTypescriptClass(objectDefination[fieldName].items?.fields ?? {}, fieldClassName);
77
+ code += ` ${fieldName}${optionalMark}: Record<string, ${fieldClassName}${valueNullType}>${nullType};\n`;
78
+ childrenCode += generateTypescriptClass(field.values.fields ?? {}, fieldClassName, options);
79
+ }
80
+ else if (field.values?.type == 'array') {
81
+ const itemNullType = options?.checkRequired && (field.values.items?.required || field.values.items?.validation?.required) ? '' : ' | null | undefined';
82
+ if (field.values.items?.type == 'object') {
83
+ const fieldClassName = className + '_' + toTypeScriptClassName(fieldName);
84
+ code += ` ${fieldName}${optionalMark}: Record<string, Array<${fieldClassName}${itemNullType}>${valueNullType}>${nullType};\n`;
85
+ childrenCode += generateTypescriptClass(field.values.items.fields ?? {}, fieldClassName, options);
86
+ }
87
+ else {
88
+ code += ` ${fieldName}${optionalMark}: Record<string, Array<${getCSharpTypeFromMushroomType(field.values.items?.type ?? 'string')}${itemNullType}>${valueNullType}>${nullType};\n`;
89
+ }
74
90
  }
75
91
  else {
76
- code += ` ${fieldName}${optionalMark}: ${getCSharpTypeFromMushroomType(objectDefination[fieldName].items?.type ?? '')}[]${nullType};\n`;
92
+ code += ` ${fieldName}${optionalMark}: Record<string, ${getCSharpTypeFromMushroomType(field.values?.type ?? 'string')}${valueNullType}>${nullType};\n`;
93
+ }
94
+ }
95
+ else if (field.type == 'array') {
96
+ const itemNullType = options?.checkRequired && (field.items.required || field.items.validation?.required) ? '' : ' | null | undefined';
97
+ if (field.items?.type == 'object') {
98
+ const fieldClassName = className + '_' + toTypeScriptClassName(fieldName);
99
+ code += ` ${fieldName}${optionalMark}: Array<${fieldClassName}${itemNullType}>${nullType};\n`;
100
+ childrenCode += generateTypescriptClass(field.items.fields ?? {}, fieldClassName, options);
101
+ }
102
+ else if (field.items?.type == 'keyValue') {
103
+ const valueNullType = options?.checkRequired && (field.items.values?.required || field.items.values?.validation?.required) ? '' : ' | null | undefined';
104
+ if (field.items.values?.type == 'object') {
105
+ const fieldClassName = className + '_' + toTypeScriptClassName(fieldName);
106
+ code += ` ${fieldName}${optionalMark}: Array<Record<string, ${fieldClassName}${valueNullType}>${itemNullType}>${nullType};\n`;
107
+ childrenCode += generateTypescriptClass(field.items.values.fields ?? {}, fieldClassName, options);
108
+ }
109
+ else {
110
+ code += ` ${fieldName}${optionalMark}: Array<Record<string, ${getCSharpTypeFromMushroomType(field.items.type ?? 'string')}${valueNullType}>${itemNullType}>${nullType};\n`;
111
+ }
112
+ }
113
+ else {
114
+ code += ` ${fieldName}${optionalMark}: Array<${getCSharpTypeFromMushroomType(field.items?.type ?? 'string')}${itemNullType}>${nullType};\n`;
77
115
  }
78
116
  }
79
117
  else {
80
- code += ` ${fieldName}${optionalMark}: ${getCSharpTypeFromMushroomType(objectDefination[fieldName].type)}${nullType};\n`;
118
+ code += ` ${fieldName}${optionalMark}: ${getCSharpTypeFromMushroomType(field.type ?? 'string')}${nullType};\n`;
81
119
  }
82
120
  }
83
121
  code += '}\n\n';
@@ -93,6 +131,69 @@ function generateTypescriptClassFromViewParameters(parameters) {
93
131
  }
94
132
  return '{}';
95
133
  }
134
+ function generateTopCustomClass(config, entityName, methodName, grantRole, postfix, code) {
135
+ const isKeyValue = config.type == 'keyValue';
136
+ const isArray = isKeyValue ? config.values?.type == 'array' : config.type == 'array';
137
+ const fields = isKeyValue ? (isArray ? config.values?.items?.fields : config.values?.fields) : (isArray ? config.items?.fields : config.fields);
138
+ const type = (isKeyValue ? (isArray ? config.values?.items?.type : config.values?.type) : (isArray ? config.items?.type : config.type)) ?? 'string';
139
+ let inputClassName;
140
+ if (type == 'object') {
141
+ if (fields) {
142
+ const roleIndicator = grantRole ? '_' + toTypeScriptClassName(grantRole) + '_' : '';
143
+ inputClassName = `${toTypeScriptClassName(entityName)}_${toTypeScriptClassName(methodName)}${roleIndicator}${postfix}`;
144
+ code.classesCode += generateTypescriptClass(fields, inputClassName, {
145
+ checkRequired: true
146
+ });
147
+ }
148
+ else {
149
+ inputClassName = 'any';
150
+ }
151
+ }
152
+ else
153
+ inputClassName = getCSharpTypeFromMushroomType(type);
154
+ return isKeyValue ? (isArray ? 'Record<string, ' + inputClassName + '[]>' : 'Record<string, ' + inputClassName + '>') : (isArray ? inputClassName + '[]' : inputClassName);
155
+ }
156
+ function generateCustomMethodCode(entityName, actionName, actions) {
157
+ const result = { classesCode: '', methodCode: '' };
158
+ if (!actionName || !actionName.startsWith('_raw_http_method_') || !actions || !actions.length)
159
+ return result;
160
+ actions = actions.filter(action => action.enabled);
161
+ if (!actions.length)
162
+ return result;
163
+ const methodName = actionName.substring('_raw_http_method_'.length);
164
+ let inputTypes = new Set();
165
+ let outputTypes = new Set();
166
+ actions.forEach(action => {
167
+ const codeHintDelegator = action?.codeHint?.delegator;
168
+ if (!codeHintDelegator)
169
+ return;
170
+ if (codeHintDelegator.result && !codeHintDelegator.isBinaryResponse) {
171
+ const className = generateTopCustomClass(codeHintDelegator.result, entityName, methodName, actions.length > 1 ? action.grant : '', 'Result', result);
172
+ outputTypes.add(className);
173
+ }
174
+ else {
175
+ outputTypes.add('any');
176
+ }
177
+ if (codeHintDelegator.param && codeHintDelegator.requestBody) {
178
+ let paramClassName = generateTopCustomClass(codeHintDelegator.param, entityName, methodName, actions.length > 1 ? action.grant : '', 'ParamRequest', result);
179
+ const bodyClassName = generateTopCustomClass(codeHintDelegator.requestBody, entityName, methodName, actions.length > 1 ? action.grant : '', 'Request', result);
180
+ inputTypes.add(`CustomMethodRequest<${paramClassName}, ${bodyClassName}>`);
181
+ }
182
+ else if (codeHintDelegator.param) {
183
+ const className = generateTopCustomClass(codeHintDelegator.param, entityName, methodName, actions.length > 1 ? action.grant : '', 'ParamRequest', result);
184
+ inputTypes.add(`CustomMethodParamsRequest<${className}>`);
185
+ }
186
+ else if (codeHintDelegator.requestBody) {
187
+ const className = generateTopCustomClass(codeHintDelegator.requestBody, entityName, methodName, actions.length > 1 ? action.grant : '', 'Request', result);
188
+ inputTypes.add(`CustomMethodBodyRequest<${className}>`);
189
+ }
190
+ else {
191
+ inputTypes.add('MushroomRequest');
192
+ }
193
+ });
194
+ result.methodCode = ` ${methodName}Async: (request: ${inputTypes.size ? [...inputTypes].join(' | ') : 'MushroomRequest'}) => Promise<MushroomResponse<${outputTypes.size ? [...outputTypes].join(' | ') : 'any'}>>;\n`;
195
+ return result;
196
+ }
96
197
  export function genTypescriptDriverString(aliasProject, source) {
97
198
  if (!aliasProject) {
98
199
  return '';
@@ -126,6 +227,19 @@ export const extensions = {
126
227
  export type ISODateValue = string | Date;
127
228
  export type IdValue = ${source.idType == 'AutoIncInt' || source.idType == 'AutoIncLong' ? 'number' : 'string'};
128
229
 
230
+ export interface CustomMethodRequest<TParam extends {}, TBody> extends MushroomRequest {
231
+ params?: TParam;
232
+ body?: TBody;
233
+ }
234
+
235
+ export interface CustomMethodParamsRequest<TParam extends {}> extends MushroomRequest {
236
+ params?: TParam;
237
+ }
238
+
239
+ export interface CustomMethodBodyRequest<TBody> extends MushroomRequest {
240
+ body?: TBody;
241
+ }
242
+
129
243
  `;
130
244
  let iApiClassBody = '';
131
245
  for (const entityName in entities) {
@@ -133,6 +247,9 @@ export type IdValue = ${source.idType == 'AutoIncInt' || source.idType == 'AutoI
133
247
  const typescriptClassName = toTypeScriptClassName(entityName);
134
248
  code += generateTypescriptClass(entity.fields, typescriptClassName);
135
249
  const actions = {};
250
+ if (entity.description) {
251
+ iApiClassBody += ` /**\n * ${entity.description.replace(/\r/, '').split('\n').map(line => line.includes('*/') ? line.replace(/\*\//g, "* /") : line).join('\n * ')}\n */\n`;
252
+ }
136
253
  iApiClassBody += ` ${entityName}: MushroomResourceBase`;
137
254
  let customMethodCode = '';
138
255
  for (const actionName in entity.actions) {
@@ -194,7 +311,9 @@ export type IdValue = ${source.idType == 'AutoIncInt' || source.idType == 'AutoI
194
311
  }
195
312
  default: {
196
313
  if (actionName.indexOf('_raw_http_method_') === 0) {
197
- customMethodCode += ` ${actionName.substring('_raw_http_method_'.length)}Async: (rawRequest: MushroomRequest) => Promise<MushroomResponse<any>>;\n`;
314
+ const customCode = generateCustomMethodCode(entityName, actionName, entity.actions[actionName]);
315
+ customMethodCode += customCode.methodCode;
316
+ code += customCode.classesCode;
198
317
  break;
199
318
  }
200
319
  else {
@@ -205,9 +324,7 @@ export type IdValue = ${source.idType == 'AutoIncInt' || source.idType == 'AutoI
205
324
  }
206
325
  }
207
326
  if (customMethodCode) {
208
- code += `export interface ${typescriptClassName}$CustomMethodResource {
209
- ${customMethodCode}}
210
- `;
327
+ code += `export interface ${typescriptClassName}$CustomMethodResource {\n${customMethodCode}}\n`;
211
328
  iApiClassBody += ` & ${typescriptClassName}$CustomMethodResource`;
212
329
  }
213
330
  const views = {};
@@ -290,6 +407,19 @@ export declare const extensions = {
290
407
  export declare type ISODateValue = string | Date;
291
408
  export declare type IdValue = ${source.idType == 'AutoIncInt' || source.idType == 'AutoIncLong' ? 'number' : 'string'};
292
409
 
410
+ export interface CustomMethodRequest<TParam extends {}, TBody> extends MushroomRequest {
411
+ params?: TParam;
412
+ body?: TBody;
413
+ }
414
+
415
+ export interface CustomMethodParamsRequest<TParam extends {}> extends MushroomRequest {
416
+ params?: TParam;
417
+ }
418
+
419
+ export interface CustomMethodBodyRequest<TBody> extends MushroomRequest {
420
+ body?: TBody;
421
+ }
422
+
293
423
  `;
294
424
  let iApiClassBody = '';
295
425
  for (const entityName in entities) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mushroom-cli",
3
- "version": "1.2.0-alpha.18",
3
+ "version": "1.2.0-alpha.19",
4
4
  "description": "Mushroom CLI",
5
5
  "main": "dist/mr.js",
6
6
  "type": "module",