mushroom-cli 1.2.7 → 2.0.0-alpha.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.
@@ -1,16 +1,19 @@
1
1
  import fs from 'fs';
2
2
  import * as common from '../common.js';
3
+ import { getExtensionEventsCode } from './csharp/extEvents.js';
3
4
  const packageVersion = common.getPackageVersion();
4
5
  const newLine = '\n';
5
6
  const header = `// NOTE: Please do not modify this file
6
7
  // NOTE: Version and compatibility information: please see in Info.cs file
7
8
 
8
9
  // ReSharper disable CheckNamespace
10
+ // ReSharper disable ClassCannotBeInstantiated
9
11
  // ReSharper disable CommentTypo
10
12
  // ReSharper disable EmptyNamespace
11
13
  // ReSharper disable IdentifierTypo
12
14
  // ReSharper disable InconsistentNaming
13
15
  // ReSharper disable PartialTypeWithSinglePart
16
+ // ReSharper disable RedundantTypeArgumentsOfMethod
14
17
  // ReSharper disable RedundantUsingDirective
15
18
  // ReSharper disable StringLiteralTypo
16
19
  // ReSharper disable UnusedMember.Global
@@ -18,10 +21,33 @@ const header = `// NOTE: Please do not modify this file
18
21
  // ReSharper disable UnusedParameter.Local
19
22
  // ReSharper disable UnusedTypeParameter
20
23
  `;
21
- function singleLine(str) {
22
- if (!str)
23
- return '';
24
- return str.replace(/\r/g, '').replace(/\n/g, '<br/>');
24
+ const infoContent = `// Mushroom CLI version: ${packageVersion} (https://www.npmjs.com/package/mushroomjs)${newLine}// Compatible with Mushroom Server version: 0.3 or higher (https://www.nuget.org/packages/Mushroom/)`;
25
+ const helperMethods = `
26
+ public delegate T GetT<out T>(Mushroom.ActionArguments arg);
27
+ private void RegisterCustomMethod<T>(GetT<T> handler) { }
28
+ public delegate TResult GetT<out TResult, in TArguments>(TArguments arg);
29
+ private void RegisterCustomMethod<TResult, TArguments>(GetT<TResult, TArguments> handler) { }
30
+ private void RegisterCustomViewMethod(Mushroom.MushroomViewHandler handler) { }
31
+ private void RegisterCustomVnTextBuilderMethod(Mushroom.Features.VnText.TextProcess handler) { }
32
+ private void RegisterEvent(Mushroom.BeforeInvokeCommandAsyncHandler handler) { }
33
+ private void RegisterEvent(Mushroom.BeforeInvokeCommandHandler handler) { }
34
+ private void RegisterBeforeEvent(Mushroom.Events.BeforeRequestEvent handler) { }
35
+ private void RegisterAfterEvent(Mushroom.Events.AfterRequestEvent handler) { }
36
+ private void RegisterAfterEvent<T>(Mushroom.Events.AfterRequestEvent<T> handler) { }
37
+ private void RegisterCustomLoginAsyncHandler(Mushroom.Extensions.DefaultAuth.LoginAsyncHandler handler) { }
38
+ private void RegisterGetAuthLogInfoAsyncHandler(Mushroom.Extensions.DefaultAuth.LoginAsyncHandler handler) { }
39
+ private void RegisterLoginSuccessHandler(Mushroom.Extensions.DefaultAuth.LoginEvents.LoginSuccessHandler handler) { }
40
+ private void RegisterSendCodeItemHandler(Mushroom.Extensions.DefaultAuth.SendCodeItemHandler handler) { }
41
+ private void RegisterJob<T>() where T : Mushroom.Job.JobBase { }
42
+ `;
43
+ const xmlEntities = {
44
+ '<': '&lt;',
45
+ '>': '&gt;',
46
+ '&': '&amp;',
47
+ '\n': '<br/>',
48
+ };
49
+ function escapseForXmlDocs(str) {
50
+ return str?.replace(/[<>&\n\r]/g, (c) => xmlEntities[c] ?? c) ?? '';
25
51
  }
