mushroom-cli 1.1.1 → 1.1.2

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/gen/gen-csharp.js CHANGED
@@ -1,1410 +1,1687 @@
1
- const fs = require("fs");
2
- const common = require("../common.js");
3
- const package_json = require("./../package.json");
4
-
5
- //#region shared function
6
- const newLine = `
7
- `;
8
- const header = `// NOTE: Please do not modify this file
9
- // NOTE: Version and compatibility information: please see in Info.cs file
10
-
11
- // ReSharper disable CheckNamespace
12
- // ReSharper disable CommentTypo
13
- // ReSharper disable EmptyNamespace
14
- // ReSharper disable IdentifierTypo
15
- // ReSharper disable InconsistentNaming
16
- // ReSharper disable PartialTypeWithSinglePart
17
- // ReSharper disable RedundantUsingDirective
18
- // ReSharper disable StringLiteralTypo
19
- // ReSharper disable UnusedMember.Global
20
- // ReSharper disable UnusedMember.Local
21
- // ReSharper disable UnusedParameter.Local
22
- // ReSharper disable UnusedTypeParameter
23
- `;
24
-
25
- function singleLine(str) {
26
- if (!str)
27
- return "";
28
- return str.replace(/\r/g, "").replace(/\n/g, "<br/>");
29
- }
30
-
31
- function toVietnameseNonTongue(str) {
32
- const signText = "ăâđêôơưàảãạáằẳẵặắầẩẫậấèẻẽẹéềểễệếìỉĩịíòỏõọóồổỗộốờởỡợớùủũụúừửữựứỳỷỹỵýĂÂĐÐÊÔƠƯÀẢÃẠÁẰẲẴẶẮẦẨẪẬẤÈẺẼẸÉỀỂỄỆẾÌỈĨỊÍÒỎÕỌÓỒỔỖỘỐỜỞỠỢỚÙỦŨỤÚỪỬỮỰỨỲỶỸỴÝ";
33
- const unsignedText = "aadeoouaaaaaaaaaaaaaaaeeeeeeeeeeiiiiiooooooooooooooouuuuuuuuuuyyyyyAADDEOOUAAAAAAAAAAAAAAAEEEEEEEEEEIIIIIOOOOOOOOOOOOOOOUUUUUUUUUUYYYYY";
34
- let returnValue = "";
35
- for (let i = 0; i < str.length; i++) {
36
- const index = signText.indexOf(str.charAt(i));
37
- returnValue += index !== -1 ? unsignedText.charAt(index) : str.charAt(i);
38
- }
39
- return returnValue;
40
- }
41
-
42
- function toCSharpName(str) {
43
- if (!str)
44
- return "_";
45
- const name = toVietnameseNonTongue(str).replace(/\W/g, "_");
46
- const c = name.charAt(0);
47
- return ('0' <= c && c <= '9' ? '_' : "") + c.toUpperCase() + name.substring(1);
48
- }
49
-
50
- function getCSharpTypeFromMushroomType(source, type, required) {
51
- switch (type) {
52
- case "string":
53
- return "string";
54
- case "object":
55
- return "";
56
- case "boolean":
57
- return required ? "bool" : "bool?";
58
- case "integer":
59
- return required ? "int" : "int?";
60
- case "long":
61
- return required ? "long" : "long?";
62
- case "double":
63
- return required ? "double" : "double?";
64
- case "array":
65
- return "";
66
- case "datetime":
67
- return required ? "System.DateTime" : "System.DateTime?";
68
- case "IdRef":
69
- case "AutoId":
70
- if (source.idType === "ObjectId" || source.idType === "GUID")
71
- return "string";
72
- if (source.idType === "AutoIncInt")
73
- return "int";
74
- if (source.idType === "AutoIncLong")
75
- return "long";
76
- }
77
- return "UNKNOWN_TYPE";
78
- }
79
-
80
- function getCSharpInitValue(csType, value) {
81
- switch(csType) {
82
- case "string":
83
- return JSON.stringify(value);
84
- case "int":
85
- return parseInt(Number(value));
86
- case "long":
87
- return parseInt(Number(value)) + "L";
88
- case "double":
89
- return Number(value);
90
- case "bool":
91
- if (value === "false")
92
- return false;
93
- if (value === "true")
94
- return true;
95
- return "NotABoolean"
96
- case "datetime":
97
- return `System.DateTime.Parse(${JSON.stringify(value)})`;
98
- default:
99
- return "UNSUPPORTED";
100
- }
101
- }
102
-
103
- function generateEnumClass(source, out, field, defaultClassName) {
104
- if (!out)
105
- return "";
106
-
107
- let strEnumClasses = "";
108
- const validation = field.type === "array" ? field.items.validation : field.validation;
109
- if (!validation)
110
- return "";
111
-
112
- if (!validation.validValues)
113
- return "";
114
-
115
- const mrType = field.type === "array" ? field.items.type : field.type;
116
- if (mrType == "object" || mrType == "array") {
117
- console.log("Unsuported enum type for type ", mrType, field);
118
- return "";
119
- }
120
-
121
- const type = getCSharpTypeFromMushroomType(source, mrType, true);
122
-
123
- validation.codeHint = validation.codeHint || {};
124
- if (validation.validValues) {
125
- validation.codeHint.validValues = validation.codeHint.validValues || {};
126
-
127
- if (!validation.codeHint.validValues.disabled) {
128
- const enumClassName = validation.codeHint.validValues.className || defaultClassName;
129
-
130
- out.arrEnumClassNames = out.arrEnumClassNames || [];
131
-
132
- if (out.arrEnumClassNames.indexOf(enumClassName) === -1) {
133
- out.arrEnumClassNames.push(enumClassName);
134
- strEnumClasses += ` /// <summary>
135
- /// ${singleLine(validation.codeHint.validValues.description || field.description)}
136
- /// </summary>
137
- public class ${enumClassName}
138
- {
139
- private ${enumClassName}() { }
140
-
141
- `;
142
- const enumProperties = validation.codeHint.validValues.nameMap || validation.validValues;
143
- for (let i = 0; i < enumProperties.length && i < validation.validValues.length; i++) {
144
- strEnumClasses += ` public const ${type} ${toCSharpName(enumProperties[i])} = ${getCSharpInitValue(type, validation.validValues[i])};
145
- `;
146
- }
147
- strEnumClasses += ` }
148
-
149
- `;
150
- }
151
- }
152
- }
153
-
154
- return strEnumClasses;
155
- }
156
- //#endregion
157
-
158
- //#region CSharp MongoDb Classes
159
- function generateCSharpClassMongoDb(source, className, fields, isRoot, description, out) {
160
- let strClasses = "";
161
- let strEnumClasses = "";
162
- let content = "";
163
- if (description) {
164
- content +=
165
- ` /// <summary>
166
- /// ${singleLine(description)}
167
- /// </summary>
168
- `;
169
- }
170
- let supperClass = "";
171
- if (isRoot) {
172
- // thêm cho trường hợp không khai báo id hoặc id.type
173
- if (!fields.id) {
174
- fields.id = {
175
- type: "AutoId"
176
- };
177
- }
178
- if (!fields.id.type) fields.id.type = "AutoId";
179
-
180
- supperClass = " : Mushroom.Models.IResource<" + getCSharpTypeFromMushroomType(source, fields.id.type, true) + ">";
181
- }
182
- content += ` public class ${className}${supperClass}
183
- {
184
- `;
185
- for (const fieldName in fields) {
186
- if (!fields.hasOwnProperty(fieldName))
187
- continue;
188
-
189
- const field = fields[fieldName];
190
- let type;
191
- const propertyName = toCSharpName(fieldName);
192
- if (field.codeHint && field.codeHint.type && field.codeHint.type.csharp) {
193
- type = field.codeHint.type.csharp;
194
- }
195
- else if (field.type === "object") {
196
- strClasses += generateCSharpClassMongoDb(source, className + "_" + propertyName, field.fields, false, null, out) + newLine;
197
- type = className + "_" + propertyName;
198
- }
199
- else if (field.type === "array") {
200
- if (field.items.type === "object") {
201
- strClasses += generateCSharpClassMongoDb(source, className + "_" + propertyName, field.items.fields, false, null, out) + newLine;
202
- type = `System.Collections.Generic.List<${className}_${propertyName}>`;
203
- } else {
204
- type = `System.Collections.Generic.List<${getCSharpTypeFromMushroomType(source, field.items.type, field.items.validation && field.items.validation.required)}>`;
205
- }
206
- } else
207
- type = getCSharpTypeFromMushroomType(source, field.type, field.validation && field.validation.required);
208
- content +=
209
- ` /// <summary>
210
- /// ${singleLine(field.description)}
211
- /// </summary>
212
- `;
213
-
214
- if (isRoot && fieldName === "id") {
215
- content += ` [MongoDB.Bson.Serialization.Attributes.BsonId${field.type === "AutoId" && source.idType === "GUID" ? "(IdGenerator = typeof(MongoDB.Bson.Serialization.IdGenerators.GuidGenerator))" : ""}]${newLine}`;
216
- }
217
- content += ` [MongoDB.Bson.Serialization.Attributes.BsonElement("${isRoot && fieldName === "id" ? "_id" : fieldName}")]
218
- [MongoDB.Bson.Serialization.Attributes.BsonIgnoreIfNull]
219
- [Newtonsoft.Json.JsonProperty(PropertyName = "${fieldName}", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore${type === "System.DateTime" ? ", DefaultValueHandling = Newtonsoft.Json.DefaultValueHandling.Ignore" : ""})]
220
- `;
221
- if ((field.type === "AutoId" || field.type === "IdRef") && source.idType === "ObjectId") {
222
- content += " [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.ObjectId)]" + newLine;
223
- }
224
- if (field.type === "AutoId" && source.idType === "GUID") {
225
- content += " [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.String)]" + newLine;
226
- }
227
- if (field.type === "datetime") {
228
- content += " [MongoDB.Bson.Serialization.Attributes.BsonDateTimeOptions(Kind = System.DateTimeKind.Local)]" + newLine;
229
- }
230
- if (field.type === "array") {
231
- if ((field.items.type === "AutoId" || field.items.type === "IdRef") && source.idType === "ObjectId") {
232
- content += " [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.ObjectId)]" + newLine;
233
- }
234
- if (field.items.type === "AutoId" && source.idType === "GUID") {
235
- content += " [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.String)]" + newLine;
236
- }
237
- if (field.items.type === "datetime") {
238
- content += " [MongoDB.Bson.Serialization.Attributes.BsonDateTimeOptions(Kind = System.DateTimeKind.Local)]" + newLine;
239
- }
240
- }
241
-
242
- content += ` public ${type} ${propertyName} { get; set; }${newLine}${newLine}`;
243
-
244
- strEnumClasses += generateEnumClass(source, out, field, `${className.toUpperCase()}_${propertyName.toUpperCase()}_ENUM`);
245
- }
246
- content += ` [MongoDB.Bson.Serialization.Attributes.BsonExtraElements]
247
- public System.Collections.Generic.Dictionary<string, object> Mushroom_ExtraProperties { get; set; }
248
-
249
- }
250
- `;
251
- if (strEnumClasses) {
252
- out.strEnumClasses = out.strEnumClasses || "";
253
-
254
- out.strEnumClasses += strEnumClasses;
255
- }
256
-
257
- return strClasses + newLine + content;
258
- }
259
-
260
- function getCSharpFunc(methodName, methodType) {
261
- if (methodType === "static") return methodName;
262
- const idx = methodName.lastIndexOf('.');
263
- if (idx === -1) return methodName;
264
- return `new ${methodName.substring(0, idx)}()${methodName.substring(idx)}`;
265
- }
266
-
267
- function genCSharpMongoDbClasses(args, projectName, project, alias, source) {
268
- const aliasProject = ((project.csharpMongo || {}).alias || {})[alias];
269
-
270
- if (!aliasProject) {
271
- 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`);
272
- }
273
-
274
- if (aliasProject.outputToFolder) {
275
- genCSharpMongoDbClassesToFolder(projectName, alias, source, aliasProject);
276
- return;
277
- }
278
-
279
- const entities = common.getEntities(source, aliasProject.allowRoles, true);
280
-
281
- const namespace = toCSharpName(source.name);
282
-
283
- let strClasses = "";
284
- let strEnumClasses = "";
285
- let collectionNames = "";
286
- let resourceNames = "";
287
- let roleNames = "";
288
-
289
- source.roles?.forEach(role => {
290
- if (!role.name) return;
291
- roleNames += `
292
- /// <summary>
293
- /// ${role.description ?? ""}
294
- /// </summary>
295
- public static string ${toCSharpName(role.name)} => "${role.name}";
296
- `;
297
- });
298
-
299
- const out = {};
300
- for (let entityName in entities) {
301
- if (!entities.hasOwnProperty(entityName))
302
- continue;
303
-
304
- const className = toCSharpName(entityName);
305
- collectionNames += ` public static string ${className}CollectionName => "${entities[entityName].storageName}";
306
- public static IMongoCollection<Resources.${className}> ${className}Collection => GetDatabase().GetCollection<Resources.${className}>(${className}CollectionName);
307
- `;
308
- resourceNames += ` public static string ${className} => "${entityName}";${newLine}`;
309
- strClasses += generateCSharpClassMongoDb(source, className, entities[entityName].fields, true, entities[entityName].description, out);
310
-
311
- const actions = entities[entityName].actions || {};
312
- for (let actionName in actions) {
313
- const action = actions[actionName];
314
- if (!Array.isArray(action))
315
- continue;
316
-
317
- action.forEach(a => {
318
- if (!a)
319
- return;
320
- if (typeof a.delegator === "string" && a.delegator.indexOf("lib:") === 0) {
321
- out.delegators = out.delegators || [];
322
- const method = a.delegator.substring(4);
323
- let type = a.codeHint && a.codeHint.delegator && a.codeHint.delegator.csharp
324
- ? a.codeHint.delegator.csharp.methodType
325
- : null;
326
- if (type !== "non-static") type = "static";
327
- out.delegators.push({
328
- method: method,
329
- source: `entity: ${entityName}, action: ${actionName}, grant: ${a.grant}`,
330
- type: type
331
- });
332
- }
333
-
334
- if (!a.events && typeof a.events !== "object") return;
335
-
336
- for (let eventName in a.events) {
337
- if (!Array.isArray(a.events[eventName])) return;
338
-
339
- out.eventHandlers = out.eventHandlers || [];
340
- a.events[eventName].forEach((ev, i) => {
341
- if (typeof ev !== "string" || ev.indexOf("lib:") !== 0) return;
342
- const method = ev.substring(4);
343
- let type = a.codeHint && a.codeHint.events
344
- && Array.isArray(a.codeHint.events[eventName])
345
- && a.codeHint.events[eventName][i]
346
- && a.codeHint.events[eventName][i].csharp
347
- ? a.codeHint.events[eventName][i].csharp.methodType
348
- : null;
349
- if (type !== "non-static") type = "static";
350
- out.eventHandlers.push({
351
- method: method,
352
- source: `entity: ${entityName}, action: ${actionName}, grant: ${a.grant}, event: ${eventName}`,
353
- type: type
354
- });
355
- });
356
- }
357
- });
358
- }
359
-
360
- const views = entities[entityName].views || {};
361
- for (let viewName in views) {
362
- const view = views[viewName];
363
- if (!Array.isArray(view))
364
- continue;
365
-
366
- view.forEach(v => {
367
- if (!v) return;
368
-
369
- if (typeof v.query === "string" && v.query.indexOf("lib:") === 0) {
370
- out.viewHandlers = out.viewHandlers || [];
371
- const method = v.query.substring(4);
372
- let type = v.codeHint && v.codeHint.query && v.codeHint.query.csharp
373
- ? v.codeHint.query.csharp.methodType
374
- : null;
375
- if (type !== "non-static") type = "static";
376
- out.viewHandlers.push({
377
- method: method,
378
- source: `entity: ${entityName}, view: ${viewName}, grant: ${v.grant}`,
379
- type: type
380
- });
381
- }
382
- });
383
- }
384
-
385
- const channels = entities[entityName].features?.vn_text?.channels;
386
- if (channels != null) {
387
- channels.forEach(channel => {
388
- if (!channel.nativeBuilder || typeof channel.nativeBuilder !== "string" || channel.nativeBuilder.indexOf("lib:") !== 0) return;
389
-
390
- out.vnTextChannels = out.vnTextChannels || [];
391
- const method = channel.nativeBuilder.substring(4);
392
- let type = channel.codeHint && channel.codeHint.nativeBuilder && channel.codeHint.nativeBuilder.csharp
393
- ? channel.codeHint.nativeBuilder.csharp.methodType
394
- : null;
395
- if (type !== "non-static") type = "static";
396
- out.vnTextChannels.push({
397
- method: method,
398
- source: `entity: ${entityName}, feature: vn_text, channel: ${channel.name}`,
399
- type: type
400
- });
401
- });
402
- }
403
- }
404
-
405
- if (out.strEnumClasses)
406
- strEnumClasses += out.strEnumClasses;
407
-
408
- const delegators = (out.delegators || []).reduce((prev, cur) => {
409
- if (cur.method in prev) {
410
- if (prev[cur.method].indexOf(cur.source) === -1) {
411
- prev[cur.method].push(cur);
412
- }
413
- }
414
- else {
415
- prev[cur.method] = [cur];
416
- }
417
- return prev;
418
- }, {});
419
- const strDelegatorReferences = Object.keys(delegators).map(method => delegators[method].map(ev => ` // ${ev.source}`).join(newLine) + newLine + ` RegisterCustomMethod(${getCSharpFunc(method, delegators[method][0].type)});`).join(newLine);
420
-
421
- const viewHandlers = (out.viewHandlers || []).reduce((prev, cur) => {
422
- if (cur.method in prev) {
423
- if (prev[cur.method].indexOf(cur.source) === -1) {
424
- prev[cur.method].push(cur);
425
- }
426
- }
427
- else {
428
- prev[cur.method] = [cur];
429
- }
430
- return prev;
431
- }, {});
432
- const strViewHandlerReferences = Object.keys(viewHandlers).map(method => viewHandlers[method].map(ev => ` // ${ev.source}`).join(newLine) + newLine + ` RegisterCustomViewMethod(${getCSharpFunc(method, viewHandlers[method][0].type)});`).join(newLine);
433
-
434
- const vnTextChannels = (out.vnTextChannels || []).reduce((prev, cur) => {
435
- if (cur.method in prev) {
436
- if (prev[cur.method].indexOf(cur.source) === -1) {
437
- prev[cur.method].push(cur);
438
- }
439
- }
440
- else {
441
- prev[cur.method] = [cur];
442
- }
443
- return prev;
444
- }, {});
445
- const strVnTextChannels = Object.keys(vnTextChannels).map(method => vnTextChannels[method].map(channel => ` // ${channel.source}`).join(newLine) + newLine + ` RegisterCustomVnTextBuilderMethod(${getCSharpFunc(method, vnTextChannels[method][0].type)});`).join(newLine);
446
-
447
- const eventHandlers = (out.eventHandlers || []).reduce((prev, cur) => {
448
- if (cur.method in prev) {
449
- if (prev[cur.method].indexOf(cur.source) === -1) {
450
- prev[cur.method].push(cur);
451
- }
452
- }
453
- else {
454
- prev[cur.method] = [cur];
455
- }
456
- return prev;
457
- }, {});
458
- const strEventHandlerReferences = Object.keys(eventHandlers).map(method => eventHandlers[method].map(ev => ` // ${ev.source}`).join(newLine) + newLine + ` RegisterEvent(${getCSharpFunc(method, eventHandlers[method][0].type)});`).join(newLine);
459
-
460
- const strJobReferences = Array.isArray(source.jobs)
461
- ? source.jobs
462
- .filter(job => job !== null && typeof(job) === "object" && job.action && typeof (job.action) === "string" && job.action.indexOf("lib:") === 0)
463
- .map(job => ` RegisterJob<${job.action.substring(4).split(',')[0]}>();`)
464
- .join(newLine)
465
- : "";
466
-
467
- const code = `// This file was generated by Mushroom CLI ${package_json.version} (https://www.npmjs.com/package/mushroom-cli), please do not modify
468
-
469
- // NOTE: Compatible with Mushroom Server version 0.2.18 or higher (https://www.nuget.org/packages/Mushroom/)
470
-
471
- // ReSharper disable RedundantUsingDirective
472
- // ReSharper disable InconsistentNaming
473
- // ReSharper disable PartialTypeWithSinglePart
474
- // ReSharper disable UnusedMember.Global
475
- // ReSharper disable UnusedMember.Local
476
- // ReSharper disable UnusedParameter.Local
477
- // ReSharper disable IdentifierTypo
478
- // ReSharper disable StringLiteralTypo
479
- // ReSharper disable CommentTypo
480
- // ReSharper disable EmptyNamespace
481
-
482
- namespace ${namespace}
483
- {
484
- using MongoDB.Driver;
485
-
486
- public static class DbConnector
487
- {
488
- ${collectionNames}
489
- public static IMongoDatabase GetDatabase() => Mushroom.MushroomDaoFactory.GetDbAdapter() as IMongoDatabase;
490
-
491
- public static async System.Threading.Tasks.Task<T> FindByIdAsync<T, TId>(this IMongoCollection<T> collection, TId id) where T : Mushroom.Models.IResource<TId>
492
- {
493
- return await (await collection.FindAsync(Builders<T>.Filter.Eq(doc => doc.Id, id))).FirstOrDefaultAsync();
494
- }
495
-
496
- public static async System.Threading.Tasks.Task<T> FindByIdAsync<T, TId>(this IMongoCollection<T> collection, TId id, FindOptions<T> findOptions) where T : Mushroom.Models.IResource<TId>
497
- {
498
- return await (await collection.FindAsync(Builders<T>.Filter.Eq(doc => doc.Id, id), findOptions)).FirstOrDefaultAsync();
499
- }
500
-
501
- public static async System.Threading.Tasks.Task<T> FindByIdAsync<T, TId>(this IMongoCollection<T> collection, TId id, ProjectionDefinition<T> projection) where T : Mushroom.Models.IResource<TId>
502
- {
503
- return await (await collection.FindAsync(Builders<T>.Filter.Eq(doc => doc.Id, id), new FindOptions<T> { Projection = projection })).FirstOrDefaultAsync();
504
- }
505
- }
506
-
507
- public class ResourceNames
508
- {
509
- private ResourceNames() { }
510
-
511
- ${resourceNames}
512
- }
513
-
514
- public class RoleNames {
515
- private RoleNames() { }
516
-
517
- ${roleNames}
518
- }
519
- }
520
-
521
- namespace ${namespace}.Resources
522
- {
523
- ${strClasses}
524
- }
525
-
526
- namespace ${namespace}.Enums
527
- {
528
- ${strEnumClasses}
529
- }
530
-
531
- #if DEBUG
532
- namespace ${namespace}.CodeHelper
533
- {
534
- class RefactorHelper
535
- {
536
- private RefactorHelper() { }
537
- private void RegisterCustomMethod(System.Func<Mushroom.ActionArguments, System.Threading.Tasks.Task> fn) { }
538
- private void RegisterCustomMethod(System.Action<Mushroom.ActionArguments> fn) { }
539
- private void RegisterCustomViewMethod(System.Func<Mushroom.ViewArguments, System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable<object>>> fn) { }
540
- private void RegisterCustomViewMethod(System.Action<Mushroom.ViewArguments> fn) { }
541
- private void RegisterCustomVnTextBuilderMethod(System.Func<System.Collections.Generic.IEnumerable<string>, System.Collections.Generic.IEnumerable<string>> fn) { }
542
- private void RegisterEvent(System.Func<object, Mushroom.ActionArguments, System.Threading.Tasks.Task> fn) { }
543
- private void RegisterEvent(System.Action<object, Mushroom.ActionArguments> fn) { }
544
- private void RegisterJob<T>() where T : Mushroom.Job.JobBase { }
545
- private void Help()
546
- {
547
- ${strDelegatorReferences}
548
- ${strViewHandlerReferences}
549
- ${strVnTextChannels}
550
- ${strEventHandlerReferences}
551
- ${strJobReferences}
552
- }
553
- }
554
- }
555
- #endif
556
- `;
557
-
558
- common.ensureFolder(aliasProject.output);
559
-
560
- fs.writeFile(aliasProject.output, code, err => {
561
- if (err)
562
- throw err;
563
- console.log(`Generated CSharp MongoDb Classes for ${projectName}@${alias} to ${aliasProject.output}`);
564
- });
565
- }
566
-
567
- function generateCSharpClassMongoDbToFolder(source, className, fields, isRoot, description, out, aliasProject) {
568
- let content = "";
569
- const namespace = toCSharpName(source.name);
570
- if (description) {
571
- content +=
572
- ` /// <summary>
573
- /// ${singleLine(description)}
574
- /// </summary>
575
- `;
576
- }
577
- let supperClass = "";
578
- if (isRoot) {
579
- // thêm cho trường hợp không khai báo id hoặc id.type
580
- if (!fields.id) {
581
- fields.id = {
582
- type: "AutoId"
583
- };
584
- }
585
- if (!fields.id.type) fields.id.type = "AutoId";
586
-
587
- supperClass = " : Mushroom.Models.IResource<" + getCSharpTypeFromMushroomType(source, fields.id.type, true) + ">";
588
- }
589
- content += ` public class ${className}${supperClass}
590
- {
591
- `;
592
- for (const fieldName in fields) {
593
- if (!fields.hasOwnProperty(fieldName))
594
- continue;
595
-
596
- const field = fields[fieldName];
597
- let type;
598
- const propertyName = toCSharpName(fieldName);
599
- if (field.codeHint && field.codeHint.type && field.codeHint.type.csharp) {
600
- type = field.codeHint.type.csharp;
601
- }
602
- else if (field.type === "object") {
603
- generateCSharpClassMongoDbToFolder(source, className + "_" + propertyName, field.fields, false, null, out, aliasProject);
604
- type = className + "_" + propertyName;
605
- }
606
- else if (field.type === "array") {
607
- if (field.items.type === "object") {
608
- generateCSharpClassMongoDbToFolder(source, className + "_" + propertyName, field.items.fields, false, null, out, aliasProject);
609
- type = `System.Collections.Generic.List<${className}_${propertyName}>`;
610
- } else {
611
- type = `System.Collections.Generic.List<${getCSharpTypeFromMushroomType(source, field.items.type, field.items.validation && field.items.validation.required)}>`;
612
- }
613
- } else
614
- type = getCSharpTypeFromMushroomType(source, field.type, field.validation && field.validation.required);
615
- content +=
616
- ` /// <summary>
617
- /// ${singleLine(field.description)}
618
- /// </summary>
619
- `;
620
-
621
- if (isRoot && fieldName === "id") {
622
- content += ` [MongoDB.Bson.Serialization.Attributes.BsonId${field.type === "AutoId" && source.idType === "GUID" ? "(IdGenerator = typeof(MongoDB.Bson.Serialization.IdGenerators.GuidGenerator))" : ""}]${newLine}`;
623
- }
624
- content += ` [MongoDB.Bson.Serialization.Attributes.BsonElement("${isRoot && fieldName === "id" ? "_id" : fieldName}")]
625
- [MongoDB.Bson.Serialization.Attributes.BsonIgnoreIfNull]
626
- [Newtonsoft.Json.JsonProperty(PropertyName = "${fieldName}", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore${type === "System.DateTime" ? ", DefaultValueHandling = Newtonsoft.Json.DefaultValueHandling.Ignore" : ""})]
627
- `;
628
- if ((field.type === "AutoId" || field.type === "IdRef") && source.idType === "ObjectId") {
629
- content += " [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.ObjectId)]" + newLine;
630
- }
631
- if (field.type === "AutoId" && source.idType === "GUID") {
632
- content += " [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.String)]" + newLine;
633
- }
634
- if (field.type === "datetime") {
635
- content += " [MongoDB.Bson.Serialization.Attributes.BsonDateTimeOptions(Kind = System.DateTimeKind.Local)]" + newLine;
636
- }
637
- if (field.type === "array") {
638
- if ((field.items.type === "AutoId" || field.items.type === "IdRef") && source.idType === "ObjectId") {
639
- content += " [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.ObjectId)]" + newLine;
640
- }
641
- if (field.items.type === "AutoId" && source.idType === "GUID") {
642
- content += " [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.String)]" + newLine;
643
- }
644
- if (field.items.type === "datetime") {
645
- content += " [MongoDB.Bson.Serialization.Attributes.BsonDateTimeOptions(Kind = System.DateTimeKind.Local)]" + newLine;
646
- }
647
- }
648
-
649
- content += ` public ${type} ${propertyName} { get; set; }
650
-
651
- `;
652
-
653
- let strEnumClasses = generateEnumClass(source, {}, field, `${className.toUpperCase()}_${propertyName.toUpperCase()}_ENUM`);
654
-
655
- const match = strEnumClasses.match(/public class\s+(\w+)/);
656
- if (!match) continue;
657
- common.ensureFolder(aliasProject.output + "/Enums", true);
658
- strEnumClasses = `${header}
659
-
660
- namespace ${namespace}.Enums
661
- {
662
- ${strEnumClasses}
663
- }
664
- `;
665
-
666
- fs.writeFileSync(aliasProject.output + "/Enums/" + match[1] + ".cs", strEnumClasses);
667
- }
668
-
669
- content += ` [MongoDB.Bson.Serialization.Attributes.BsonExtraElements]
670
- [Newtonsoft.Json.JsonIgnore]
671
- public System.Collections.Generic.Dictionary<string, object> Mushroom_ExtraProperties { get; set; }
672
-
673
- }
674
- `;
675
-
676
- common.ensureFolder(aliasProject.output + "/Resources", true);
677
-
678
- content = `${header}
679
-
680
- namespace ${namespace}.Resources
681
- {
682
- ${content}
683
- }
684
- `;
685
-
686
- out.allClasses = out.allClasses || [];
687
-
688
- const normalizedName = className.toLowerCase();
689
- const duplicate = out.allClasses.find(c => c.normalizedName == normalizedName);
690
- if (duplicate) {
691
- fs.appendFileSync(aliasProject.output + "/Resources/" + duplicate.className + ".cs", content);
692
- }
693
- else {
694
- out.allClasses.push({
695
- className,
696
- normalizedName
697
- });
698
- fs.writeFileSync(aliasProject.output + "/Resources/" + className + ".cs", content);
699
- }
700
- }
701
-
702
- function genCSharpMongoDbClassesToFolder(projectName, alias, source, aliasProject) {
703
-
704
- if (fs.existsSync(aliasProject.output)) {
705
- try {
706
- fs.unlinkSync(aliasProject.output); // xóa file nếu có
707
- } catch(e) {}
708
- try {
709
- fs.rmSync(aliasProject.output, { recursive: true, force: true }); // xóa thư mục nếu có
710
- } catch(e) {}
711
- }
712
- fs.mkdirSync(aliasProject.output, { recursive: true, mode: 493 }); // 493 = 755 in octa
713
-
714
- const entities = common.getEntities(source, aliasProject.allowRoles, true);
715
-
716
- const namespace = toCSharpName(source.name);
717
-
718
- let collectionNames = "";
719
- let resourceNames = "";
720
- let roleNames = "";
721
-
722
- source.roles?.forEach(role => {
723
- if (!role.name) return;
724
- roleNames += `
725
- /// <summary>
726
- /// ${role.description ?? ""}
727
- /// </summary>
728
- public static string ${toCSharpName(role.name)} => "${role.name}";
729
- `;
730
- });
731
-
732
- const out = {};
733
- for (let entityName in entities) {
734
- if (!entities.hasOwnProperty(entityName))
735
- continue;
736
-
737
- const className = toCSharpName(entityName);
738
- collectionNames += ` public static string ${className}CollectionName => "${entities[entityName].storageName}";
739
- public static IMongoCollection<Resources.${className}> ${className}Collection => GetDatabase().GetCollection<Resources.${className}>(${className}CollectionName);
740
- `;
741
- resourceNames += ` public static string ${className} => "${entityName}";
742
- `;
743
-
744
- generateCSharpClassMongoDbToFolder(source, className, entities[entityName].fields, true, entities[entityName].description, out, aliasProject);
745
-
746
- const actions = entities[entityName].actions || {};
747
- for (let actionName in actions) {
748
- const action = actions[actionName];
749
- if (!Array.isArray(action))
750
- continue;
751
-
752
- action.forEach(a => {
753
- if (!a)
754
- return;
755
- if (typeof a.delegator === "string" && a.delegator.indexOf("lib:") === 0) {
756
- out.delegators = out.delegators || [];
757
- const method = a.delegator.substring(4);
758
- let type = a.codeHint && a.codeHint.delegator && a.codeHint.delegator.csharp
759
- ? a.codeHint.delegator.csharp.methodType
760
- : null;
761
- if (type !== "non-static") type = "static";
762
- out.delegators.push({
763
- method: method,
764
- source: `entity: ${entityName}, action: ${actionName}, grant: ${a.grant}`,
765
- type: type
766
- });
767
- }
768
-
769
- if (!a.events && typeof a.events !== "object") return;
770
-
771
- for (let eventName in a.events) {
772
- if (!Array.isArray(a.events[eventName])) return;
773
-
774
- out.eventHandlers = out.eventHandlers || [];
775
- a.events[eventName].forEach((ev, i) => {
776
- if (typeof ev !== "string" || ev.indexOf("lib:") !== 0) return;
777
- const method = ev.substring(4);
778
- let type = a.codeHint && a.codeHint.events
779
- && Array.isArray(a.codeHint.events[eventName])
780
- && a.codeHint.events[eventName][i]
781
- && a.codeHint.events[eventName][i].csharp
782
- ? a.codeHint.events[eventName][i].csharp.methodType
783
- : null;
784
- if (type !== "non-static") type = "static";
785
- out.eventHandlers.push({
786
- method: method,
787
- source: `entity: ${entityName}, action: ${actionName}, grant: ${a.grant}, event: ${eventName}`,
788
- type: type
789
- });
790
- });
791
- }
792
- });
793
- }
794
-
795
- const views = entities[entityName].views || {};
796
- for (let viewName in views) {
797
- const view = views[viewName];
798
- if (!Array.isArray(view))
799
- continue;
800
-
801
- view.forEach(v => {
802
- if (!v) return;
803
-
804
- if (typeof v.query === "string" && v.query.indexOf("lib:") === 0) {
805
- out.viewHandlers = out.viewHandlers || [];
806
- const method = v.query.substring(4);
807
- let type = v.codeHint && v.codeHint.query && v.codeHint.query.csharp
808
- ? v.codeHint.query.csharp.methodType
809
- : null;
810
- if (type !== "non-static") type = "static";
811
- out.viewHandlers.push({
812
- method: method,
813
- source: `entity: ${entityName}, view: ${viewName}, grant: ${v.grant}`,
814
- type: type
815
- });
816
- }
817
- });
818
- }
819
-
820
- const channels = entities[entityName].features?.vn_text?.channels;
821
- if (channels != null) {
822
- channels.forEach(channel => {
823
- if (!channel.nativeBuilder || typeof channel.nativeBuilder !== "string" || channel.nativeBuilder.indexOf("lib:") !== 0) return;
824
-
825
- out.vnTextChannels = out.vnTextChannels || [];
826
- const method = channel.nativeBuilder.substring(4);
827
- let type = channel.codeHint && channel.codeHint.nativeBuilder && channel.codeHint.nativeBuilder.csharp
828
- ? channel.codeHint.nativeBuilder.csharp.methodType
829
- : null;
830
- if (type !== "non-static") type = "static";
831
- out.vnTextChannels.push({
832
- method: method,
833
- source: `entity: ${entityName}, feature: vn_text, channel: ${channel.name}`,
834
- type: type
835
- });
836
- });
837
- }
838
- }
839
-
840
-
841
- const delegators = (out.delegators || []).reduce((prev, cur) => {
842
- if (cur.method in prev) {
843
- if (prev[cur.method].indexOf(cur.source) === -1) {
844
- prev[cur.method].push(cur);
845
- }
846
- }
847
- else {
848
- prev[cur.method] = [cur];
849
- }
850
- return prev;
851
- }, {});
852
- const strDelegatorReferences = Object.keys(delegators).map(method => delegators[method].map(ev => ` // ${ev.source}`).join(newLine) + newLine + ` RegisterCustomMethod(${getCSharpFunc(method, delegators[method][0].type)});`).join(newLine);
853
-
854
- const viewHandlers = (out.viewHandlers || []).reduce((prev, cur) => {
855
- if (cur.method in prev) {
856
- if (prev[cur.method].indexOf(cur.source) === -1) {
857
- prev[cur.method].push(cur);
858
- }
859
- }
860
- else {
861
- prev[cur.method] = [cur];
862
- }
863
- return prev;
864
- }, {});
865
- const strViewHandlerReferences = Object.keys(viewHandlers).map(method => viewHandlers[method].map(ev => ` // ${ev.source}`).join(newLine) + newLine + ` RegisterCustomViewMethod(${getCSharpFunc(method, viewHandlers[method][0].type)});`).join(newLine);
866
-
867
- const vnTextChannels = (out.vnTextChannels || []).reduce((prev, cur) => {
868
- if (cur.method in prev) {
869
- if (prev[cur.method].indexOf(cur.source) === -1) {
870
- prev[cur.method].push(cur);
871
- }
872
- }
873
- else {
874
- prev[cur.method] = [cur];
875
- }
876
- return prev;
877
- }, {});
878
- const strVnTextChannels = Object.keys(vnTextChannels).map(method => vnTextChannels[method].map(channel => ` // ${channel.source}`).join(newLine) + newLine + ` RegisterCustomVnTextBuilderMethod(${getCSharpFunc(method, vnTextChannels[method][0].type)});`).join(newLine);
879
-
880
- const eventHandlers = (out.eventHandlers || []).reduce((prev, cur) => {
881
- if (cur.method in prev) {
882
- if (prev[cur.method].indexOf(cur.source) === -1) {
883
- prev[cur.method].push(cur);
884
- }
885
- }
886
- else {
887
- prev[cur.method] = [cur];
888
- }
889
- return prev;
890
- }, {});
891
- const strEventHandlerReferences = Object.keys(eventHandlers).map(method => eventHandlers[method].map(ev => ` // ${ev.source}`).join(newLine) + newLine + ` RegisterEvent(${getCSharpFunc(method, eventHandlers[method][0].type)});`).join(newLine);
892
-
893
- const strJobReferences = Array.isArray(source.jobs)
894
- ? source.jobs
895
- .filter(job => job !== null && typeof(job) === "object" && job.action && typeof (job.action) === "string" && job.action.indexOf("lib:") === 0)
896
- .map(job => ` RegisterJob<${job.action.substring(4).split(',')[0]}>();`)
897
- .join(newLine)
898
- : "";
899
-
900
- const dbConnectorFileContent = `${header}
901
- using MongoDB.Driver;
902
-
903
- namespace ${namespace}
904
- {
905
- public static class DbConnector
906
- {
907
- ${collectionNames}
908
- public static IMongoDatabase GetDatabase() => Mushroom.MushroomDaoFactory.GetDbAdapter() as IMongoDatabase;
909
- }
910
- }
911
- `;
912
-
913
- const resourceNamesFileContent = `${header}
914
-
915
- namespace ${namespace}
916
- {
917
- public class ResourceNames
918
- {
919
- private ResourceNames() { }
920
-
921
- ${resourceNames}
922
- }
923
- }
924
- `;
925
-
926
- const roleNamesFileContent = `${header}
927
-
928
- namespace ${namespace}
929
- {
930
- public class RoleNames
931
- {
932
- private RoleNames() { }
933
-
934
- ${roleNames}
935
- }
936
- }
937
- `;
938
-
939
-
940
- const refactorHelperFileContent = `${header}
941
-
942
- #if DEBUG
943
- namespace ${namespace}
944
- {
945
- class RefactorHelper
946
- {
947
- private RefactorHelper() { }
948
- private void RegisterCustomMethod(System.Func<Mushroom.ActionArguments, System.Threading.Tasks.Task> fn) { }
949
- private void RegisterCustomMethod(System.Action<Mushroom.ActionArguments> fn) { }
950
- private void RegisterCustomViewMethod(System.Func<Mushroom.ViewArguments, System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable<object>>> fn) { }
951
- private void RegisterCustomViewMethod(System.Action<Mushroom.ViewArguments> fn) { }
952
- private void RegisterCustomVnTextBuilderMethod(System.Func<System.Collections.Generic.IEnumerable<string>, System.Collections.Generic.IEnumerable<string>> fn) { }
953
- private void RegisterEvent(System.Func<object, Mushroom.ActionArguments, System.Threading.Tasks.Task> fn) { }
954
- private void RegisterEvent(System.Action<object, Mushroom.ActionArguments> fn) { }
955
- private void RegisterJob<T>() where T : Mushroom.Job.JobBase { }
956
- private void Help()
957
- {
958
- ${strDelegatorReferences}
959
- ${strViewHandlerReferences}
960
- ${strVnTextChannels}
961
- ${strEventHandlerReferences}
962
- ${strJobReferences}
963
- }
964
- }
965
- }
966
- #endif
967
- `;
968
-
969
- const infoFileContent = `// Mushroom CLI version: ${package_json.version}${newLine}// Compatible with Mushroom Server version: 0.2.25.4 or higher (https://www.nuget.org/packages/Mushroom/)
970
- // For Mushroom Server 0.2.18 to 0.2.25.4: Please remove all FindById methods in DbConnector.cs`
971
-
972
- fs.writeFileSync(aliasProject.output + "/DbConnector.cs", dbConnectorFileContent);
973
- fs.writeFileSync(aliasProject.output + "/ResourceNames.cs", resourceNamesFileContent);
974
- fs.writeFileSync(aliasProject.output + "/RoleNames.cs", roleNamesFileContent);
975
- fs.writeFileSync(aliasProject.output + "/RefactorHelper.cs", refactorHelperFileContent);
976
- fs.writeFileSync(aliasProject.output + "/Info.cs", infoFileContent);
977
-
978
- console.log(`Generated CSharp MongoDb Classes for ${projectName}@${alias} to folder ${aliasProject.output}`);
979
- }
980
- //#endregion
981
-
982
- //#region CSharp Driver
983
- function generateCSharpClassDriver(source, className, fields, description, out) {
984
- let strClasses = "";
985
- let strEnumClasses = "";
986
- let content = "";
987
- if (description) {
988
- content +=
989
- ` /// <summary>
990
- /// ${singleLine(description)}
991
- /// </summary>
992
- `;
993
- }
994
- content += ` public partial class ${className}
995
- {
996
- `;
997
-
998
- for (let fieldName in fields) {
999
- if (!fields.hasOwnProperty(fieldName))
1000
- continue;
1001
-
1002
- const field = fields[fieldName];
1003
-
1004
- const propertyName = toCSharpName(fieldName);
1005
- let type;
1006
- if (field.type === "object") {
1007
- strClasses += generateCSharpClassDriver(source, className + "_" + propertyName, field.fields, null, out) + newLine;
1008
- type = className + "_" + propertyName;
1009
- }
1010
- else if (field.type === "array") {
1011
- if (field.items.type === "object") {
1012
- strClasses += generateCSharpClassDriver(source, className + "_" + propertyName, field.items.fields, null, out) + newLine;
1013
- type = `System.Collections.Generic.List<${className}_${propertyName}>`;
1014
- } else {
1015
- type = `System.Collections.Generic.List<${getCSharpTypeFromMushroomType(source, field.items.type, field.items.validation && field.items.validation.required)}>`;
1016
- }
1017
- } else
1018
- type = getCSharpTypeFromMushroomType(source, field.type, field.validation && field.validation.required);
1019
- content +=
1020
- ` /// <summary>
1021
- /// ${singleLine(field.description)}
1022
- /// </summary>
1023
- [Newtonsoft.Json.JsonProperty(PropertyName ="${fieldName}", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore${type === "System.Datetime" ? ", DefaultValueHandling = Newtonsoft.Json.DefaultValueHandling.Ignore" : ""})]
1024
- public ${type} ${propertyName} { get; set; }
1025
-
1026
- `;
1027
- strEnumClasses += generateEnumClass(source, out, field, `${className.toUpperCase()}_${propertyName.toUpperCase()}_ENUM`);
1028
- }
1029
-
1030
- if (strEnumClasses) {
1031
- out.strEnumClasses = out.strEnumClasses || "";
1032
-
1033
- out.strEnumClasses += strEnumClasses;
1034
- }
1035
-
1036
-
1037
- content += " }" + newLine;
1038
- return strClasses + newLine + content;
1039
- }
1040
-
1041
- function genCSharpDriver(args, projectName, project, alias, source) {
1042
- const aliasProject = ((project.csharpDriver || {}).alias || {})[alias];
1043
-
1044
- if (!aliasProject) {
1045
- throw new Error(`Not found gen c#-driver configuration. Please run 'npx mushroom-cli config ${projectName} gen c#-driver OUTPUT_FILE.cs${alias === "default" ? "" : " alias " + alias}' first`);
1046
- }
1047
-
1048
- const entities = common.getEntities(source, aliasProject.allowRoles);
1049
-
1050
- const namespace = toCSharpName(source.name);
1051
-
1052
- let strClasses = "";
1053
- let strEnumClasses = "";
1054
- let codeStaticCtor = "";
1055
- let codeStaticProperties = "";
1056
- let codeConnectors = "";
1057
- let codeExtraClasses = "";
1058
-
1059
- const out = {};
1060
-
1061
- let accessModifier = aliasProject.accessModifier || "internal";
1062
-
1063
- for (const entityName in entities) {
1064
- if (!entities.hasOwnProperty(entityName))
1065
- continue;
1066
-
1067
- const className = toCSharpName(entityName);
1068
-
1069
- strClasses += generateCSharpClassDriver(source, className, entities[entityName].fields, entities[entityName].description, out);
1070
- codeStaticCtor += ` ${className} = new ${className}Connector(client);${newLine}`;
1071
- codeStaticProperties += ` public static ${className}Connector ${className} { get; }${newLine}${newLine}`;
1072
-
1073
- const entity = entities[entityName];
1074
-
1075
- codeConnectors += ` ${accessModifier} partial class ${className}Connector : MushroomDriver.MushroomResourceConnector<${className}>
1076
- {
1077
- protected override string Resource { get; } = ${JSON.stringify(entityName)};
1078
-
1079
- `;
1080
-
1081
- if (Object.keys(entity.views).length) {
1082
- codeConnectors += ` public ${className}Connector(MushroomDriver.MushroomClient client) : base(client)
1083
- {
1084
- Views = new ${className}Views(Client, () => Resource);
1085
- }
1086
-
1087
- `;
1088
- } else {
1089
- codeConnectors += ` public ${className}Connector(MushroomDriver.MushroomClient client) : base(client) { }
1090
-
1091
- `;
1092
- }
1093
-
1094
- for (const actionName in entity.actions) {
1095
- if (!entity.actions.hasOwnProperty(actionName))
1096
- continue;
1097
-
1098
- switch (actionName) {
1099
- case "findMany":
1100
- codeConnectors += ` public System.Threading.Tasks.Task<System.Collections.Generic.List<${className}>> List(MushroomDriver.ListArg arg = null)
1101
- {
1102
- return InternalList(arg);
1103
- }
1104
-
1105
- `;
1106
- break;
1107
- case "findById":
1108
- codeConnectors += ` public System.Threading.Tasks.Task<${className}> FindById(MushroomDriver.FindByIdArg arg)
1109
- {
1110
- return InternalFindById(arg);
1111
- }
1112
-
1113
- `;
1114
- break;
1115
- case "createOne":
1116
- codeConnectors += ` public System.Threading.Tasks.Task<string> Create(MushroomDriver.CreateArg<${className}> arg)
1117
- {
1118
- return InternalCreate(arg);
1119
- }
1120
-
1121
- `;
1122
- break;
1123
- case "createMany":
1124
- codeConnectors += ` public System.Threading.Tasks.Task<System.Collections.Generic.List<string>> Create(MushroomDriver.BatchCreateArg<${className}> arg)
1125
- {
1126
- return InternalCreate(arg);
1127
- }
1128
-
1129
- `;
1130
- break;
1131
- case "updateOne":
1132
- codeConnectors += ` public System.Threading.Tasks.Task<string> Update(MushroomDriver.UpdateArg<${className}> arg)
1133
- {
1134
- return InternalUpdate(arg);
1135
- }
1136
-
1137
- `;
1138
- break;
1139
- case "updateMany":
1140
- codeConnectors += ` public System.Threading.Tasks.Task<System.Collections.Generic.List<string>> Update(MushroomDriver.BatchUpdateArg<${className}> arg)
1141
- {
1142
- return InternalUpdate(arg);
1143
- }
1144
-
1145
- `;
1146
- break;
1147
- case "updatePartially":
1148
- codeConnectors += ` public System.Threading.Tasks.Task<string> Update(MushroomDriver.PartialUpdateArg<${className}> arg)
1149
- {
1150
- return InternalUpdate(arg);
1151
- }
1152
-
1153
- public System.Threading.Tasks.Task<string> Update(MushroomDriver.PartialUpdateArg<System.Collections.Generic.Dictionary<string, object>> arg)
1154
- {
1155
- return InternalUpdate(arg);
1156
- }
1157
-
1158
- `;
1159
- break;
1160
- case "deleteOne":
1161
- codeConnectors += ` public System.Threading.Tasks.Task<long> Delete(MushroomDriver.DeleteArg arg)
1162
- {
1163
- return InternalDelete(arg);
1164
- }
1165
-
1166
- `;
1167
- break;
1168
- case "deleteMany":
1169
- codeConnectors += ` public System.Threading.Tasks.Task<long> Delete(MushroomDriver.BatchDeleteArg arg)
1170
- {
1171
- return InternalDelete(arg);
1172
- }
1173
-
1174
- `;
1175
- break;
1176
- default:
1177
- // if not start with _raw_http_method_ --> break;
1178
- if (actionName.indexOf("_raw_http_method_"))
1179
- break;
1180
-
1181
- const customMethod = toCSharpName(actionName.substring("_raw_http_method_".length));
1182
-
1183
- codeConnectors += ` public async System.Threading.Tasks.Task<${className}${customMethod}Result> ${customMethod}(${className}${customMethod}Arg arg)
1184
- {
1185
- if (arg == null)
1186
- throw new System.ArgumentNullException(nameof(arg));
1187
-
1188
- var request = new MushroomDriver.MushroomRequest
1189
- {
1190
- RootApiUrl = Client.RootApiUrl,
1191
- Url = Client.RootApiUrl + arg.BuildUrl(),
1192
- Method = arg.Method
1193
- };
1194
- var headers = new System.Collections.Generic.Dictionary<string, string>
1195
- {
1196
- {"X-Requested-With", "Mushroom Driver " + MushroomDriver.MushroomConnector.Version}
1197
- };
1198
- if (arg.UseXHttpMethodOverride)
1199
- {
1200
- headers["X-Http-Method-Override"] = request.Method;
1201
- request.Method = "POST";
1202
- }
1203
- request.Headers = headers;
1204
- request.Data = arg.CustomData ?? arg.Data;
1205
- var response = await MushroomDriver.MushroomConnector.Execute(request);
1206
- var result = response.GetResult<${className}${customMethod}Result>();
1207
- result.MushroomResponseMetadata = response.Metadata;
1208
- return result;
1209
- }
1210
-
1211
- `;
1212
-
1213
- codeExtraClasses += ` ${accessModifier} partial class ${className}${customMethod}Result
1214
- {
1215
- public System.Collections.Generic.Dictionary<string, object> MushroomResponseMetadata { get; set; }
1216
- }
1217
-
1218
- ${accessModifier} partial class ${className}${customMethod}Body { }
1219
-
1220
- ${accessModifier} partial class ${className}${customMethod}Arg : MushroomDriver.MushroomRequestArg
1221
- {
1222
- public override string BuildUrl()
1223
- {
1224
- BuildCustomUrl();
1225
- return CustomUrl;
1226
- }
1227
-
1228
- partial void BuildCustomUrl();
1229
-
1230
- private string OriginUrl => "${entityName}s/${actionName.substring("_raw_http_method_".length)}";
1231
-
1232
- private string CustomUrl { get; set; } = "${entityName}s/${actionName.substring("_raw_http_method_".length)}";
1233
-
1234
- public override string Method { get; } = "${actionName.substring("_raw_http_method_".length)}";
1235
-
1236
- public ${className}${customMethod}Body Data { get; set; }
1237
-
1238
- public object CustomData { get; set; }
1239
- }
1240
-
1241
- `;
1242
- break;
1243
- }
1244
- }
1245
-
1246
- if (Object.keys(entity.views).length) {
1247
- codeConnectors += ` public ${className}Views Views { get; }
1248
-
1249
- `;
1250
- codeExtraClasses += ` ${accessModifier} partial class ${className}Views : MushroomDriver.MushroomViewConnector
1251
- {
1252
- protected System.Func<string> FnResource;
1253
-
1254
- public ${className}Views(MushroomDriver.MushroomClient client, System.Func<string> fnResource) : base(client)
1255
- {
1256
- FnResource = fnResource;
1257
- }
1258
-
1259
- `;
1260
- let viewExtraClass = "";
1261
- for (let viewName in entity.views) {
1262
- if (!entity.views.hasOwnProperty(viewName))
1263
- continue;
1264
-
1265
- let viewMethodName = toCSharpName(viewName);
1266
-
1267
- let hasNoParamView = false;
1268
- entity.views[viewName].forEach(view => {
1269
- let role = view.grant === "*" ? "" : `_${toCSharpName(view.grant)}`;
1270
- let hasParameter = view.parameters && view.parameters.length;
1271
- if (hasParameter) {
1272
- codeExtraClasses += ` public System.Threading.Tasks.Task<System.Collections.Generic.List<${className}View_${viewMethodName}Result>> ${viewMethodName}(${className}View${role}_${viewMethodName}Arg arg)
1273
- {
1274
- return InternalExecuteView<${className}View_${viewMethodName}Result>(new MushroomDriver.ViewArg<${className}View${role}_${viewMethodName}Arg> {
1275
- Parameters = arg,
1276
- Resource = FnResource?.Invoke(),
1277
- ViewName = "${viewName}"
1278
- });
1279
- }
1280
-
1281
- `;
1282
- viewExtraClass += ` ${accessModifier} partial class ${className}View${role}_${viewMethodName}Arg
1283
- {
1284
- `;
1285
- view.parameters.forEach(p => {
1286
- let type = getCSharpTypeFromMushroomType(source, p.type, p.validation && p.validation.required);
1287
- if (p.isArray)
1288
- type = `System.Collections.Generic.List<${type}>`;
1289
- viewExtraClass += ` [Newtonsoft.Json.JsonProperty(PropertyName = "${p.field}")]
1290
- public ${type} ${toCSharpName(p.field)} { get; set; }
1291
-
1292
- `;
1293
- });
1294
- viewExtraClass += ` }
1295
-
1296
- `;
1297
- }
1298
- else if (!hasNoParamView) {
1299
- hasNoParamView = true;
1300
- codeExtraClasses += ` public System.Threading.Tasks.Task<System.Collections.Generic.List<${className}View_${viewMethodName}Result>> ${viewMethodName}()
1301
- {
1302
- return InternalExecuteView<${className}View_${viewMethodName}Result>(new MushroomDriver.ViewArg {
1303
- Resource = FnResource?.Invoke(),
1304
- ViewName = "${viewName}"
1305
- });
1306
- }
1307
-
1308
- `;
1309
- }
1310
- });
1311
-
1312
-
1313
- viewExtraClass += ` ${accessModifier} partial class ${className}View_${viewMethodName}Result
1314
- {
1315
-
1316
- }
1317
-
1318
- `;
1319
- }
1320
- codeExtraClasses += ` }
1321
-
1322
- ${viewExtraClass}`;
1323
- }
1324
-
1325
- codeConnectors += " }" + newLine + newLine;
1326
- }
1327
-
1328
- if (out.strEnumClasses)
1329
- strEnumClasses += out.strEnumClasses;
1330
-
1331
- const code = `// This file was generated by Mushroom CLI ${package_json.version} (https://www.npmjs.com/package/mushroom-cli), please do not modify
1332
-
1333
- // Require package: Mushroom.Driver version 1.4.0 or later (https://www.nuget.org/packages/Mushroom.Driver/)
1334
-
1335
- // ReSharper disable InconsistentNaming
1336
- // ReSharper disable PartialTypeWithSinglePart
1337
- // ReSharper disable PartialMethodWithSinglePart
1338
- // ReSharper disable UnusedMember.Global
1339
- // ReSharper disable UnusedMember.Local
1340
- // ReSharper disable IdentifierTypo
1341
- // ReSharper disable StringLiteralTypo
1342
- // ReSharper disable CommentTypo
1343
- // ReSharper disable AutoPropertyCanBeMadeGetOnly.Local
1344
-
1345
-
1346
- using JsonPropertyAttribute = Newtonsoft.Json.JsonPropertyAttribute;
1347
- using NullValueHandling = Newtonsoft.Json.NullValueHandling;
1348
- using ${namespace}.Resources;
1349
-
1350
- namespace ${namespace}
1351
- {
1352
- ${accessModifier} partial class API
1353
- {
1354
- static API()
1355
- {
1356
- CustomizeRootApiUrl();
1357
- var client = new MushroomDriver.MushroomClient(_rootApiUrl);
1358
- MushroomClient = client;
1359
-
1360
- ${Array.isArray(aliasProject.features) && aliasProject.features.indexOf("auth") !== -1 ? "Authentication = new MushroomDriver.Auth.Authentication(_rootApiUrl);" : ""}
1361
- ${Array.isArray(aliasProject.features) && aliasProject.features.indexOf("file") !== -1 ? "FileExtension = new MushroomDriver.File.FileExtension(_rootApiUrl);" : ""}
1362
-
1363
- ${codeStaticCtor}
1364
- }
1365
-
1366
- static partial void CustomizeRootApiUrl();
1367
-
1368
- private static string _rootApiUrl = ${JSON.stringify(common.getRootUrl(source))};
1369
-
1370
- public static MushroomDriver.MushroomClient MushroomClient { get; }
1371
-
1372
- ${Array.isArray(aliasProject.features) && aliasProject.features.indexOf("auth") !== -1 ? "public static MushroomDriver.Auth.Authentication Authentication { get; }" : ""}
1373
-
1374
- ${Array.isArray(aliasProject.features) && aliasProject.features.indexOf("file") !== -1 ? "public static MushroomDriver.File.FileExtension FileExtension { get; }" : ""}
1375
-
1376
- ${codeStaticProperties}
1377
- }
1378
-
1379
- /*${accessModifier} partial class API
1380
- {
1381
- static partial void CustomizeRootApiUrl()
1382
- {
1383
- _rootApiUrl = "your customized root api url";
1384
- }
1385
- }*/
1386
-
1387
- ${codeConnectors}${codeExtraClasses}
1388
- }
1389
-
1390
- namespace ${namespace}.Resources
1391
- {
1392
- ${strClasses}
1393
- }
1394
-
1395
- namespace ${namespace}.Enums
1396
- {
1397
- ${strEnumClasses}
1398
- }`;
1399
-
1400
- common.ensureFolder(aliasProject.output);
1401
-
1402
- fs.writeFileSync(aliasProject.output, code);
1403
- console.log(`Generated CSharp Driver for ${projectName}@${alias} to ${aliasProject.output}`);
1404
- }
1405
- //#endregion
1406
-
1407
- module.exports = {
1408
- genCSharpMongoDbClasses: genCSharpMongoDbClasses,
1409
- genCSharpDriver: genCSharpDriver
1410
- };
1
+ const fs = require("fs");
2
+ const common = require("../common.js");
3
+ const package_json = require("./../package.json");
4
+
5
+ //#region shared function
6
+ const newLine = `
7
+ `;
8
+ const header = `// NOTE: Please do not modify this file
9
+ // NOTE: Version and compatibility information: please see in Info.cs file
10
+
11
+ // ReSharper disable CheckNamespace
12
+ // ReSharper disable CommentTypo
13
+ // ReSharper disable EmptyNamespace
14
+ // ReSharper disable IdentifierTypo
15
+ // ReSharper disable InconsistentNaming
16
+ // ReSharper disable PartialTypeWithSinglePart
17
+ // ReSharper disable RedundantUsingDirective
18
+ // ReSharper disable StringLiteralTypo
19
+ // ReSharper disable UnusedMember.Global
20
+ // ReSharper disable UnusedMember.Local
21
+ // ReSharper disable UnusedParameter.Local
22
+ // ReSharper disable UnusedTypeParameter
23
+ `;
24
+
25
+ function singleLine(str) {
26
+ if (!str) return "";
27
+ return str.replace(/\r/g, "").replace(/\n/g, "<br/>");
28
+ }
29
+
30
+ function toVietnameseNonTongue(str) {
31
+ const signText =
32
+ "ăâđêôơưàảãạáằẳẵặắầẩẫậấèẻẽẹéềểễệếìỉĩịíòỏõọóồổỗộốờởỡợớùủũụúừửữựứỳỷỹỵýĂÂĐÐÊÔƠƯÀẢÃẠÁẰẲẴẶẮẦẨẪẬẤÈẺẼẸÉỀỂỄỆẾÌỈĨỊÍÒỎÕỌÓỒỔỖỘỐỜỞỠỢỚÙỦŨỤÚỪỬỮỰỨỲỶỸỴÝ";
33
+ const unsignedText =
34
+ "aadeoouaaaaaaaaaaaaaaaeeeeeeeeeeiiiiiooooooooooooooouuuuuuuuuuyyyyyAADDEOOUAAAAAAAAAAAAAAAEEEEEEEEEEIIIIIOOOOOOOOOOOOOOOUUUUUUUUUUYYYYY";
35
+ let returnValue = "";
36
+ for (let i = 0; i < str.length; i++) {
37
+ const index = signText.indexOf(str.charAt(i));
38
+ returnValue += index !== -1 ? unsignedText.charAt(index) : str.charAt(i);
39
+ }
40
+ return returnValue;
41
+ }
42
+
43
+ function toCSharpName(str) {
44
+ if (!str) return "_";
45
+ const name = toVietnameseNonTongue(str).replace(/\W/g, "_");
46
+ const c = name.charAt(0);
47
+ return (
48
+ ("0" <= c && c <= "9" ? "_" : "") + c.toUpperCase() + name.substring(1)
49
+ );
50
+ }
51
+
52
+ function getCSharpTypeFromMushroomType(source, type, required) {
53
+ switch (type) {
54
+ case "string":
55
+ return "string";
56
+ case "object":
57
+ return "";
58
+ case "boolean":
59
+ return required ? "bool" : "bool?";
60
+ case "integer":
61
+ return required ? "int" : "int?";
62
+ case "long":
63
+ return required ? "long" : "long?";
64
+ case "double":
65
+ return required ? "double" : "double?";
66
+ case "array":
67
+ return "";
68
+ case "datetime":
69
+ return required ? "System.DateTime" : "System.DateTime?";
70
+ case "IdRef":
71
+ case "AutoId":
72
+ if (source.idType === "ObjectId" || source.idType === "GUID")
73
+ return "string";
74
+ if (source.idType === "AutoIncInt") return "int";
75
+ if (source.idType === "AutoIncLong") return "long";
76
+ }
77
+ return "UNKNOWN_TYPE";
78
+ }
79
+
80
+ function getCSharpInitValue(csType, value) {
81
+ switch (csType) {
82
+ case "string":
83
+ return JSON.stringify(value);
84
+ case "int":
85
+ return parseInt(Number(value));
86
+ case "long":
87
+ return parseInt(Number(value)) + "L";
88
+ case "double":
89
+ return Number(value);
90
+ case "bool":
91
+ if (value === "false") return false;
92
+ if (value === "true") return true;
93
+ return "NotABoolean";
94
+ case "datetime":
95
+ return `System.DateTime.Parse(${JSON.stringify(value)})`;
96
+ default:
97
+ return "UNSUPPORTED";
98
+ }
99
+ }
100
+
101
+ function generateEnumClass(source, out, field, defaultClassName) {
102
+ if (!out) return "";
103
+
104
+ let strEnumClasses = "";
105
+ const validation =
106
+ field.type === "array" ? field.items.validation : field.validation;
107
+ if (!validation) return "";
108
+
109
+ if (!validation.validValues) return "";
110
+
111
+ const mrType = field.type === "array" ? field.items.type : field.type;
112
+ if (mrType == "object" || mrType == "array") {
113
+ console.log("Unsuported enum type for type ", mrType, field);
114
+ return "";
115
+ }
116
+
117
+ const type = getCSharpTypeFromMushroomType(source, mrType, true);
118
+
119
+ validation.codeHint = validation.codeHint || {};
120
+ if (validation.validValues) {
121
+ validation.codeHint.validValues = validation.codeHint.validValues || {};
122
+
123
+ if (!validation.codeHint.validValues.disabled) {
124
+ const enumClassName =
125
+ validation.codeHint.validValues.className || defaultClassName;
126
+
127
+ out.arrEnumClassNames = out.arrEnumClassNames || [];
128
+
129
+ if (out.arrEnumClassNames.indexOf(enumClassName) === -1) {
130
+ out.arrEnumClassNames.push(enumClassName);
131
+ strEnumClasses += ` /// <summary>
132
+ /// ${singleLine(validation.codeHint.validValues.description || field.description)}
133
+ /// </summary>
134
+ public class ${enumClassName}
135
+ {
136
+ private ${enumClassName}() { }
137
+
138
+ `;
139
+ const enumProperties =
140
+ validation.codeHint.validValues.nameMap || validation.validValues;
141
+ for (
142
+ let i = 0;
143
+ i < enumProperties.length && i < validation.validValues.length;
144
+ i++
145
+ ) {
146
+ strEnumClasses += ` public const ${type} ${toCSharpName(enumProperties[i])} = ${getCSharpInitValue(type, validation.validValues[i])};
147
+ `;
148
+ }
149
+ strEnumClasses += ` }
150
+
151
+ `;
152
+ }
153
+ }
154
+ }
155
+
156
+ return strEnumClasses;
157
+ }
158
+ //#endregion
159
+
160
+ //#region CSharp MongoDb Classes
161
+ function generateCSharpClassMongoDb(
162
+ source,
163
+ className,
164
+ fields,
165
+ isRoot,
166
+ description,
167
+ out,
168
+ ) {
169
+ let strClasses = "";
170
+ let strEnumClasses = "";
171
+ let content = "";
172
+ if (description) {
173
+ content += ` /// <summary>
174
+ /// ${singleLine(description)}
175
+ /// </summary>
176
+ `;
177
+ }
178
+ let supperClass = "";
179
+ if (isRoot) {
180
+ // thêm cho trường hợp không khai báo id hoặc id.type
181
+ if (!fields.id) {
182
+ fields.id = {
183
+ type: "AutoId",
184
+ };
185
+ }
186
+ if (!fields.id.type) fields.id.type = "AutoId";
187
+
188
+ supperClass =
189
+ " : Mushroom.Models.IResource<" +
190
+ getCSharpTypeFromMushroomType(source, fields.id.type, true) +
191
+ ">";
192
+ }
193
+ content += ` public class ${className}${supperClass}
194
+ {
195
+ `;
196
+ for (const fieldName in fields) {
197
+ if (!fields.hasOwnProperty(fieldName)) continue;
198
+
199
+ const field = fields[fieldName];
200
+ let type;
201
+ const propertyName = toCSharpName(fieldName);
202
+ if (field.codeHint && field.codeHint.type && field.codeHint.type.csharp) {
203
+ type = field.codeHint.type.csharp;
204
+ } else if (field.type === "object") {
205
+ strClasses +=
206
+ generateCSharpClassMongoDb(
207
+ source,
208
+ className + "_" + propertyName,
209
+ field.fields,
210
+ false,
211
+ null,
212
+ out,
213
+ ) + newLine;
214
+ type = className + "_" + propertyName;
215
+ } else if (field.type === "array") {
216
+ if (field.items.type === "object") {
217
+ strClasses +=
218
+ generateCSharpClassMongoDb(
219
+ source,
220
+ className + "_" + propertyName,
221
+ field.items.fields,
222
+ false,
223
+ null,
224
+ out,
225
+ ) + newLine;
226
+ type = `System.Collections.Generic.List<${className}_${propertyName}>`;
227
+ } else {
228
+ type = `System.Collections.Generic.List<${getCSharpTypeFromMushroomType(source, field.items.type, field.items.validation && field.items.validation.required)}>`;
229
+ }
230
+ } else
231
+ type = getCSharpTypeFromMushroomType(
232
+ source,
233
+ field.type,
234
+ field.validation && field.validation.required,
235
+ );
236
+ content += ` /// <summary>
237
+ /// ${singleLine(field.description)}
238
+ /// </summary>
239
+ `;
240
+
241
+ if (isRoot && fieldName === "id") {
242
+ content += ` [MongoDB.Bson.Serialization.Attributes.BsonId${field.type === "AutoId" && source.idType === "GUID" ? "(IdGenerator = typeof(MongoDB.Bson.Serialization.IdGenerators.GuidGenerator))" : ""}]${newLine}`;
243
+ }
244
+ content += ` [MongoDB.Bson.Serialization.Attributes.BsonElement("${isRoot && fieldName === "id" ? "_id" : fieldName}")]
245
+ [MongoDB.Bson.Serialization.Attributes.BsonIgnoreIfNull]
246
+ [Newtonsoft.Json.JsonProperty(PropertyName = "${fieldName}", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore${type === "System.DateTime" ? ", DefaultValueHandling = Newtonsoft.Json.DefaultValueHandling.Ignore" : ""})]
247
+ `;
248
+ if (
249
+ (field.type === "AutoId" || field.type === "IdRef") &&
250
+ source.idType === "ObjectId"
251
+ ) {
252
+ content +=
253
+ " [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.ObjectId)]" +
254
+ newLine;
255
+ }
256
+ if (field.type === "AutoId" && source.idType === "GUID") {
257
+ content +=
258
+ " [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.String)]" +
259
+ newLine;
260
+ }
261
+ if (field.type === "datetime") {
262
+ content +=
263
+ " [MongoDB.Bson.Serialization.Attributes.BsonDateTimeOptions(Kind = System.DateTimeKind.Local)]" +
264
+ newLine;
265
+ }
266
+ if (field.type === "array") {
267
+ if (
268
+ (field.items.type === "AutoId" || field.items.type === "IdRef") &&
269
+ source.idType === "ObjectId"
270
+ ) {
271
+ content +=
272
+ " [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.ObjectId)]" +
273
+ newLine;
274
+ }
275
+ if (field.items.type === "AutoId" && source.idType === "GUID") {
276
+ content +=
277
+ " [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.String)]" +
278
+ newLine;
279
+ }
280
+ if (field.items.type === "datetime") {
281
+ content +=
282
+ " [MongoDB.Bson.Serialization.Attributes.BsonDateTimeOptions(Kind = System.DateTimeKind.Local)]" +
283
+ newLine;
284
+ }
285
+ }
286
+
287
+ content += ` public ${type} ${propertyName} { get; set; }${newLine}${newLine}`;
288
+
289
+ strEnumClasses += generateEnumClass(
290
+ source,
291
+ out,
292
+ field,
293
+ `${className.toUpperCase()}_${propertyName.toUpperCase()}_ENUM`,
294
+ );
295
+ }
296
+ content += ` [MongoDB.Bson.Serialization.Attributes.BsonExtraElements]
297
+ public System.Collections.Generic.Dictionary<string, object> Mushroom_ExtraProperties { get; set; }
298
+
299
+ }
300
+ `;
301
+ if (strEnumClasses) {
302
+ out.strEnumClasses = out.strEnumClasses || "";
303
+
304
+ out.strEnumClasses += strEnumClasses;
305
+ }
306
+
307
+ return strClasses + newLine + content;
308
+ }
309
+
310
+ function getCSharpFunc(methodName, methodType) {
311
+ if (methodType === "static") return methodName;
312
+ const idx = methodName.lastIndexOf(".");
313
+ if (idx === -1) return methodName;
314
+ return `new ${methodName.substring(0, idx)}()${methodName.substring(idx)}`;
315
+ }
316
+
317
+ function genCSharpMongoDbClasses(args, projectName, project, alias, source) {
318
+ const aliasProject = ((project.csharpMongo || {}).alias || {})[alias];
319
+
320
+ if (!aliasProject) {
321
+ throw new Error(
322
+ `Not found gen c#-mongo configuration. Please run 'npx mushroom-cli config ${projectName} gen c#-mongo OUTPUT_FILE.cs${alias === "default" ? "" : " alias " + alias}' first`,
323
+ );
324
+ }
325
+
326
+ if (aliasProject.outputToFolder) {
327
+ genCSharpMongoDbClassesToFolder(projectName, alias, source, aliasProject);
328
+ return;
329
+ }
330
+
331
+ const entities = common.getEntities(source, aliasProject.allowRoles, true);
332
+
333
+ const namespace = toCSharpName(source.name);
334
+
335
+ let strClasses = "";
336
+ let strEnumClasses = "";
337
+ let collectionNames = "";
338
+ let resourceNames = "";
339
+ let roleNames = "";
340
+
341
+ source.roles?.forEach((role) => {
342
+ if (!role.name) return;
343
+ roleNames += `
344
+ /// <summary>
345
+ /// ${role.description ?? ""}
346
+ /// </summary>
347
+ public static string ${toCSharpName(role.name)} => "${role.name}";
348
+ `;
349
+ });
350
+
351
+ const out = {};
352
+ for (let entityName in entities) {
353
+ if (!entities.hasOwnProperty(entityName)) continue;
354
+
355
+ const className = toCSharpName(entityName);
356
+ collectionNames += ` public static string ${className}CollectionName => "${entities[entityName].storageName}";
357
+ public static IMongoCollection<Resources.${className}> ${className}Collection => GetDatabase().GetCollection<Resources.${className}>(${className}CollectionName);
358
+ `;
359
+ resourceNames += ` public static string ${className} => "${entityName}";${newLine}`;
360
+ strClasses += generateCSharpClassMongoDb(
361
+ source,
362
+ className,
363
+ entities[entityName].fields,
364
+ true,
365
+ entities[entityName].description,
366
+ out,
367
+ );
368
+
369
+ const actions = entities[entityName].actions || {};
370
+ for (let actionName in actions) {
371
+ const action = actions[actionName];
372
+ if (!Array.isArray(action)) continue;
373
+
374
+ action.forEach((a) => {
375
+ if (!a) return;
376
+ if (
377
+ typeof a.delegator === "string" &&
378
+ a.delegator.indexOf("lib:") === 0
379
+ ) {
380
+ out.delegators = out.delegators || [];
381
+ const method = a.delegator.substring(4);
382
+ let type =
383
+ a.codeHint && a.codeHint.delegator && a.codeHint.delegator.csharp
384
+ ? a.codeHint.delegator.csharp.methodType
385
+ : null;
386
+ if (type !== "non-static") type = "static";
387
+ out.delegators.push({
388
+ method: method,
389
+ source: `entity: ${entityName}, action: ${actionName}, grant: ${a.grant}`,
390
+ type: type,
391
+ });
392
+ }
393
+
394
+ if (!a.events && typeof a.events !== "object") return;
395
+
396
+ for (let eventName in a.events) {
397
+ if (!Array.isArray(a.events[eventName])) return;
398
+
399
+ out.eventHandlers = out.eventHandlers || [];
400
+ a.events[eventName].forEach((ev, i) => {
401
+ if (typeof ev !== "string" || ev.indexOf("lib:") !== 0) return;
402
+ const method = ev.substring(4);
403
+ let type =
404
+ a.codeHint &&
405
+ a.codeHint.events &&
406
+ Array.isArray(a.codeHint.events[eventName]) &&
407
+ a.codeHint.events[eventName][i] &&
408
+ a.codeHint.events[eventName][i].csharp
409
+ ? a.codeHint.events[eventName][i].csharp.methodType
410
+ : null;
411
+ if (type !== "non-static") type = "static";
412
+ out.eventHandlers.push({
413
+ method: method,
414
+ source: `entity: ${entityName}, action: ${actionName}, grant: ${a.grant}, event: ${eventName}`,
415
+ type: type,
416
+ });
417
+ });
418
+ }
419
+ });
420
+ }
421
+
422
+ const views = entities[entityName].views || {};
423
+ for (let viewName in views) {
424
+ const view = views[viewName];
425
+ if (!Array.isArray(view)) continue;
426
+
427
+ view.forEach((v) => {
428
+ if (!v) return;
429
+
430
+ if (typeof v.query === "string" && v.query.indexOf("lib:") === 0) {
431
+ out.viewHandlers = out.viewHandlers || [];
432
+ const method = v.query.substring(4);
433
+ let type =
434
+ v.codeHint && v.codeHint.query && v.codeHint.query.csharp
435
+ ? v.codeHint.query.csharp.methodType
436
+ : null;
437
+ if (type !== "non-static") type = "static";
438
+ out.viewHandlers.push({
439
+ method: method,
440
+ source: `entity: ${entityName}, view: ${viewName}, grant: ${v.grant}`,
441
+ type: type,
442
+ });
443
+ }
444
+ });
445
+ }
446
+
447
+ const channels = entities[entityName].features?.vn_text?.channels;
448
+ if (channels != null) {
449
+ channels.forEach((channel) => {
450
+ if (
451
+ !channel.nativeBuilder ||
452
+ typeof channel.nativeBuilder !== "string" ||
453
+ channel.nativeBuilder.indexOf("lib:") !== 0
454
+ )
455
+ return;
456
+
457
+ out.vnTextChannels = out.vnTextChannels || [];
458
+ const method = channel.nativeBuilder.substring(4);
459
+ let type =
460
+ channel.codeHint &&
461
+ channel.codeHint.nativeBuilder &&
462
+ channel.codeHint.nativeBuilder.csharp
463
+ ? channel.codeHint.nativeBuilder.csharp.methodType
464
+ : null;
465
+ if (type !== "non-static") type = "static";
466
+ out.vnTextChannels.push({
467
+ method: method,
468
+ source: `entity: ${entityName}, feature: vn_text, channel: ${channel.name}`,
469
+ type: type,
470
+ });
471
+ });
472
+ }
473
+ }
474
+
475
+ if (out.strEnumClasses) strEnumClasses += out.strEnumClasses;
476
+
477
+ const delegators = (out.delegators || []).reduce((prev, cur) => {
478
+ if (cur.method in prev) {
479
+ if (prev[cur.method].indexOf(cur.source) === -1) {
480
+ prev[cur.method].push(cur);
481
+ }
482
+ } else {
483
+ prev[cur.method] = [cur];
484
+ }
485
+ return prev;
486
+ }, {});
487
+ const strDelegatorReferences = Object.keys(delegators)
488
+ .map(
489
+ (method) =>
490
+ delegators[method]
491
+ .map((ev) => ` // ${ev.source}`)
492
+ .join(newLine) +
493
+ newLine +
494
+ ` RegisterCustomMethod(${getCSharpFunc(method, delegators[method][0].type)});`,
495
+ )
496
+ .join(newLine);
497
+
498
+ const viewHandlers = (out.viewHandlers || []).reduce((prev, cur) => {
499
+ if (cur.method in prev) {
500
+ if (prev[cur.method].indexOf(cur.source) === -1) {
501
+ prev[cur.method].push(cur);
502
+ }
503
+ } else {
504
+ prev[cur.method] = [cur];
505
+ }
506
+ return prev;
507
+ }, {});
508
+ const strViewHandlerReferences = Object.keys(viewHandlers)
509
+ .map(
510
+ (method) =>
511
+ viewHandlers[method]
512
+ .map((ev) => ` // ${ev.source}`)
513
+ .join(newLine) +
514
+ newLine +
515
+ ` RegisterCustomViewMethod(${getCSharpFunc(method, viewHandlers[method][0].type)});`,
516
+ )
517
+ .join(newLine);
518
+
519
+ const vnTextChannels = (out.vnTextChannels || []).reduce((prev, cur) => {
520
+ if (cur.method in prev) {
521
+ if (prev[cur.method].indexOf(cur.source) === -1) {
522
+ prev[cur.method].push(cur);
523
+ }
524
+ } else {
525
+ prev[cur.method] = [cur];
526
+ }
527
+ return prev;
528
+ }, {});
529
+ const strVnTextChannels = Object.keys(vnTextChannels)
530
+ .map(
531
+ (method) =>
532
+ vnTextChannels[method]
533
+ .map((channel) => ` // ${channel.source}`)
534
+ .join(newLine) +
535
+ newLine +
536
+ ` RegisterCustomVnTextBuilderMethod(${getCSharpFunc(method, vnTextChannels[method][0].type)});`,
537
+ )
538
+ .join(newLine);
539
+
540
+ const eventHandlers = (out.eventHandlers || []).reduce((prev, cur) => {
541
+ if (cur.method in prev) {
542
+ if (prev[cur.method].indexOf(cur.source) === -1) {
543
+ prev[cur.method].push(cur);
544
+ }
545
+ } else {
546
+ prev[cur.method] = [cur];
547
+ }
548
+ return prev;
549
+ }, {});
550
+ const strEventHandlerReferences = Object.keys(eventHandlers)
551
+ .map(
552
+ (method) =>
553
+ eventHandlers[method]
554
+ .map((ev) => ` // ${ev.source}`)
555
+ .join(newLine) +
556
+ newLine +
557
+ ` RegisterEvent(${getCSharpFunc(method, eventHandlers[method][0].type)});`,
558
+ )
559
+ .join(newLine);
560
+
561
+ const strJobReferences = Array.isArray(source.jobs)
562
+ ? source.jobs
563
+ .filter(
564
+ (job) =>
565
+ job !== null &&
566
+ typeof job === "object" &&
567
+ job.action &&
568
+ typeof job.action === "string" &&
569
+ job.action.indexOf("lib:") === 0,
570
+ )
571
+ .map(
572
+ (job) =>
573
+ ` RegisterJob<${job.action.substring(4).split(",")[0]}>();`,
574
+ )
575
+ .join(newLine)
576
+ : "";
577
+
578
+ const code = `// This file was generated by Mushroom CLI ${package_json.version} (https://www.npmjs.com/package/mushroom-cli), please do not modify
579
+
580
+ // NOTE: Compatible with Mushroom Server version 0.2.18 or higher (https://www.nuget.org/packages/Mushroom/)
581
+
582
+ // ReSharper disable RedundantUsingDirective
583
+ // ReSharper disable InconsistentNaming
584
+ // ReSharper disable PartialTypeWithSinglePart
585
+ // ReSharper disable UnusedMember.Global
586
+ // ReSharper disable UnusedMember.Local
587
+ // ReSharper disable UnusedParameter.Local
588
+ // ReSharper disable IdentifierTypo
589
+ // ReSharper disable StringLiteralTypo
590
+ // ReSharper disable CommentTypo
591
+ // ReSharper disable EmptyNamespace
592
+
593
+ namespace ${namespace}
594
+ {
595
+ using MongoDB.Driver;
596
+
597
+ public static class DbConnector
598
+ {
599
+ ${collectionNames}
600
+ public static IMongoDatabase GetDatabase() => Mushroom.MushroomDaoFactory.GetDbAdapter() as IMongoDatabase;
601
+
602
+ public static async System.Threading.Tasks.Task<T> FindByIdAsync<T, TId>(this IMongoCollection<T> collection, TId id) where T : Mushroom.Models.IResource<TId>
603
+ {
604
+ return await (await collection.FindAsync(Builders<T>.Filter.Eq(doc => doc.Id, id))).FirstOrDefaultAsync();
605
+ }
606
+
607
+ public static async System.Threading.Tasks.Task<T> FindByIdAsync<T, TId>(this IMongoCollection<T> collection, TId id, FindOptions<T> findOptions) where T : Mushroom.Models.IResource<TId>
608
+ {
609
+ return await (await collection.FindAsync(Builders<T>.Filter.Eq(doc => doc.Id, id), findOptions)).FirstOrDefaultAsync();
610
+ }
611
+
612
+ public static async System.Threading.Tasks.Task<T> FindByIdAsync<T, TId>(this IMongoCollection<T> collection, TId id, ProjectionDefinition<T> projection) where T : Mushroom.Models.IResource<TId>
613
+ {
614
+ return await (await collection.FindAsync(Builders<T>.Filter.Eq(doc => doc.Id, id), new FindOptions<T> { Projection = projection })).FirstOrDefaultAsync();
615
+ }
616
+ }
617
+
618
+ public class ResourceNames
619
+ {
620
+ private ResourceNames() { }
621
+
622
+ ${resourceNames}
623
+ }
624
+
625
+ public class RoleNames {
626
+ private RoleNames() { }
627
+
628
+ ${roleNames}
629
+ }
630
+ }
631
+
632
+ namespace ${namespace}.Resources
633
+ {
634
+ ${strClasses}
635
+ }
636
+
637
+ namespace ${namespace}.Enums
638
+ {
639
+ ${strEnumClasses}
640
+ }
641
+
642
+ #if DEBUG
643
+ namespace ${namespace}.CodeHelper
644
+ {
645
+ class RefactorHelper
646
+ {
647
+ private RefactorHelper() { }
648
+ private void RegisterCustomMethod(System.Func<Mushroom.ActionArguments, System.Threading.Tasks.Task> fn) { }
649
+ private void RegisterCustomMethod(System.Action<Mushroom.ActionArguments> fn) { }
650
+ private void RegisterCustomViewMethod(System.Func<Mushroom.ViewArguments, System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable<object>>> fn) { }
651
+ private void RegisterCustomViewMethod(System.Action<Mushroom.ViewArguments> fn) { }
652
+ private void RegisterCustomVnTextBuilderMethod(System.Func<System.Collections.Generic.IEnumerable<string>, System.Collections.Generic.IEnumerable<string>> fn) { }
653
+ private void RegisterEvent(System.Func<object, Mushroom.ActionArguments, System.Threading.Tasks.Task> fn) { }
654
+ private void RegisterEvent(System.Action<object, Mushroom.ActionArguments> fn) { }
655
+ private void RegisterJob<T>() where T : Mushroom.Job.JobBase { }
656
+ private void Help()
657
+ {
658
+ ${strDelegatorReferences}
659
+ ${strViewHandlerReferences}
660
+ ${strVnTextChannels}
661
+ ${strEventHandlerReferences}
662
+ ${strJobReferences}
663
+ }
664
+ }
665
+ }
666
+ #endif
667
+ `;
668
+
669
+ common.ensureFolder(aliasProject.output);
670
+
671
+ fs.writeFile(aliasProject.output, code, (err) => {
672
+ if (err) throw err;
673
+ console.log(
674
+ `Generated CSharp MongoDb Classes for ${projectName}@${alias} to ${aliasProject.output}`,
675
+ );
676
+ });
677
+ }
678
+
679
+ function generateCSharpClassMongoDbToFolder(
680
+ source,
681
+ className,
682
+ fields,
683
+ isRoot,
684
+ description,
685
+ out,
686
+ aliasProject,
687
+ ) {
688
+ let content = "";
689
+ const namespace = toCSharpName(source.name);
690
+ if (description) {
691
+ content += ` /// <summary>
692
+ /// ${singleLine(description)}
693
+ /// </summary>
694
+ `;
695
+ }
696
+ let supperClass = "";
697
+ if (isRoot) {
698
+ // thêm cho trường hợp không khai báo id hoặc id.type
699
+ if (!fields.id) {
700
+ fields.id = {
701
+ type: "AutoId",
702
+ };
703
+ }
704
+ if (!fields.id.type) fields.id.type = "AutoId";
705
+
706
+ supperClass =
707
+ " : Mushroom.Models.IResource<" +
708
+ getCSharpTypeFromMushroomType(source, fields.id.type, true) +
709
+ ">";
710
+ }
711
+ content += ` public class ${className}${supperClass}
712
+ {
713
+ `;
714
+ for (const fieldName in fields) {
715
+ if (!fields.hasOwnProperty(fieldName)) continue;
716
+
717
+ const field = fields[fieldName];
718
+ let type;
719
+ const propertyName = toCSharpName(fieldName);
720
+ if (field.codeHint && field.codeHint.type && field.codeHint.type.csharp) {
721
+ type = field.codeHint.type.csharp;
722
+ } else if (field.type === "object") {
723
+ generateCSharpClassMongoDbToFolder(
724
+ source,
725
+ className + "_" + propertyName,
726
+ field.fields,
727
+ false,
728
+ null,
729
+ out,
730
+ aliasProject,
731
+ );
732
+ type = className + "_" + propertyName;
733
+ } else if (field.type === "array") {
734
+ if (field.items.type === "object") {
735
+ generateCSharpClassMongoDbToFolder(
736
+ source,
737
+ className + "_" + propertyName,
738
+ field.items.fields,
739
+ false,
740
+ null,
741
+ out,
742
+ aliasProject,
743
+ );
744
+ type = `System.Collections.Generic.List<${className}_${propertyName}>`;
745
+ } else {
746
+ type = `System.Collections.Generic.List<${getCSharpTypeFromMushroomType(source, field.items.type, field.items.validation && field.items.validation.required)}>`;
747
+ }
748
+ } else
749
+ type = getCSharpTypeFromMushroomType(
750
+ source,
751
+ field.type,
752
+ field.validation && field.validation.required,
753
+ );
754
+ content += ` /// <summary>
755
+ /// ${singleLine(field.description)}
756
+ /// </summary>
757
+ `;
758
+
759
+ if (isRoot && fieldName === "id") {
760
+ content += ` [MongoDB.Bson.Serialization.Attributes.BsonId${field.type === "AutoId" && source.idType === "GUID" ? "(IdGenerator = typeof(MongoDB.Bson.Serialization.IdGenerators.GuidGenerator))" : ""}]${newLine}`;
761
+ }
762
+ content += ` [MongoDB.Bson.Serialization.Attributes.BsonElement("${isRoot && fieldName === "id" ? "_id" : fieldName}")]
763
+ [MongoDB.Bson.Serialization.Attributes.BsonIgnoreIfNull]
764
+ [Newtonsoft.Json.JsonProperty(PropertyName = "${fieldName}", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore${type === "System.DateTime" ? ", DefaultValueHandling = Newtonsoft.Json.DefaultValueHandling.Ignore" : ""})]
765
+ `;
766
+ if (
767
+ (field.type === "AutoId" || field.type === "IdRef") &&
768
+ source.idType === "ObjectId"
769
+ ) {
770
+ content +=
771
+ " [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.ObjectId)]" +
772
+ newLine;
773
+ }
774
+ if (field.type === "AutoId" && source.idType === "GUID") {
775
+ content +=
776
+ " [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.String)]" +
777
+ newLine;
778
+ }
779
+ if (field.type === "datetime") {
780
+ content +=
781
+ " [MongoDB.Bson.Serialization.Attributes.BsonDateTimeOptions(Kind = System.DateTimeKind.Local)]" +
782
+ newLine;
783
+ }
784
+ if (field.type === "array") {
785
+ if (
786
+ (field.items.type === "AutoId" || field.items.type === "IdRef") &&
787
+ source.idType === "ObjectId"
788
+ ) {
789
+ content +=
790
+ " [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.ObjectId)]" +
791
+ newLine;
792
+ }
793
+ if (field.items.type === "AutoId" && source.idType === "GUID") {
794
+ content +=
795
+ " [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.String)]" +
796
+ newLine;
797
+ }
798
+ if (field.items.type === "datetime") {
799
+ content +=
800
+ " [MongoDB.Bson.Serialization.Attributes.BsonDateTimeOptions(Kind = System.DateTimeKind.Local)]" +
801
+ newLine;
802
+ }
803
+ }
804
+
805
+ content += ` public ${type} ${propertyName} { get; set; }
806
+
807
+ `;
808
+
809
+ let strEnumClasses = generateEnumClass(
810
+ source,
811
+ {},
812
+ field,
813
+ `${className.toUpperCase()}_${propertyName.toUpperCase()}_ENUM`,
814
+ );
815
+
816
+ const match = strEnumClasses.match(/public class\s+(\w+)/);
817
+ if (!match) continue;
818
+ common.ensureFolder(aliasProject.output + "/Enums", true);
819
+ strEnumClasses = `${header}
820
+
821
+ namespace ${namespace}.Enums
822
+ {
823
+ ${strEnumClasses}
824
+ }
825
+ `;
826
+
827
+ fs.writeFileSync(
828
+ aliasProject.output + "/Enums/" + match[1] + ".cs",
829
+ strEnumClasses,
830
+ );
831
+ }
832
+
833
+ content += ` [MongoDB.Bson.Serialization.Attributes.BsonExtraElements]
834
+ [Newtonsoft.Json.JsonIgnore]
835
+ public System.Collections.Generic.Dictionary<string, object> Mushroom_ExtraProperties { get; set; }
836
+
837
+ }
838
+ `;
839
+
840
+ common.ensureFolder(aliasProject.output + "/Resources", true);
841
+
842
+ content = `${header}
843
+
844
+ namespace ${namespace}.Resources
845
+ {
846
+ ${content}
847
+ }
848
+ `;
849
+
850
+ out.allClasses = out.allClasses || [];
851
+
852
+ const normalizedName = className.toLowerCase();
853
+ const duplicate = out.allClasses.find(
854
+ (c) => c.normalizedName == normalizedName,
855
+ );
856
+ if (duplicate) {
857
+ fs.appendFileSync(
858
+ aliasProject.output + "/Resources/" + duplicate.className + ".cs",
859
+ content,
860
+ );
861
+ } else {
862
+ out.allClasses.push({
863
+ className,
864
+ normalizedName,
865
+ });
866
+ fs.writeFileSync(
867
+ aliasProject.output + "/Resources/" + className + ".cs",
868
+ content,
869
+ );
870
+ }
871
+ }
872
+
873
+ function genCSharpMongoDbClassesToFolder(
874
+ projectName,
875
+ alias,
876
+ source,
877
+ aliasProject,
878
+ ) {
879
+ if (fs.existsSync(aliasProject.output)) {
880
+ try {
881
+ fs.unlinkSync(aliasProject.output); // xóa file nếu có
882
+ } catch (e) {}
883
+ try {
884
+ fs.rmSync(aliasProject.output, { recursive: true, force: true }); // xóa thư mục nếu có
885
+ } catch (e) {}
886
+ }
887
+ fs.mkdirSync(aliasProject.output, { recursive: true, mode: 493 }); // 493 = 755 in octa
888
+
889
+ const entities = common.getEntities(source, aliasProject.allowRoles, true);
890
+
891
+ const namespace = toCSharpName(source.name);
892
+
893
+ let collectionNames = "";
894
+ let resourceNames = "";
895
+ let roleNames = "";
896
+
897
+ source.roles?.forEach((role) => {
898
+ if (!role.name) return;
899
+ roleNames += `
900
+ /// <summary>
901
+ /// ${role.description ?? ""}
902
+ /// </summary>
903
+ public static string ${toCSharpName(role.name)} => "${role.name}";
904
+ `;
905
+ });
906
+
907
+ const out = {};
908
+ for (let entityName in entities) {
909
+ if (!entities.hasOwnProperty(entityName)) continue;
910
+
911
+ const className = toCSharpName(entityName);
912
+ collectionNames += ` public static string ${className}CollectionName => "${entities[entityName].storageName}";
913
+ public static IMongoCollection<Resources.${className}> ${className}Collection => GetDatabase().GetCollection<Resources.${className}>(${className}CollectionName);
914
+ `;
915
+ resourceNames += ` public static string ${className} => "${entityName}";
916
+ `;
917
+
918
+ generateCSharpClassMongoDbToFolder(
919
+ source,
920
+ className,
921
+ entities[entityName].fields,
922
+ true,
923
+ entities[entityName].description,
924
+ out,
925
+ aliasProject,
926
+ );
927
+
928
+ const actions = entities[entityName].actions || {};
929
+ for (let actionName in actions) {
930
+ const action = actions[actionName];
931
+ if (!Array.isArray(action)) continue;
932
+
933
+ action.forEach((a) => {
934
+ if (!a) return;
935
+ if (
936
+ typeof a.delegator === "string" &&
937
+ a.delegator.indexOf("lib:") === 0
938
+ ) {
939
+ out.delegators = out.delegators || [];
940
+ const method = a.delegator.substring(4);
941
+ let type =
942
+ a.codeHint && a.codeHint.delegator && a.codeHint.delegator.csharp
943
+ ? a.codeHint.delegator.csharp.methodType
944
+ : null;
945
+ if (type !== "non-static") type = "static";
946
+ out.delegators.push({
947
+ method: method,
948
+ source: `entity: ${entityName}, action: ${actionName}, grant: ${a.grant}`,
949
+ type: type,
950
+ });
951
+ }
952
+
953
+ if (!a.events && typeof a.events !== "object") return;
954
+
955
+ for (let eventName in a.events) {
956
+ if (!Array.isArray(a.events[eventName])) return;
957
+
958
+ out.eventHandlers = out.eventHandlers || [];
959
+ a.events[eventName].forEach((ev, i) => {
960
+ if (typeof ev !== "string" || ev.indexOf("lib:") !== 0) return;
961
+ const method = ev.substring(4);
962
+ let type =
963
+ a.codeHint &&
964
+ a.codeHint.events &&
965
+ Array.isArray(a.codeHint.events[eventName]) &&
966
+ a.codeHint.events[eventName][i] &&
967
+ a.codeHint.events[eventName][i].csharp
968
+ ? a.codeHint.events[eventName][i].csharp.methodType
969
+ : null;
970
+ if (type !== "non-static") type = "static";
971
+ out.eventHandlers.push({
972
+ method: method,
973
+ source: `entity: ${entityName}, action: ${actionName}, grant: ${a.grant}, event: ${eventName}`,
974
+ type: type,
975
+ });
976
+ });
977
+ }
978
+ });
979
+ }
980
+
981
+ const views = entities[entityName].views || {};
982
+ for (let viewName in views) {
983
+ const view = views[viewName];
984
+ if (!Array.isArray(view)) continue;
985
+
986
+ view.forEach((v) => {
987
+ if (!v) return;
988
+
989
+ if (typeof v.query === "string" && v.query.indexOf("lib:") === 0) {
990
+ out.viewHandlers = out.viewHandlers || [];
991
+ const method = v.query.substring(4);
992
+ let type =
993
+ v.codeHint && v.codeHint.query && v.codeHint.query.csharp
994
+ ? v.codeHint.query.csharp.methodType
995
+ : null;
996
+ if (type !== "non-static") type = "static";
997
+ out.viewHandlers.push({
998
+ method: method,
999
+ source: `entity: ${entityName}, view: ${viewName}, grant: ${v.grant}`,
1000
+ type: type,
1001
+ });
1002
+ }
1003
+ });
1004
+ }
1005
+
1006
+ const channels = entities[entityName].features?.vn_text?.channels;
1007
+ if (channels != null) {
1008
+ channels.forEach((channel) => {
1009
+ if (
1010
+ !channel.nativeBuilder ||
1011
+ typeof channel.nativeBuilder !== "string" ||
1012
+ channel.nativeBuilder.indexOf("lib:") !== 0
1013
+ )
1014
+ return;
1015
+
1016
+ out.vnTextChannels = out.vnTextChannels || [];
1017
+ const method = channel.nativeBuilder.substring(4);
1018
+ let type =
1019
+ channel.codeHint &&
1020
+ channel.codeHint.nativeBuilder &&
1021
+ channel.codeHint.nativeBuilder.csharp
1022
+ ? channel.codeHint.nativeBuilder.csharp.methodType
1023
+ : null;
1024
+ if (type !== "non-static") type = "static";
1025
+ out.vnTextChannels.push({
1026
+ method: method,
1027
+ source: `entity: ${entityName}, feature: vn_text, channel: ${channel.name}`,
1028
+ type: type,
1029
+ });
1030
+ });
1031
+ }
1032
+ }
1033
+
1034
+ const delegators = (out.delegators || []).reduce((prev, cur) => {
1035
+ if (cur.method in prev) {
1036
+ if (prev[cur.method].indexOf(cur.source) === -1) {
1037
+ prev[cur.method].push(cur);
1038
+ }
1039
+ } else {
1040
+ prev[cur.method] = [cur];
1041
+ }
1042
+ return prev;
1043
+ }, {});
1044
+ const strDelegatorReferences = Object.keys(delegators)
1045
+ .map(
1046
+ (method) =>
1047
+ delegators[method]
1048
+ .map((ev) => ` // ${ev.source}`)
1049
+ .join(newLine) +
1050
+ newLine +
1051
+ ` RegisterCustomMethod(${getCSharpFunc(method, delegators[method][0].type)});`,
1052
+ )
1053
+ .join(newLine);
1054
+
1055
+ const viewHandlers = (out.viewHandlers || []).reduce((prev, cur) => {
1056
+ if (cur.method in prev) {
1057
+ if (prev[cur.method].indexOf(cur.source) === -1) {
1058
+ prev[cur.method].push(cur);
1059
+ }
1060
+ } else {
1061
+ prev[cur.method] = [cur];
1062
+ }
1063
+ return prev;
1064
+ }, {});
1065
+ const strViewHandlerReferences = Object.keys(viewHandlers)
1066
+ .map(
1067
+ (method) =>
1068
+ viewHandlers[method]
1069
+ .map((ev) => ` // ${ev.source}`)
1070
+ .join(newLine) +
1071
+ newLine +
1072
+ ` RegisterCustomViewMethod(${getCSharpFunc(method, viewHandlers[method][0].type)});`,
1073
+ )
1074
+ .join(newLine);
1075
+
1076
+ const vnTextChannels = (out.vnTextChannels || []).reduce((prev, cur) => {
1077
+ if (cur.method in prev) {
1078
+ if (prev[cur.method].indexOf(cur.source) === -1) {
1079
+ prev[cur.method].push(cur);
1080
+ }
1081
+ } else {
1082
+ prev[cur.method] = [cur];
1083
+ }
1084
+ return prev;
1085
+ }, {});
1086
+ const strVnTextChannels = Object.keys(vnTextChannels)
1087
+ .map(
1088
+ (method) =>
1089
+ vnTextChannels[method]
1090
+ .map((channel) => ` // ${channel.source}`)
1091
+ .join(newLine) +
1092
+ newLine +
1093
+ ` RegisterCustomVnTextBuilderMethod(${getCSharpFunc(method, vnTextChannels[method][0].type)});`,
1094
+ )
1095
+ .join(newLine);
1096
+
1097
+ const eventHandlers = (out.eventHandlers || []).reduce((prev, cur) => {
1098
+ if (cur.method in prev) {
1099
+ if (prev[cur.method].indexOf(cur.source) === -1) {
1100
+ prev[cur.method].push(cur);
1101
+ }
1102
+ } else {
1103
+ prev[cur.method] = [cur];
1104
+ }
1105
+ return prev;
1106
+ }, {});
1107
+ const strEventHandlerReferences = Object.keys(eventHandlers)
1108
+ .map(
1109
+ (method) =>
1110
+ eventHandlers[method]
1111
+ .map((ev) => ` // ${ev.source}`)
1112
+ .join(newLine) +
1113
+ newLine +
1114
+ ` RegisterEvent(${getCSharpFunc(method, eventHandlers[method][0].type)});`,
1115
+ )
1116
+ .join(newLine);
1117
+
1118
+ const strJobReferences = Array.isArray(source.jobs)
1119
+ ? source.jobs
1120
+ .filter(
1121
+ (job) =>
1122
+ job !== null &&
1123
+ typeof job === "object" &&
1124
+ job.action &&
1125
+ typeof job.action === "string" &&
1126
+ job.action.indexOf("lib:") === 0,
1127
+ )
1128
+ .map(
1129
+ (job) =>
1130
+ ` RegisterJob<${job.action.substring(4).split(",")[0]}>();`,
1131
+ )
1132
+ .join(newLine)
1133
+ : "";
1134
+
1135
+ const dbConnectorFileContent = `${header}
1136
+ using MongoDB.Driver;
1137
+
1138
+ namespace ${namespace}
1139
+ {
1140
+ public static class DbConnector
1141
+ {
1142
+ ${collectionNames}
1143
+ public static IMongoDatabase GetDatabase() => Mushroom.MushroomDaoFactory.GetDbAdapter() as IMongoDatabase;
1144
+ }
1145
+ }
1146
+ `;
1147
+
1148
+ const resourceNamesFileContent = `${header}
1149
+
1150
+ namespace ${namespace}
1151
+ {
1152
+ public class ResourceNames
1153
+ {
1154
+ private ResourceNames() { }
1155
+
1156
+ ${resourceNames}
1157
+ }
1158
+ }
1159
+ `;
1160
+
1161
+ const roleNamesFileContent = `${header}
1162
+
1163
+ namespace ${namespace}
1164
+ {
1165
+ public class RoleNames
1166
+ {
1167
+ private RoleNames() { }
1168
+
1169
+ ${roleNames}
1170
+ }
1171
+ }
1172
+ `;
1173
+
1174
+ const refactorHelperFileContent = `${header}
1175
+
1176
+ #if DEBUG
1177
+ namespace ${namespace}
1178
+ {
1179
+ class RefactorHelper
1180
+ {
1181
+ private RefactorHelper() { }
1182
+ private void RegisterCustomMethod(System.Func<Mushroom.ActionArguments, System.Threading.Tasks.Task> fn) { }
1183
+ private void RegisterCustomMethod(System.Action<Mushroom.ActionArguments> fn) { }
1184
+ private void RegisterCustomViewMethod(System.Func<Mushroom.ViewArguments, System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable<object>>> fn) { }
1185
+ private void RegisterCustomViewMethod(System.Action<Mushroom.ViewArguments> fn) { }
1186
+ private void RegisterCustomVnTextBuilderMethod(System.Func<System.Collections.Generic.IEnumerable<string>, System.Collections.Generic.IEnumerable<string>> fn) { }
1187
+ private void RegisterEvent(System.Func<object, Mushroom.ActionArguments, System.Threading.Tasks.Task> fn) { }
1188
+ private void RegisterEvent(System.Action<object, Mushroom.ActionArguments> fn) { }
1189
+ private void RegisterJob<T>() where T : Mushroom.Job.JobBase { }
1190
+ private void Help()
1191
+ {
1192
+ ${strDelegatorReferences}
1193
+ ${strViewHandlerReferences}
1194
+ ${strVnTextChannels}
1195
+ ${strEventHandlerReferences}
1196
+ ${strJobReferences}
1197
+ }
1198
+ }
1199
+ }
1200
+ #endif
1201
+ `;
1202
+
1203
+ const infoFileContent = `// Mushroom CLI version: ${package_json.version}${newLine}// Compatible with Mushroom Server version: 0.2.25.4 or higher (https://www.nuget.org/packages/Mushroom/)
1204
+ // For Mushroom Server 0.2.18 to 0.2.25.4: Please remove all FindById methods in DbConnector.cs`;
1205
+
1206
+ fs.writeFileSync(
1207
+ aliasProject.output + "/DbConnector.cs",
1208
+ dbConnectorFileContent,
1209
+ );
1210
+ fs.writeFileSync(
1211
+ aliasProject.output + "/ResourceNames.cs",
1212
+ resourceNamesFileContent,
1213
+ );
1214
+ fs.writeFileSync(aliasProject.output + "/RoleNames.cs", roleNamesFileContent);
1215
+ fs.writeFileSync(
1216
+ aliasProject.output + "/RefactorHelper.cs",
1217
+ refactorHelperFileContent,
1218
+ );
1219
+ fs.writeFileSync(aliasProject.output + "/Info.cs", infoFileContent);
1220
+
1221
+ console.log(
1222
+ `Generated CSharp MongoDb Classes for ${projectName}@${alias} to folder ${aliasProject.output}`,
1223
+ );
1224
+ }
1225
+ //#endregion
1226
+
1227
+ //#region CSharp Driver
1228
+ function generateCSharpClassDriver(
1229
+ source,
1230
+ className,
1231
+ fields,
1232
+ description,
1233
+ out,
1234
+ ) {
1235
+ let strClasses = "";
1236
+ let strEnumClasses = "";
1237
+ let content = "";
1238
+ if (description) {
1239
+ content += ` /// <summary>
1240
+ /// ${singleLine(description)}
1241
+ /// </summary>
1242
+ `;
1243
+ }
1244
+ content += ` public partial class ${className}
1245
+ {
1246
+ `;
1247
+
1248
+ for (let fieldName in fields) {
1249
+ if (!fields.hasOwnProperty(fieldName)) continue;
1250
+
1251
+ const field = fields[fieldName];
1252
+
1253
+ const propertyName = toCSharpName(fieldName);
1254
+ let type;
1255
+ if (field.type === "object") {
1256
+ strClasses +=
1257
+ generateCSharpClassDriver(
1258
+ source,
1259
+ className + "_" + propertyName,
1260
+ field.fields,
1261
+ null,
1262
+ out,
1263
+ ) + newLine;
1264
+ type = className + "_" + propertyName;
1265
+ } else if (field.type === "array") {
1266
+ if (field.items.type === "object") {
1267
+ strClasses +=
1268
+ generateCSharpClassDriver(
1269
+ source,
1270
+ className + "_" + propertyName,
1271
+ field.items.fields,
1272
+ null,
1273
+ out,
1274
+ ) + newLine;
1275
+ type = `System.Collections.Generic.List<${className}_${propertyName}>`;
1276
+ } else {
1277
+ type = `System.Collections.Generic.List<${getCSharpTypeFromMushroomType(source, field.items.type, field.items.validation && field.items.validation.required)}>`;
1278
+ }
1279
+ } else
1280
+ type = getCSharpTypeFromMushroomType(
1281
+ source,
1282
+ field.type,
1283
+ field.validation && field.validation.required,
1284
+ );
1285
+ content += ` /// <summary>
1286
+ /// ${singleLine(field.description)}
1287
+ /// </summary>
1288
+ [Newtonsoft.Json.JsonProperty(PropertyName ="${fieldName}", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore${type === "System.Datetime" ? ", DefaultValueHandling = Newtonsoft.Json.DefaultValueHandling.Ignore" : ""})]
1289
+ public ${type} ${propertyName} { get; set; }
1290
+
1291
+ `;
1292
+ strEnumClasses += generateEnumClass(
1293
+ source,
1294
+ out,
1295
+ field,
1296
+ `${className.toUpperCase()}_${propertyName.toUpperCase()}_ENUM`,
1297
+ );
1298
+ }
1299
+
1300
+ if (strEnumClasses) {
1301
+ out.strEnumClasses = out.strEnumClasses || "";
1302
+
1303
+ out.strEnumClasses += strEnumClasses;
1304
+ }
1305
+
1306
+ content += " }" + newLine;
1307
+ return strClasses + newLine + content;
1308
+ }
1309
+
1310
+ function genCSharpDriver(args, projectName, project, alias, source) {
1311
+ const aliasProject = ((project.csharpDriver || {}).alias || {})[alias];
1312
+
1313
+ if (!aliasProject) {
1314
+ throw new Error(
1315
+ `Not found gen c#-driver configuration. Please run 'npx mushroom-cli config ${projectName} gen c#-driver OUTPUT_FILE.cs${alias === "default" ? "" : " alias " + alias}' first`,
1316
+ );
1317
+ }
1318
+
1319
+ const entities = common.getEntities(source, aliasProject.allowRoles);
1320
+
1321
+ const namespace = toCSharpName(source.name);
1322
+
1323
+ let strClasses = "";
1324
+ let strEnumClasses = "";
1325
+ let codeStaticCtor = "";
1326
+ let codeStaticProperties = "";
1327
+ let codeConnectors = "";
1328
+ let codeExtraClasses = "";
1329
+
1330
+ const out = {};
1331
+
1332
+ let accessModifier = aliasProject.accessModifier || "internal";
1333
+
1334
+ for (const entityName in entities) {
1335
+ if (!entities.hasOwnProperty(entityName)) continue;
1336
+
1337
+ const className = toCSharpName(entityName);
1338
+
1339
+ strClasses += generateCSharpClassDriver(
1340
+ source,
1341
+ className,
1342
+ entities[entityName].fields,
1343
+ entities[entityName].description,
1344
+ out,
1345
+ );
1346
+ codeStaticCtor += ` ${className} = new ${className}Connector(client);${newLine}`;
1347
+ codeStaticProperties += ` public static ${className}Connector ${className} { get; }${newLine}${newLine}`;
1348
+
1349
+ const entity = entities[entityName];
1350
+
1351
+ codeConnectors += ` ${accessModifier} partial class ${className}Connector : MushroomDriver.MushroomResourceConnector<${className}>
1352
+ {
1353
+ protected override string Resource { get; } = ${JSON.stringify(entityName)};
1354
+
1355
+ `;
1356
+
1357
+ if (Object.keys(entity.views).length) {
1358
+ codeConnectors += ` public ${className}Connector(MushroomDriver.MushroomClient client) : base(client)
1359
+ {
1360
+ Views = new ${className}Views(Client, () => Resource);
1361
+ }
1362
+
1363
+ `;
1364
+ } else {
1365
+ codeConnectors += ` public ${className}Connector(MushroomDriver.MushroomClient client) : base(client) { }
1366
+
1367
+ `;
1368
+ }
1369
+
1370
+ for (const actionName in entity.actions) {
1371
+ if (!entity.actions.hasOwnProperty(actionName)) continue;
1372
+
1373
+ switch (actionName) {
1374
+ case "findMany":
1375
+ codeConnectors += ` public System.Threading.Tasks.Task<System.Collections.Generic.List<${className}>> List(MushroomDriver.ListArg arg = null)
1376
+ {
1377
+ return InternalList(arg);
1378
+ }
1379
+
1380
+ `;
1381
+ break;
1382
+ case "findById":
1383
+ codeConnectors += ` public System.Threading.Tasks.Task<${className}> FindById(MushroomDriver.FindByIdArg arg)
1384
+ {
1385
+ return InternalFindById(arg);
1386
+ }
1387
+
1388
+ `;
1389
+ break;
1390
+ case "createOne":
1391
+ codeConnectors += ` public System.Threading.Tasks.Task<string> Create(MushroomDriver.CreateArg<${className}> arg)
1392
+ {
1393
+ return InternalCreate(arg);
1394
+ }
1395
+
1396
+ `;
1397
+ break;
1398
+ case "createMany":
1399
+ codeConnectors += ` public System.Threading.Tasks.Task<System.Collections.Generic.List<string>> Create(MushroomDriver.BatchCreateArg<${className}> arg)
1400
+ {
1401
+ return InternalCreate(arg);
1402
+ }
1403
+
1404
+ `;
1405
+ break;
1406
+ case "updateOne":
1407
+ codeConnectors += ` public System.Threading.Tasks.Task<string> Update(MushroomDriver.UpdateArg<${className}> arg)
1408
+ {
1409
+ return InternalUpdate(arg);
1410
+ }
1411
+
1412
+ `;
1413
+ break;
1414
+ case "updateMany":
1415
+ codeConnectors += ` public System.Threading.Tasks.Task<System.Collections.Generic.List<string>> Update(MushroomDriver.BatchUpdateArg<${className}> arg)
1416
+ {
1417
+ return InternalUpdate(arg);
1418
+ }
1419
+
1420
+ `;
1421
+ break;
1422
+ case "updatePartially":
1423
+ codeConnectors += ` public System.Threading.Tasks.Task<string> Update(MushroomDriver.PartialUpdateArg<${className}> arg)
1424
+ {
1425
+ return InternalUpdate(arg);
1426
+ }
1427
+
1428
+ public System.Threading.Tasks.Task<string> Update(MushroomDriver.PartialUpdateArg<System.Collections.Generic.Dictionary<string, object>> arg)
1429
+ {
1430
+ return InternalUpdate(arg);
1431
+ }
1432
+
1433
+ `;
1434
+ break;
1435
+ case "deleteOne":
1436
+ codeConnectors += ` public System.Threading.Tasks.Task<long> Delete(MushroomDriver.DeleteArg arg)
1437
+ {
1438
+ return InternalDelete(arg);
1439
+ }
1440
+
1441
+ `;
1442
+ break;
1443
+ case "deleteMany":
1444
+ codeConnectors += ` public System.Threading.Tasks.Task<long> Delete(MushroomDriver.BatchDeleteArg arg)
1445
+ {
1446
+ return InternalDelete(arg);
1447
+ }
1448
+
1449
+ `;
1450
+ break;
1451
+ default:
1452
+ // if not start with _raw_http_method_ --> break;
1453
+ if (actionName.indexOf("_raw_http_method_")) break;
1454
+
1455
+ const customMethod = toCSharpName(
1456
+ actionName.substring("_raw_http_method_".length),
1457
+ );
1458
+
1459
+ codeConnectors += ` public async System.Threading.Tasks.Task<${className}${customMethod}Result> ${customMethod}(${className}${customMethod}Arg arg)
1460
+ {
1461
+ if (arg == null)
1462
+ throw new System.ArgumentNullException(nameof(arg));
1463
+
1464
+ var request = new MushroomDriver.MushroomRequest
1465
+ {
1466
+ RootApiUrl = Client.RootApiUrl,
1467
+ Url = Client.RootApiUrl + arg.BuildUrl(),
1468
+ Method = arg.Method
1469
+ };
1470
+ var headers = new System.Collections.Generic.Dictionary<string, string>
1471
+ {
1472
+ {"X-Requested-With", "Mushroom Driver " + MushroomDriver.MushroomConnector.Version}
1473
+ };
1474
+ if (arg.UseXHttpMethodOverride)
1475
+ {
1476
+ headers["X-Http-Method-Override"] = request.Method;
1477
+ request.Method = "POST";
1478
+ }
1479
+ request.Headers = headers;
1480
+ request.Data = arg.CustomData ?? arg.Data;
1481
+ var response = await MushroomDriver.MushroomConnector.Execute(request);
1482
+ var result = response.GetResult<${className}${customMethod}Result>();
1483
+ result.MushroomResponseMetadata = response.Metadata;
1484
+ return result;
1485
+ }
1486
+
1487
+ `;
1488
+
1489
+ codeExtraClasses += ` ${accessModifier} partial class ${className}${customMethod}Result
1490
+ {
1491
+ public System.Collections.Generic.Dictionary<string, object> MushroomResponseMetadata { get; set; }
1492
+ }
1493
+
1494
+ ${accessModifier} partial class ${className}${customMethod}Body { }
1495
+
1496
+ ${accessModifier} partial class ${className}${customMethod}Arg : MushroomDriver.MushroomRequestArg
1497
+ {
1498
+ public override string BuildUrl()
1499
+ {
1500
+ BuildCustomUrl();
1501
+ return CustomUrl;
1502
+ }
1503
+
1504
+ partial void BuildCustomUrl();
1505
+
1506
+ private string OriginUrl => "${entityName}s/${actionName.substring("_raw_http_method_".length)}";
1507
+
1508
+ private string CustomUrl { get; set; } = "${entityName}s/${actionName.substring("_raw_http_method_".length)}";
1509
+
1510
+ public override string Method { get; } = "${actionName.substring("_raw_http_method_".length)}";
1511
+
1512
+ public ${className}${customMethod}Body Data { get; set; }
1513
+
1514
+ public object CustomData { get; set; }
1515
+ }
1516
+
1517
+ `;
1518
+ break;
1519
+ }
1520
+ }
1521
+
1522
+ if (Object.keys(entity.views).length) {
1523
+ codeConnectors += ` public ${className}Views Views { get; }
1524
+
1525
+ `;
1526
+ codeExtraClasses += ` ${accessModifier} partial class ${className}Views : MushroomDriver.MushroomViewConnector
1527
+ {
1528
+ protected System.Func<string> FnResource;
1529
+
1530
+ public ${className}Views(MushroomDriver.MushroomClient client, System.Func<string> fnResource) : base(client)
1531
+ {
1532
+ FnResource = fnResource;
1533
+ }
1534
+
1535
+ `;
1536
+ let viewExtraClass = "";
1537
+ for (let viewName in entity.views) {
1538
+ if (!entity.views.hasOwnProperty(viewName)) continue;
1539
+
1540
+ let viewMethodName = toCSharpName(viewName);
1541
+
1542
+ let hasNoParamView = false;
1543
+ entity.views[viewName].forEach((view) => {
1544
+ let role = view.grant === "*" ? "" : `_${toCSharpName(view.grant)}`;
1545
+ let hasParameter = view.parameters && view.parameters.length;
1546
+ if (hasParameter) {
1547
+ codeExtraClasses += ` public System.Threading.Tasks.Task<System.Collections.Generic.List<${className}View_${viewMethodName}Result>> ${viewMethodName}(${className}View${role}_${viewMethodName}Arg arg)
1548
+ {
1549
+ return InternalExecuteView<${className}View_${viewMethodName}Result>(new MushroomDriver.ViewArg<${className}View${role}_${viewMethodName}Arg> {
1550
+ Parameters = arg,
1551
+ Resource = FnResource?.Invoke(),
1552
+ ViewName = "${viewName}"
1553
+ });
1554
+ }
1555
+
1556
+ `;
1557
+ viewExtraClass += ` ${accessModifier} partial class ${className}View${role}_${viewMethodName}Arg
1558
+ {
1559
+ `;
1560
+ view.parameters.forEach((p) => {
1561
+ let type = getCSharpTypeFromMushroomType(
1562
+ source,
1563
+ p.type,
1564
+ p.validation && p.validation.required,
1565
+ );
1566
+ if (p.isArray) type = `System.Collections.Generic.List<${type}>`;
1567
+ viewExtraClass += ` [Newtonsoft.Json.JsonProperty(PropertyName = "${p.field}")]
1568
+ public ${type} ${toCSharpName(p.field)} { get; set; }
1569
+
1570
+ `;
1571
+ });
1572
+ viewExtraClass += ` }
1573
+
1574
+ `;
1575
+ } else if (!hasNoParamView) {
1576
+ hasNoParamView = true;
1577
+ codeExtraClasses += ` public System.Threading.Tasks.Task<System.Collections.Generic.List<${className}View_${viewMethodName}Result>> ${viewMethodName}()
1578
+ {
1579
+ return InternalExecuteView<${className}View_${viewMethodName}Result>(new MushroomDriver.ViewArg {
1580
+ Resource = FnResource?.Invoke(),
1581
+ ViewName = "${viewName}"
1582
+ });
1583
+ }
1584
+
1585
+ `;
1586
+ }
1587
+ });
1588
+
1589
+ viewExtraClass += ` ${accessModifier} partial class ${className}View_${viewMethodName}Result
1590
+ {
1591
+
1592
+ }
1593
+
1594
+ `;
1595
+ }
1596
+ codeExtraClasses += ` }
1597
+
1598
+ ${viewExtraClass}`;
1599
+ }
1600
+
1601
+ codeConnectors += " }" + newLine + newLine;
1602
+ }
1603
+
1604
+ if (out.strEnumClasses) strEnumClasses += out.strEnumClasses;
1605
+
1606
+ const code = `// This file was generated by Mushroom CLI ${package_json.version} (https://www.npmjs.com/package/mushroom-cli), please do not modify
1607
+
1608
+ // Require package: Mushroom.Driver version 1.4.0 or later (https://www.nuget.org/packages/Mushroom.Driver/)
1609
+
1610
+ // ReSharper disable InconsistentNaming
1611
+ // ReSharper disable PartialTypeWithSinglePart
1612
+ // ReSharper disable PartialMethodWithSinglePart
1613
+ // ReSharper disable UnusedMember.Global
1614
+ // ReSharper disable UnusedMember.Local
1615
+ // ReSharper disable IdentifierTypo
1616
+ // ReSharper disable StringLiteralTypo
1617
+ // ReSharper disable CommentTypo
1618
+ // ReSharper disable AutoPropertyCanBeMadeGetOnly.Local
1619
+
1620
+
1621
+ using JsonPropertyAttribute = Newtonsoft.Json.JsonPropertyAttribute;
1622
+ using NullValueHandling = Newtonsoft.Json.NullValueHandling;
1623
+ using ${namespace}.Resources;
1624
+
1625
+ namespace ${namespace}
1626
+ {
1627
+ ${accessModifier} partial class API
1628
+ {
1629
+ static API()
1630
+ {
1631
+ CustomizeRootApiUrl();
1632
+ var client = new MushroomDriver.MushroomClient(_rootApiUrl);
1633
+ MushroomClient = client;
1634
+
1635
+ ${Array.isArray(aliasProject.features) && aliasProject.features.indexOf("auth") !== -1 ? "Authentication = new MushroomDriver.Auth.Authentication(_rootApiUrl);" : ""}
1636
+ ${Array.isArray(aliasProject.features) && aliasProject.features.indexOf("file") !== -1 ? "FileExtension = new MushroomDriver.File.FileExtension(_rootApiUrl);" : ""}
1637
+
1638
+ ${codeStaticCtor}
1639
+ }
1640
+
1641
+ static partial void CustomizeRootApiUrl();
1642
+
1643
+ private static string _rootApiUrl = ${JSON.stringify(common.getRootUrl(source))};
1644
+
1645
+ public static MushroomDriver.MushroomClient MushroomClient { get; }
1646
+
1647
+ ${Array.isArray(aliasProject.features) && aliasProject.features.indexOf("auth") !== -1 ? "public static MushroomDriver.Auth.Authentication Authentication { get; }" : ""}
1648
+
1649
+ ${Array.isArray(aliasProject.features) && aliasProject.features.indexOf("file") !== -1 ? "public static MushroomDriver.File.FileExtension FileExtension { get; }" : ""}
1650
+
1651
+ ${codeStaticProperties}
1652
+ }
1653
+
1654
+ /*${accessModifier} partial class API
1655
+ {
1656
+ static partial void CustomizeRootApiUrl()
1657
+ {
1658
+ _rootApiUrl = "your customized root api url";
1659
+ }
1660
+ }*/
1661
+
1662
+ ${codeConnectors}${codeExtraClasses}
1663
+ }
1664
+
1665
+ namespace ${namespace}.Resources
1666
+ {
1667
+ ${strClasses}
1668
+ }
1669
+
1670
+ namespace ${namespace}.Enums
1671
+ {
1672
+ ${strEnumClasses}
1673
+ }`;
1674
+
1675
+ common.ensureFolder(aliasProject.output);
1676
+
1677
+ fs.writeFileSync(aliasProject.output, code);
1678
+ console.log(
1679
+ `Generated CSharp Driver for ${projectName}@${alias} to ${aliasProject.output}`,
1680
+ );
1681
+ }
1682
+ //#endregion
1683
+
1684
+ module.exports = {
1685
+ genCSharpMongoDbClasses: genCSharpMongoDbClasses,
1686
+ genCSharpDriver: genCSharpDriver,
1687
+ };