mushroom-cli 1.2.0-alpha.2 → 1.2.0-alpha.20

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