mushroom-cli 1.2.0-alpha.11 → 1.2.0-alpha.13

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