26
52
  function toCSharpName(str) {
27
53
  if (!str)
@@ -101,31 +127,29 @@ function generateEnumClass(source, out, field, defaultClassName) {
101
127
  }
102
128
  const type = getCSharpTypeFromMushroomType(source, mrType, true);
103
129
  validation.codeHint = validation.codeHint || {};
104
- if (validation.validValues) {
105
- validation.codeHint.validValues = validation.codeHint.validValues || {};
106
- if (!validation.codeHint.validValues.disabled) {
107
- const enumClassName = validation.codeHint.validValues.className || defaultClassName;
108
- out.arrEnumClassNames ?? (out.arrEnumClassNames = []);
109
- if (!out.arrEnumClassNames.includes(enumClassName)) {
110
- out.arrEnumClassNames.push(enumClassName);
111
- strEnumClasses += ` /// <summary>
112
- /// ${singleLine(validation.codeHint.validValues.description || field.description)}
130
+ validation.codeHint.validValues = validation.codeHint.validValues || {};
131
+ if (validation.codeHint.validValues.disabled)
132
+ return '';
133
+ const enumClassName = validation.codeHint.validValues.className || defaultClassName;
134
+ out.arrEnumClassNames ?? (out.arrEnumClassNames = []);
135
+ if (!out.arrEnumClassNames.includes(enumClassName)) {
136
+ out.arrEnumClassNames.push(enumClassName);
137
+ strEnumClasses += ` /// <summary>
138
+ /// ${escapseForXmlDocs(validation.codeHint.validValues.description || field.description)}
113
139
  /// </summary>
114
140
  public partial class ${enumClassName}
115
141
  {
116
142
  private ${enumClassName}() { }
117
143
 
118
144
  `;
119
- const enumProperties = validation.codeHint.validValues.nameMap || validation.validValues;
120
- for (let i = 0; i < enumProperties.length && i < validation.validValues.length; i++) {
121
- strEnumClasses += ` public const ${type} ${toCSharpName(enumProperties[i])} = ${getCSharpInitValue(type, validation.validValues[i])};
145
+ const enumProperties = validation.codeHint.validValues.nameMap || validation.validValues;
146
+ for (let i = 0; i < enumProperties.length && i < validation.validValues.length; i++) {
147
+ strEnumClasses += ` public const ${type} ${toCSharpName(enumProperties[i])} = ${getCSharpInitValue(type, validation.validValues[i])};
122
148
  `;
123
- }
124
- strEnumClasses += ` }
149
+ }
150
+ strEnumClasses += ` }
125
151
 
126
152
  `;
127
- }
128
- }
129
153
  }
130
154
  return strEnumClasses;
131
155
  }
@@ -144,13 +168,13 @@ function groupCSharpMethodHandlerByMethod(handlers) {
144
168
  return prev;
145
169
  }, {});
146
170
  }
147
- function generateCSharpClassMongoDb(source, className, fields, isRoot, description, out) {
171
+ function generateCSharpClassMongoDb(source, className, fields, isRoot, description, out, aliasProject) {
148
172
  let strClasses = '';
149
173
  let strEnumClasses = '';
150
174
  let content = '';
151
175
  if (description) {
152
176
  content += ` /// <summary>
153
- /// ${singleLine(description)}
177
+ /// ${escapseForXmlDocs(description)}
154
178
  /// </summary>
155
179
  `;
156
180
  }
@@ -177,14 +201,13 @@ function generateCSharpClassMongoDb(source, className, fields, isRoot, descripti
177
201
  }
178
202
  else if (field.type === 'object') {
179
203
  strClasses +=
180
- generateCSharpClassMongoDb(source, className + '_' + propertyName, field.fields ?? {}, false, null, out) +
181
- newLine;
204
+ generateCSharpClassMongoDb(source, className + '_' + propertyName, field.fields ?? {}, false, null, out, aliasProject) + newLine;
182
205
  type = className + '_' + propertyName;
183
206
  }
184
207
  else if (field.type === 'array') {
185
208
  if (field.items?.type === 'object') {
186
209
  strClasses +=
187
- generateCSharpClassMongoDb(source, className + '_' + propertyName, field.items.fields ?? {}, false, null, out) + newLine;
210
+ generateCSharpClassMongoDb(source, className + '_' + propertyName, field.items.fields ?? {}, false, null, out, aliasProject) + newLine;
188
211
  type = `System.Collections.Generic.List<${className}_${propertyName}>`;
189
212
  }
190
213
  else if (field.items) {
@@ -194,7 +217,7 @@ function generateCSharpClassMongoDb(source, className, fields, isRoot, descripti
194
217
  else
195
218
  type = getCSharpTypeFromMushroomType(source, field.type, field.validation && field.validation.required);
196
219
  content += ` /// <summary>
197
- /// ${singleLine(field.description)}
220
+ /// ${escapseForXmlDocs(field.description)}
198
221
  /// </summary>
199
222
  `;
200
223
  if (isRoot && fieldName === 'id') {
@@ -216,30 +239,76 @@ function generateCSharpClassMongoDb(source, className, fields, isRoot, descripti
216
239
  content +=
217
240
  ' [MongoDB.Bson.Serialization.Attributes.BsonDateTimeOptions(Kind = System.DateTimeKind.Local)]\n';
218
241
  }
219
- if (field.type === 'array' && field.items) {
220
- if ((field.items.type === 'AutoId' || field.items.type === 'IdRef') && source.idType === 'ObjectId') {
242
+ if (field.type === 'array') {
243
+ if ((field.items?.type === 'AutoId' || field.items?.type === 'IdRef') && source.idType === 'ObjectId') {
221
244
  content +=
222
245
  ' [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.ObjectId)]\n';
223
246
  }
224
- if (field.items.type === 'AutoId' && source.idType === 'GUID') {
247
+ if (field.items?.type === 'AutoId' && source.idType === 'GUID') {
225
248
  content += ' [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.String)]\n';
226
249
  }
227
- if (field.items.type === 'datetime') {
250
+ if (field.items?.type === 'datetime') {
228
251
  content +=
229
252
  ' [MongoDB.Bson.Serialization.Attributes.BsonDateTimeOptions(Kind = System.DateTimeKind.Local)]\n';
230
253
  }
231
254
  }
232
- content += ` public ${type} ${propertyName} { get; set; }\n\n`;
233
- strEnumClasses += generateEnumClass(source, out, field, `${className.toUpperCase()}_${propertyName.toUpperCase()}_ENUM`);
255
+ content += ` public ${type} ${propertyName} { get; set; }${newLine}${newLine}`;
256
+ const strEnumClass = generateEnumClass(source, out, field, `${className.toUpperCase()}_${propertyName.toUpperCase()}_ENUM`);
257
+ if (!strEnumClass)
258
+ continue;
259
+ strEnumClasses += strEnumClass;
260
+ if (aliasProject.outputToFolder) {
261
+ const match = strEnumClass.match(/public partial class\s+(\w+)/);
262
+ if (!match)
263
+ continue;
264
+ common.ensureFolder(aliasProject.output + '/Enums', true);
265
+ const namespace = toCSharpName(source.name);
266
+ const fileContent = `${header}
267
+
268
+ namespace ${namespace}.Enums
269
+ {
270
+ ${strEnumClass}
271
+ }
272
+ `;
273
+ fs.writeFileSync(aliasProject.output + '/Enums/' + match[1] + '.cs', fileContent);
274
+ }
234
275
  }
235
276
  content += ` [MongoDB.Bson.Serialization.Attributes.BsonExtraElements]
277
+ [Newtonsoft.Json.JsonIgnore]
278
+ [System.Text.Json.Serialization.JsonIgnore]
236
279
  public System.Collections.Generic.Dictionary<string, object> Mushroom_ExtraProperties { get; set; }
237
280
 
238
281
  }
239
282
  `;
240
- if (strEnumClasses) {
241
- out.strEnumClasses ?? (out.strEnumClasses = '');
242
- out.strEnumClasses += strEnumClasses;
283
+ if (aliasProject.outputToFolder) {
284
+ common.ensureFolder(aliasProject.output + '/Resources', true);
285
+ const namespace = toCSharpName(source.name);
286
+ content = `${header}
287
+
288
+ namespace ${namespace}.Resources
289
+ {
290
+ ${content}
291
+ }
292
+ `;
293
+ const normalizedName = className.toLowerCase();
294
+ out.allClasses ?? (out.allClasses = []);
295
+ const duplicate = out.allClasses.find((c) => c.normalizedName == normalizedName);
296
+ if (duplicate) {
297
+ fs.appendFileSync(aliasProject.output + '/Resources/' + duplicate.className + '.cs', content);
298
+ }
299
+ else {
300
+ out.allClasses.push({
301
+ className,
302
+ normalizedName,
303
+ });
304
+ fs.writeFileSync(aliasProject.output + '/Resources/' + className + '.cs', content);
305
+ }
306
+ }
307
+ else {
308
+ if (strEnumClasses) {
309
+ out.strEnumClasses ?? (out.strEnumClasses = '');
310
+ out.strEnumClasses += strEnumClasses;
311
+ }
243
312
  }
244
313
  return strClasses + newLine + content;
245
314
  }
@@ -254,39 +323,44 @@ function getCSharpFunc(methodName, methodType) {
254
323
  export function genCSharpMongoDbClasses(args, projectName, project, alias, source) {
255
324
  const aliasProject = ((project.csharpMongo || {}).alias || {})[alias];
256
325
  if (!aliasProject) {
257
- throw new Error(`Not found gen c#-mongo configuration. Please run 'npx mushroom-cli config ${projectName} gen c#-mongo OUTPUT_FILE.cs${alias === 'default' ? '' : ' alias ' + alias}' first`);
326
+ throw new Error('Not found gen c#-mongo configuration.');
327
+ }
328
+ if (fs.existsSync(aliasProject.output)) {
329
+ try {
330
+ fs.unlinkSync(aliasProject.output);
331
+ }
332
+ catch { }
258
333
  }
259
334
  if (aliasProject.outputToFolder) {
260
- genCSharpMongoDbClassesToFolder(projectName, alias, source, aliasProject);
261
- return;
335
+ if (fs.existsSync(aliasProject.output)) {
336
+ try {
337
+ fs.rmSync(aliasProject.output, { recursive: true, force: true });
338
+ }
339
+ catch { }
340
+ }
341
+ fs.mkdirSync(aliasProject.output, { recursive: true, mode: 0o755 });
262
342
  }
263
343
  const entities = common.getEntities(source, aliasProject.allowRoles, true);
264
344
  const namespace = toCSharpName(source.name);
265
345
  let strClasses = '';
266
- let strEnumClasses = '';
267
346
  let collectionNames = '';
268
347
  let resourceNames = '';
269
- let roleNames = '';
270
- source.roles?.forEach((role) => {
271
- if (!role.name)
272
- return;
273
- roleNames += `
348
+ const roleNames = source.roles
349
+ ?.filter((r) => r.name)
350
+ .map((role) => `
274
351
  /// <summary>
275
352
  /// ${role.description ?? ''}
276
353
  /// </summary>
277
- public static string ${toCSharpName(role.name)} => "${role.name}";
278
- `;
279
- });
280
- const out = {
281
- strEnumClasses: '',
282
- };
354
+ public static string ${toCSharpName(role.name)} => "${role.name}";`)
355
+ .join(newLine) ?? '';
356
+ const out = {};
283
357
  for (const entityName in entities) {
284
358
  const className = toCSharpName(entityName);
285
359
  collectionNames += ` public static string ${className}CollectionName => "${entities[entityName].storageName}";
286
360
  public static IMongoCollection<Resources.${className}> ${className}Collection => GetDatabase().GetCollection<Resources.${className}>(${className}CollectionName);
287
361
  `;
288
- resourceNames += ` public static string ${className} => "${entityName}";\n`;
289
- strClasses += generateCSharpClassMongoDb(source, className, entities[entityName].fields, true, entities[entityName].description, out);
362
+ resourceNames += ` public static string ${className} => "${entityName}";${newLine}`;
363
+ strClasses += generateCSharpClassMongoDb(source, className, entities[entityName].fields, true, entities[entityName].description, out, aliasProject);
290
364
  const actions = entities[entityName].actions || {};
291
365
  for (const actionName in actions) {
292
366
  const action = actions[actionName];
@@ -381,12 +455,10 @@ export function genCSharpMongoDbClasses(args, projectName, project, alias, sourc
381
455
  });
382
456
  }
383
457
  }
384
- if (out.strEnumClasses)
385
- strEnumClasses += out.strEnumClasses;
386
458
  const delegators = groupCSharpMethodHandlerByMethod(out.delegators);
387
459
  const strDelegatorReferences = Object.keys(delegators)
388
460
  .map((method) => delegators[method].map((ev) => ` // ${ev.source}`).join(newLine) +
389
- `\n RegisterCustomMethod(${getCSharpFunc(method, delegators[method][0].type)});`)
461
+ `\n RegisterCustomMethod<System.Threading.Tasks.Task>(${getCSharpFunc(method, delegators[method][0].type)});`)
390
462
  .join(newLine);
391
463
  const viewHandlers = groupCSharpMethodHandlerByMethod(out.viewHandlers);
392
464
  const strViewHandlerReferences = Object.keys(viewHandlers)
@@ -413,69 +485,57 @@ export function genCSharpMongoDbClasses(args, projectName, project, alias, sourc
413
485
  .map((job) => ` RegisterJob<${job.action.substring(4).split(',')[0]}>();`)
414
486
  .join(newLine)
415
487
  : '';
416
- const code = `// This file was generated by Mushroom CLI ${packageVersion} (https://www.npmjs.com/package/mushroom-cli), please do not modify
417
-
418
- // NOTE: Compatible with Mushroom Server version 0.2.18 or higher (https://www.nuget.org/packages/Mushroom/)
419
-
420
- // ReSharper disable RedundantUsingDirective
421
- // ReSharper disable InconsistentNaming
422
- // ReSharper disable PartialTypeWithSinglePart
423
- // ReSharper disable UnusedMember.Global
424
- // ReSharper disable UnusedMember.Local
425
- // ReSharper disable UnusedParameter.Local
426
- // ReSharper disable IdentifierTypo
427
- // ReSharper disable StringLiteralTypo
428
- // ReSharper disable CommentTypo
429
- // ReSharper disable EmptyNamespace
488
+ const strRouteHandlers = source.routes
489
+ ?.filter((route) => route.delegator.startsWith('lib:'))
490
+ .map((route) => ` // route: ${route.path} - grant: ${route.grant}${newLine} RegisterCustomMethod<System.Threading.Tasks.Task>(${getCSharpFunc(route.delegator.substring(4), route.codeHint?.delegator?.csharp?.methodType ?? 'static')});`)
491
+ .join(newLine) ?? '';
492
+ const strExtensionEventHandlers = getExtensionEventsCode(source, newLine);
493
+ if (aliasProject.outputToFolder) {
494
+ const dbConnectorFileContent = `${header}
495
+ using MongoDB.Driver;
430
496
 
431
497
  namespace ${namespace}
432
498
  {
433
- using MongoDB.Driver;
434
-
435
499
  public static class DbConnector
436
500
  {
437
501
  ${collectionNames}
438
502
  public static IMongoDatabase GetDatabase() => Mushroom.MushroomDaoFactory.GetDbAdapter() as IMongoDatabase;
439
503
  }
504
+ }
505
+ `;
506
+ const resourceNamesFileContent = `${header}
440
507
 
508
+ namespace ${namespace}
509
+ {
441
510
  public class ResourceNames
442
511
  {
443
512
  private ResourceNames() { }
444
513
 
445
514
  ${resourceNames}
446
515
  }
516
+ }
517
+ `;
518
+ const roleNamesFileContent = `${header}
447
519
 
448
- public class RoleNames {
520
+ namespace ${namespace}
521
+ {
522
+ public class RoleNames
523
+ {
449
524
  private RoleNames() { }
450
525
 
451
526
  ${roleNames}
452
527
  }
453
528
  }
454
-
455
- namespace ${namespace}.Resources
456
- {
457
- ${strClasses}
458
- }
459
-
460
- namespace ${namespace}.Enums
461
- {
462
- ${strEnumClasses}
463
- }
529
+ `;
530
+ const refactorHelperFileContent = `${header}
464
531
 
465
532
  #if DEBUG
466
- namespace ${namespace}.CodeHelper
533
+ namespace ${namespace}
467
534
  {
468
535
  class RefactorHelper
469
536
  {
470
537
  private RefactorHelper() { }
471
- private void RegisterCustomMethod(System.Func<Mushroom.ActionArguments, System.Threading.Tasks.Task> fn) { }
472
- private void RegisterCustomMethod(System.Action<Mushroom.ActionArguments> fn) { }
473
- private void RegisterCustomViewMethod(System.Func<Mushroom.ViewArguments, System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable<object>>> fn) { }
474
- private void RegisterCustomViewMethod(System.Func<Mushroom.ViewArguments, System.Collections.Generic.IEnumerable<object>> fn) { }
475
- private void RegisterCustomVnTextBuilderMethod(System.Func<System.Collections.Generic.IEnumerable<string>, System.Collections.Generic.IEnumerable<string>> fn) { }
476
- private void RegisterEvent(System.Func<object, Mushroom.ActionArguments, System.Threading.Tasks.Task> fn) { }
477
- private void RegisterEvent(System.Action<object, Mushroom.ActionArguments> fn) { }
478
- private void RegisterJob<T>() where T : Mushroom.Job.JobBase { }
538
+ ${helperMethods}
479
539
  private void Help()
480
540
  {
481
541
  ${strDelegatorReferences}
@@ -483,359 +543,66 @@ ${strViewHandlerReferences}
483
543
  ${strVnTextChannels}
484
544
  ${strEventHandlerReferences}
485
545
  ${strJobReferences}
546
+ ${strRouteHandlers}
547
+ ${strExtensionEventHandlers}
486
548
  }
487
549
  }
488
550
  }
489
551
  #endif
490
552
  `;
491
- common.ensureFolder(aliasProject.output);
492
- fs.writeFile(aliasProject.output, code, (err) => {
493
- if (err)
494
- throw err;
495
- common.logInfo(`Generated CSharp MongoDb Classes for ${projectName}@${alias} to ${aliasProject.output}`);
496
- });
497
- }
498
- function generateCSharpClassMongoDbToFolder(source, className, fields, isRoot, description, out, aliasProject) {
499
- let content = '';
500
- const namespace = toCSharpName(source.name);
501
- if (description) {
502
- content += ` /// <summary>
503
- /// ${singleLine(description)}
504
- /// </summary>
505
- `;
506
- }
507
- let supperClass = '';
508
- if (isRoot) {
509
- if (!fields.id) {
510
- fields.id = {
511
- type: 'AutoId',
512
- };
513
- }
514
- if (!fields.id.type)
515
- fields.id.type = 'AutoId';
516
- supperClass = ' : Mushroom.Models.IResource<' + getCSharpTypeFromMushroomType(source, fields.id.type, true) + '>';
517
- }
518
- content += ` public partial class ${className}${supperClass}
519
- {
520
- `;
521
- for (const fieldName in fields) {
522
- const field = fields[fieldName];
523
- let type;
524
- const propertyName = toCSharpName(fieldName);
525
- if (field.codeHint && field.codeHint.type && field.codeHint.type.csharp) {
526
- type = field.codeHint.type.csharp;
527
- }
528
- else if (field.type === 'object') {
529
- generateCSharpClassMongoDbToFolder(source, className + '_' + propertyName, field.fields ?? {}, false, null, out, aliasProject);
530
- type = className + '_' + propertyName;
531
- }
532
- else if (field.type === 'array') {
533
- if (field.items?.type === 'object') {
534
- generateCSharpClassMongoDbToFolder(source, className + '_' + propertyName, field.items.fields ?? {}, false, null, out, aliasProject);
535
- type = `System.Collections.Generic.List<${className}_${propertyName}>`;
536
- }
537
- else if (field.items) {
538
- type = `System.Collections.Generic.List<${getCSharpTypeFromMushroomType(source, field.items.type, field.items.validation && field.items.validation.required)}>`;
539
- }
540
- }
541
- else
542
- type = getCSharpTypeFromMushroomType(source, field.type, field.validation && field.validation.required);
543
- content += ` /// <summary>
544
- /// ${singleLine(field.description)}
545
- /// </summary>
546
- `;
547
- if (isRoot && fieldName === 'id') {
548
- content += ` [MongoDB.Bson.Serialization.Attributes.BsonId${field.type === 'AutoId' && source.idType === 'GUID' ? '(IdGenerator = typeof(MongoDB.Bson.Serialization.IdGenerators.GuidGenerator))' : ''}]\n`;
549
- }
550
- content += ` [MongoDB.Bson.Serialization.Attributes.BsonElement("${isRoot && fieldName === 'id' ? '_id' : fieldName}")]
551
- [MongoDB.Bson.Serialization.Attributes.BsonIgnoreIfNull]
552
- [Newtonsoft.Json.JsonProperty(PropertyName = "${fieldName}", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore${type === 'System.DateTime' ? ', DefaultValueHandling = Newtonsoft.Json.DefaultValueHandling.Ignore' : ''})]
553
- [System.Text.Json.Serialization.JsonPropertyName("${fieldName}")]
554
- [System.Text.Json.Serialization.JsonIgnore(Condition = ${type === 'System.DateTime' ? 'System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingDefault' : 'System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull'})]
555
- `;
556
- if ((field.type === 'AutoId' || field.type === 'IdRef') && source.idType === 'ObjectId') {
557
- content += ' [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.ObjectId)]\n';
558
- }
559
- if (field.type === 'AutoId' && source.idType === 'GUID') {
560
- content += ' [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.String)]\n';
561
- }
562
- if (field.type === 'datetime') {
563
- content +=
564
- ' [MongoDB.Bson.Serialization.Attributes.BsonDateTimeOptions(Kind = System.DateTimeKind.Local)]\n';
565
- }
566
- if (field.type === 'array') {
567
- if ((field.items?.type === 'AutoId' || field.items?.type === 'IdRef') && source.idType === 'ObjectId') {
568
- content +=
569
- ' [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.ObjectId)]\n';
570
- }
571
- if (field.items?.type === 'AutoId' && source.idType === 'GUID') {
572
- content += ' [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.String)]\n';
573
- }
574
- if (field.items?.type === 'datetime') {
575
- content +=
576
- ' [MongoDB.Bson.Serialization.Attributes.BsonDateTimeOptions(Kind = System.DateTimeKind.Local)]\n';
577
- }
578
- }
579
- content += ` public ${type} ${propertyName} { get; set; }
580
-
581
- `;
582
- let strEnumClasses = generateEnumClass(source, {}, field, `${className.toUpperCase()}_${propertyName.toUpperCase()}_ENUM`);
583
- const match = strEnumClasses.match(/public partial class\s+(\w+)/);
584
- if (!match)
585
- continue;
586
- common.ensureFolder(aliasProject.output + '/Enums', true);
587
- strEnumClasses = `${header}
588
-
589
- namespace ${namespace}.Enums
590
- {
591
- ${strEnumClasses}
592
- }
593
- `;
594
- fs.writeFileSync(aliasProject.output + '/Enums/' + match[1] + '.cs', strEnumClasses);
595
- }
596
- content += ` [MongoDB.Bson.Serialization.Attributes.BsonExtraElements]
597
- [Newtonsoft.Json.JsonIgnore]
598
- [System.Text.Json.Serialization.JsonIgnore]
599
- public System.Collections.Generic.Dictionary<string, object> Mushroom_ExtraProperties { get; set; }
600
-
601
- }
602
- `;
603
- common.ensureFolder(aliasProject.output + '/Resources', true);
604
- content = `${header}
605
-
606
- namespace ${namespace}.Resources
607
- {
608
- ${content}
609
- }
610
- `;
611
- const normalizedName = className.toLowerCase();
612
- out.allClasses ?? (out.allClasses = []);
613
- const duplicate = out.allClasses.find((c) => c.normalizedName == normalizedName);
614
- if (duplicate) {
615
- fs.appendFileSync(aliasProject.output + '/Resources/' + duplicate.className + '.cs', content);
553
+ fs.writeFileSync(aliasProject.output + '/DbConnector.cs', dbConnectorFileContent);
554
+ fs.writeFileSync(aliasProject.output + '/ResourceNames.cs', resourceNamesFileContent);
555
+ fs.writeFileSync(aliasProject.output + '/RoleNames.cs', roleNamesFileContent);
556
+ fs.writeFileSync(aliasProject.output + '/RefactorHelper.cs', refactorHelperFileContent);
557
+ fs.writeFileSync(aliasProject.output + '/Info.cs', infoContent);
558
+ common.logInfo(`Generated CSharp MongoDb Classes for ${projectName}@${alias} to folder ${aliasProject.output}`);
616
559
  }
617
560
  else {
618
- out.allClasses.push({
619
- className,
620
- normalizedName,
621
- });
622
- fs.writeFileSync(aliasProject.output + '/Resources/' + className + '.cs', content);
623
- }
624
- }
625
- function genCSharpMongoDbClassesToFolder(projectName, alias, source, aliasProject) {
626
- if (fs.existsSync(aliasProject.output)) {
627
- try {
628
- fs.unlinkSync(aliasProject.output);
629
- }
630
- catch { }
631
- try {
632
- fs.rmSync(aliasProject.output, { recursive: true, force: true });
633
- }
634
- catch { }
635
- }
636
- fs.mkdirSync(aliasProject.output, { recursive: true, mode: 0o755 });
637
- const entities = common.getEntities(source, aliasProject.allowRoles, true);
638
- const namespace = toCSharpName(source.name);
639
- let collectionNames = '';
640
- let resourceNames = '';
641
- let roleNames = '';
642
- source.roles?.forEach((role) => {
643
- if (!role.name)
644
- return;
645
- roleNames += `
646
- /// <summary>
647
- /// ${role.description ?? ''}
648
- /// </summary>
649
- public static string ${toCSharpName(role.name)} => "${role.name}";
650
- `;
651
- });
652
- const out = {};
653
- for (const entityName in entities) {
654
- const className = toCSharpName(entityName);
655
- collectionNames += ` public static string ${className}CollectionName => "${entities[entityName].storageName}";
656
- public static IMongoCollection<Resources.${className}> ${className}Collection => GetDatabase().GetCollection<Resources.${className}>(${className}CollectionName);
657
- `;
658
- resourceNames += ` public static string ${className} => "${entityName}";
659
- `;
660
- generateCSharpClassMongoDbToFolder(source, className, entities[entityName].fields, true, entities[entityName].description, out, aliasProject);
661
- const actions = entities[entityName].actions || {};
662
- for (const actionName in actions) {
663
- const action = actions[actionName];
664
- if (!Array.isArray(action))
665
- continue;
666
- action.forEach((a) => {
667
- if (!a)
668
- return;
669
- if (typeof a.delegator === 'string' && a.delegator.indexOf('lib:') === 0) {
670
- const method = a.delegator.substring(4);
671
- let type = a.codeHint && a.codeHint.delegator && a.codeHint.delegator.csharp
672
- ? a.codeHint.delegator.csharp.methodType
673
- : null;
674
- if (type !== 'non-static')
675
- type = 'static';
676
- out.delegators ?? (out.delegators = []);
677
- out.delegators.push({
678
- method: method,
679
- source: `entity: ${entityName}, action: ${actionName}, grant: ${a.grant}`,
680
- type: type,
681
- });
682
- }
683
- if (!a.events && !(typeof a.events === 'object'))
684
- return;
685
- for (const eventName in a.events) {
686
- if (!Array.isArray(a.events[eventName]))
687
- return;
688
- a.events[eventName].forEach((ev, i) => {
689
- if (typeof ev !== 'string' || ev.indexOf('lib:') !== 0)
690
- return;
691
- const method = ev.substring(4);
692
- let type = a.codeHint &&
693
- a.codeHint.events &&
694
- Array.isArray(a.codeHint.events[eventName]) &&
695
- a.codeHint.events[eventName][i] &&
696
- a.codeHint.events[eventName][i].csharp
697
- ? a.codeHint.events[eventName][i].csharp.methodType
698
- : null;
699
- if (type !== 'non-static')
700
- type = 'static';
701
- out.eventHandlers ?? (out.eventHandlers = []);
702
- out.eventHandlers.push({
703
- method: method,
704
- source: `entity: ${entityName}, action: ${actionName}, grant: ${a.grant}, event: ${eventName}`,
705
- type: type,
706
- });
707
- });
708
- }
709
- });
710
- }
711
- const views = entities[entityName].views || {};
712
- for (const viewName in views) {
713
- const view = views[viewName];
714
- if (!Array.isArray(view))
715
- continue;
716
- view.forEach((v) => {
717
- if (!v)
718
- return;
719
- if (typeof v.query === 'string' && v.query.indexOf('lib:') === 0) {
720
- const method = v.query.substring(4);
721
- let type = v.codeHint && v.codeHint.query && v.codeHint.query.csharp ? v.codeHint.query.csharp.methodType : null;
722
- if (type !== 'non-static')
723
- type = 'static';
724
- out.viewHandlers ?? (out.viewHandlers = []);
725
- out.viewHandlers.push({
726
- method: method,
727
- source: `entity: ${entityName}, view: ${viewName}, grant: ${v.grant}`,
728
- type: type,
729
- });
730
- }
731
- });
732
- }
733
- const channels = entities[entityName].features?.vn_text?.channels;
734
- if (channels != null) {
735
- channels.forEach((channel) => {
736
- if (!channel.nativeBuilder ||
737
- typeof channel.nativeBuilder !== 'string' ||
738
- channel.nativeBuilder.indexOf('lib:') !== 0)
739
- return;
740
- const method = channel.nativeBuilder.substring(4);
741
- let type = channel.codeHint && channel.codeHint.nativeBuilder && channel.codeHint.nativeBuilder.csharp
742
- ? channel.codeHint.nativeBuilder.csharp.methodType
743
- : null;
744
- if (type !== 'non-static')
745
- type = 'static';
746
- out.vnTextChannels ?? (out.vnTextChannels = []);
747
- out.vnTextChannels.push({
748
- method: method,
749
- source: `entity: ${entityName}, feature: vn_text, channel: ${channel.name}`,
750
- type: type,
751
- });
752
- });
753
- }
754
- }
755
- const delegators = groupCSharpMethodHandlerByMethod(out.delegators);
756
- const strDelegatorReferences = Object.keys(delegators)
757
- .map((method) => delegators[method].map((ev) => ` // ${ev.source}`).join(newLine) +
758
- `\n RegisterCustomMethod(${getCSharpFunc(method, delegators[method][0].type)});`)
759
- .join(newLine);
760
- const viewHandlers = groupCSharpMethodHandlerByMethod(out.viewHandlers);
761
- const strViewHandlerReferences = Object.keys(viewHandlers)
762
- .map((method) => viewHandlers[method].map((ev) => ` // ${ev.source}`).join(newLine) +
763
- `\n RegisterCustomViewMethod(${getCSharpFunc(method, viewHandlers[method][0].type)});`)
764
- .join(newLine);
765
- const vnTextChannels = groupCSharpMethodHandlerByMethod(out.vnTextChannels);
766
- const strVnTextChannels = Object.keys(vnTextChannels)
767
- .map((method) => vnTextChannels[method].map((channel) => ` // ${channel.source}`).join(newLine) +
768
- `\n RegisterCustomVnTextBuilderMethod(${getCSharpFunc(method, vnTextChannels[method][0].type)});`)
769
- .join(newLine);
770
- const eventHandlers = groupCSharpMethodHandlerByMethod(out.eventHandlers);
771
- const strEventHandlerReferences = Object.keys(eventHandlers)
772
- .map((method) => eventHandlers[method].map((ev) => ` // ${ev.source}`).join(newLine) +
773
- `\n RegisterEvent(${getCSharpFunc(method, eventHandlers[method][0].type)});`)
774
- .join(newLine);
775
- const strJobReferences = Array.isArray(source.jobs)
776
- ? source.jobs
777
- .filter((job) => job !== null &&
778
- typeof job === 'object' &&
779
- job.action &&
780
- typeof job.action === 'string' &&
781
- job.action.indexOf('lib:') === 0)
782
- .map((job) => ` RegisterJob<${job.action.substring(4).split(',')[0]}>();`)
783
- .join(newLine)
784
- : '';
785
- const dbConnectorFileContent = `${header}
786
- using MongoDB.Driver;
561
+ const fullCode = `${infoContent}
562
+
563
+ ${header}
787
564
 
788
565
  namespace ${namespace}
789
566
  {
567
+ using MongoDB.Driver;
568
+
790
569
  public static class DbConnector
791
570
  {
792
571
  ${collectionNames}
793
572
  public static IMongoDatabase GetDatabase() => Mushroom.MushroomDaoFactory.GetDbAdapter() as IMongoDatabase;
794
573
  }
795
- }
796
- `;
797
- const resourceNamesFileContent = `${header}
798
574
 
799
- namespace ${namespace}
800
- {
801
575
  public class ResourceNames
802
576
  {
803
577
  private ResourceNames() { }
804
578
 
805
579
  ${resourceNames}
806
580
  }
807
- }
808
- `;
809
- const roleNamesFileContent = `${header}
810
581
 
811
- namespace ${namespace}
812
- {
813
- public class RoleNames
814
- {
582
+ public class RoleNames {
815
583
  private RoleNames() { }
816
584
 
817
585
  ${roleNames}
818
586
  }
819
587
  }
820
- `;
821
- const refactorHelperFileContent = `${header}
588
+
589
+ namespace ${namespace}.Resources
590
+ {
591
+ ${strClasses}
592
+ }
593
+
594
+ namespace ${namespace}.Enums
595
+ {
596
+ ${out.strEnumClasses ?? ''}
597
+ }
822
598
 
823
599
  #if DEBUG
824
- namespace ${namespace}
600
+ namespace ${namespace}.CodeHelper
825
601
  {
826
602
  class RefactorHelper
827
603
  {
828
604
  private RefactorHelper() { }
829
- private void RegisterCustomMethod(System.Func<Mushroom.ActionArguments, System.Threading.Tasks.Task> fn) { }
830
- private void RegisterCustomMethod(System.Action<Mushroom.ActionArguments> fn) { }
831
- private void RegisterCustomViewMethod(System.Func<Mushroom.ViewArguments, System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable<object>>> fn) { }
832
- private void RegisterCustomViewMethod(System.Func<Mushroom.ViewArguments, System.Collections.Generic.IEnumerable<object>> fn) { }
833
- private void RegisterCustomVnTextBuilderMethod(System.Func<System.Collections.Generic.IEnumerable<string>, System.Collections.Generic.IEnumerable<string>> fn) { }
834
- private void RegisterEvent(System.Func<object, Mushroom.ActionArguments, System.Threading.Tasks.Task> fn) { }
835
- private void RegisterEvent(System.Action<object, Mushroom.ActionArguments> fn) { }
836
- private void RegisterRespondingEvent(System.Func<object, Mushroom.ActionArguments, Mushroom.ActionResult, System.Threading.Tasks.Task> fn) { }
837
- private void RegisterRespondingEvent(System.Action<object, Mushroom.ActionArguments, Mushroom.ActionResult> fn) { }
838
- private void RegisterJob<T>() where T : Mushroom.Job.JobBase { }
605
+ ${helperMethods}
839
606
  private void Help()
840
607
  {
841
608
  ${strDelegatorReferences}
@@ -843,20 +610,20 @@ ${strViewHandlerReferences}
843
610
  ${strVnTextChannels}
844
611
  ${strEventHandlerReferences}
845
612
  ${strJobReferences}
613
+ ${strRouteHandlers}
614
+ ${strExtensionEventHandlers}
846
615
  }
847
616
  }
848
617
  }
849
618
  #endif
850
619
  `;
851
- const infoFileContent = `// Mushroom CLI version: ${packageVersion}
852
- // Compatible with Mushroom Server version: 0.2.25.4 or higher (https://www.nuget.org/packages/Mushroom/)
853
- // For Mushroom Server 0.2.18 to 0.2.25.4: Please remove all FindById methods in DbConnector.cs`;
854
- fs.writeFileSync(aliasProject.output + '/DbConnector.cs', dbConnectorFileContent);
855
- fs.writeFileSync(aliasProject.output + '/ResourceNames.cs', resourceNamesFileContent);
856
- fs.writeFileSync(aliasProject.output + '/RoleNames.cs', roleNamesFileContent);
857
- fs.writeFileSync(aliasProject.output + '/RefactorHelper.cs', refactorHelperFileContent);
858
- fs.writeFileSync(aliasProject.output + '/Info.cs', infoFileContent);
859
- common.logInfo(`Generated CSharp MongoDb Classes for ${projectName}@${alias} to folder ${aliasProject.output}`);
620
+ common.ensureFolder(aliasProject.output);
621
+ fs.writeFile(aliasProject.output, fullCode, (err) => {
622
+ if (err)
623
+ throw err;
624
+ common.logInfo(`Generated CSharp MongoDb Classes for ${projectName}@${alias} to ${aliasProject.output}`);
625
+ });
626
+ }
860
627
  }
861
628
  function generateCSharpClassDriver(source, className, fields, description, out) {
862
629
  let strClasses = '';
@@ -864,7 +631,7 @@ function generateCSharpClassDriver(source, className, fields, description, out)
864
631
  let content = '';
865
632
  if (description) {
866
633
  content += ` /// <summary>
867
- /// ${singleLine(description)}
634
+ /// ${escapseForXmlDocs(description)}
868
635
  /// </summary>
869
636
  `;
870
637
  }
@@ -894,7 +661,7 @@ function generateCSharpClassDriver(source, className, fields, description, out)
894
661
  else
895
662
  type = getCSharpTypeFromMushroomType(source, field.type, field.validation && field.validation.required);
896
663
  content += ` /// <summary>
897
- /// ${singleLine(field.description)}
664
+ /// ${escapseForXmlDocs(field.description)}
898
665
  /// </summary>
899
666
  [Newtonsoft.Json.JsonProperty(PropertyName ="${fieldName}", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore${type === 'System.Datetime' ? ', DefaultValueHandling = Newtonsoft.Json.DefaultValueHandling.Ignore' : ''})]
900
667
  [System.Text.Json.Serialization.JsonPropertyName("${fieldName}")]