libmodulor 0.24.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +32 -151
  3. package/dist/esm/app/workers/AppUCsLoader.d.ts +2 -3
  4. package/dist/esm/apps/Helper/src/i18n.d.ts +39 -2
  5. package/dist/esm/apps/Helper/src/i18n.js +15 -1
  6. package/dist/esm/apps/Helper/src/lib/SrcFilesGenerator.d.ts +13 -0
  7. package/dist/esm/apps/Helper/src/lib/SrcFilesGenerator.js +37 -0
  8. package/dist/esm/apps/Helper/src/lib/consts.d.ts +2 -0
  9. package/dist/esm/apps/Helper/src/lib/consts.js +2 -0
  10. package/dist/esm/apps/Helper/src/lib/funcs.d.ts +4 -0
  11. package/dist/esm/apps/Helper/src/lib/funcs.js +9 -0
  12. package/dist/esm/apps/Helper/src/lib/io.d.ts +10 -0
  13. package/dist/esm/apps/Helper/src/lib/io.js +22 -0
  14. package/dist/esm/apps/Helper/src/lib/layers/app.d.ts +3 -0
  15. package/dist/esm/apps/Helper/src/lib/layers/app.js +30 -0
  16. package/dist/esm/apps/Helper/src/lib/layers/product.d.ts +3 -0
  17. package/dist/esm/apps/Helper/src/lib/layers/product.js +27 -0
  18. package/dist/esm/apps/Helper/src/lib/layers/project.d.ts +4 -0
  19. package/dist/esm/apps/Helper/src/lib/layers/project.js +163 -0
  20. package/dist/esm/apps/Helper/src/lib/layers/target.d.ts +3 -0
  21. package/dist/esm/apps/Helper/src/lib/layers/target.js +202 -0
  22. package/dist/esm/apps/Helper/src/lib/layers/uc.d.ts +3 -0
  23. package/dist/esm/apps/Helper/src/lib/layers/uc.js +113 -0
  24. package/dist/esm/apps/Helper/src/lib/project.js +21 -23
  25. package/dist/esm/apps/Helper/src/lib/types.d.ts +3 -0
  26. package/dist/esm/apps/Helper/src/lib/types.js +1 -0
  27. package/dist/esm/apps/Helper/src/manifest.d.ts +20 -0
  28. package/dist/esm/apps/Helper/src/manifest.js +20 -0
  29. package/dist/esm/apps/Helper/src/ucds/CreateAppUCD.d.ts +7 -0
  30. package/dist/esm/apps/Helper/src/ucds/CreateAppUCD.js +101 -0
  31. package/dist/esm/apps/Helper/src/ucds/CreateProductUCD.d.ts +7 -0
  32. package/dist/esm/apps/Helper/src/ucds/CreateProductUCD.js +101 -0
  33. package/dist/esm/apps/Helper/src/ucds/CreateProjectUCD.d.ts +1 -17
  34. package/dist/esm/apps/Helper/src/ucds/CreateProjectUCD.js +40 -34
  35. package/dist/esm/apps/Helper/src/ucds/CreateTargetUCD.d.ts +9 -0
  36. package/dist/esm/apps/Helper/src/ucds/CreateTargetUCD.js +109 -0
  37. package/dist/esm/apps/Helper/src/ucds/CreateUCUCD.d.ts +8 -0
  38. package/dist/esm/apps/Helper/src/ucds/CreateUCUCD.js +87 -0
  39. package/dist/esm/apps/Helper/src/ucds/DeleteGeneratedAppsTestsUCD.d.ts +1 -1
  40. package/dist/esm/apps/Helper/src/ucds/DeleteGeneratedAppsTestsUCD.js +1 -1
  41. package/dist/esm/apps/Helper/src/ucds/GenerateAppsTestsUCD.d.ts +1 -1
  42. package/dist/esm/apps/Helper/src/ucds/GenerateAppsTestsUCD.js +1 -1
  43. package/dist/esm/apps/Helper/src/ucds/TestAppUCD.d.ts +1 -1
  44. package/dist/esm/apps/Helper/src/ucds/TestAppUCD.js +1 -1
  45. package/dist/esm/convention.d.ts +15 -4
  46. package/dist/esm/convention.js +33 -9
  47. package/dist/esm/dt/Validation.d.ts +2 -2
  48. package/dist/esm/dt/base/TBase.d.ts +2 -0
  49. package/dist/esm/dt/base/TBase.js +3 -0
  50. package/dist/esm/dt/base/TObject.d.ts +6 -4
  51. package/dist/esm/dt/base/TObject.js +4 -5
  52. package/dist/esm/dt/base/TString.d.ts +2 -1
  53. package/dist/esm/dt/base/TString.js +22 -0
  54. package/dist/esm/dt/final/TFile.d.ts +13 -4
  55. package/dist/esm/dt/final/TFile.js +70 -8
  56. package/dist/esm/dt/final/TFileExtension.d.ts +1 -1
  57. package/dist/esm/dt/final/TFileMimeType.d.ts +2 -6
  58. package/dist/esm/dt/final/TFileMimeType.js +0 -6
  59. package/dist/esm/dt/final/TFilePath.d.ts +7 -0
  60. package/dist/esm/dt/final/TFilePath.js +5 -1
  61. package/dist/esm/dt/index.d.ts +1 -1
  62. package/dist/esm/error/funcs.d.ts +2 -0
  63. package/dist/esm/error/funcs.js +20 -0
  64. package/dist/esm/error/index.d.ts +1 -1
  65. package/dist/esm/error/index.js +1 -1
  66. package/dist/esm/i18n/WordingManager.d.ts +2 -1
  67. package/dist/esm/i18n/WordingManager.js +23 -2
  68. package/dist/esm/i18n/locales/de.js +8 -0
  69. package/dist/esm/i18n/locales/en.js +8 -0
  70. package/dist/esm/i18n/locales/es.js +8 -0
  71. package/dist/esm/i18n/locales/fr.js +8 -0
  72. package/dist/esm/i18n/types.d.ts +2 -2
  73. package/dist/esm/index.d.ts +2 -0
  74. package/dist/esm/index.js +2 -0
  75. package/dist/esm/index.node-test.d.ts +1 -1
  76. package/dist/esm/index.node-test.js +1 -1
  77. package/dist/esm/product/index.d.ts +1 -1
  78. package/dist/esm/product/index.js +1 -1
  79. package/dist/esm/product/workers/ProductUCsLoader.d.ts +8 -6
  80. package/dist/esm/product/workers/ProductUCsLoader.js +19 -5
  81. package/dist/esm/products/Helper/cli-node-core/container.d.ts +3 -0
  82. package/dist/esm/products/Helper/cli-node-core/container.js +26 -0
  83. package/dist/esm/products/Helper/cli-node-core/index.d.ts +1 -0
  84. package/dist/esm/products/Helper/cli-node-core/index.js +9 -0
  85. package/dist/esm/products/Helper/i18n.d.ts +101 -2
  86. package/dist/esm/products/Helper/targets/node-core-cli/container.d.ts +3 -0
  87. package/dist/esm/products/Helper/targets/node-core-cli/container.js +26 -0
  88. package/dist/esm/products/Helper/targets/node-core-cli/index.d.ts +1 -0
  89. package/dist/esm/products/Helper/targets/node-core-cli/index.js +9 -0
  90. package/dist/esm/std/FSManager.d.ts +7 -5
  91. package/dist/esm/std/FSManager.js +5 -6
  92. package/dist/esm/std/FormDataBuilder.d.ts +2 -1
  93. package/dist/esm/std/SettingsManager.d.ts +3 -16
  94. package/dist/esm/std/SettingsManager.js +1 -16
  95. package/dist/esm/std/ShellCommandExecutor.d.ts +1 -1
  96. package/dist/esm/std/consts.js +4 -4
  97. package/dist/esm/std/impl/EnvSettingsManager.d.ts +5 -4
  98. package/dist/esm/std/impl/EnvSettingsManager.js +40 -62
  99. package/dist/esm/std/impl/FakeFSManager.d.ts +3 -1
  100. package/dist/esm/std/impl/FakeFSManager.js +3 -0
  101. package/dist/esm/std/impl/FakeShellCommandExecutor.d.ts +12 -0
  102. package/dist/esm/std/impl/FakeShellCommandExecutor.js +30 -0
  103. package/dist/esm/std/impl/NodeFSManager.js +3 -2
  104. package/dist/esm/std/impl/StaticSettingsManager.d.ts +1 -1
  105. package/dist/esm/std/impl/StaticSettingsManager.js +3 -0
  106. package/dist/esm/std/index.d.ts +1 -0
  107. package/dist/esm/std/index.js +1 -0
  108. package/dist/esm/std/lib/settings.d.ts +5 -0
  109. package/dist/esm/std/lib/settings.js +39 -0
  110. package/dist/esm/target/edge-worker-hono-server/SyncEdgeWorkerHonoServerManager.d.ts +3 -1
  111. package/dist/esm/target/edge-worker-hono-server/SyncEdgeWorkerHonoServerManager.js +12 -7
  112. package/dist/esm/target/index.d.ts +1 -0
  113. package/dist/esm/target/index.js +1 -0
  114. package/dist/esm/target/lib/cli/CLIManager.d.ts +2 -2
  115. package/dist/esm/target/lib/client/consts.js +2 -1
  116. package/dist/esm/target/lib/entrypoint.d.ts +2 -0
  117. package/dist/esm/target/lib/entrypoint.js +1 -0
  118. package/dist/esm/target/lib/manifest.d.ts +13 -0
  119. package/dist/esm/target/lib/manifest.js +11 -0
  120. package/dist/esm/target/lib/mcp-server/MCPServerBooter.d.ts +2 -2
  121. package/dist/esm/target/lib/react/StyleContextProvider.d.ts +1 -0
  122. package/dist/esm/target/lib/react/form.d.ts +1 -1
  123. package/dist/esm/target/lib/react/form.js +1 -0
  124. package/dist/esm/target/lib/react/useAction.d.ts +1 -1
  125. package/dist/esm/target/lib/react/useAction.js +13 -12
  126. package/dist/esm/target/lib/server/CustomerFacingErrorBuilder.js +6 -1
  127. package/dist/esm/target/lib/server/ServerBooter.d.ts +2 -2
  128. package/dist/esm/target/lib/server/ServerRequestHandler.js +6 -2
  129. package/dist/esm/target/lib/server/consts.js +2 -1
  130. package/dist/esm/target/lib/server-express/funcs.d.ts +2 -0
  131. package/dist/esm/target/lib/server-express/funcs.js +8 -1
  132. package/dist/esm/target/lib/server-hono/funcs.d.ts +2 -1
  133. package/dist/esm/target/lib/server-hono/funcs.js +7 -3
  134. package/dist/esm/target/lib/web/input.d.ts +1 -0
  135. package/dist/esm/target/lib/web/input.js +5 -1
  136. package/dist/esm/target/node-express-server/NodeExpressServerManager.d.ts +3 -1
  137. package/dist/esm/target/node-express-server/NodeExpressServerManager.js +17 -12
  138. package/dist/esm/target/node-hono-server/NodeHonoServerManager.d.ts +3 -1
  139. package/dist/esm/target/node-hono-server/NodeHonoServerManager.js +15 -10
  140. package/dist/esm/target/node-stricli-cli/NodeStricliCLIManager.d.ts +3 -1
  141. package/dist/esm/target/node-stricli-cli/NodeStricliCLIManager.js +9 -5
  142. package/dist/esm/target/react-native-pure/UCFormField.js +2 -1
  143. package/dist/esm/target/react-native-pure/UCFormFieldControl.js +6 -4
  144. package/dist/esm/target/react-native-pure/UCFormFieldErr.d.ts +1 -1
  145. package/dist/esm/target/react-native-pure/UCFormFieldErr.js +4 -1
  146. package/dist/esm/target/react-native-pure/UCFormFieldHelp.d.ts +4 -0
  147. package/dist/esm/target/react-native-pure/UCFormFieldHelp.js +15 -0
  148. package/dist/esm/target/react-web-pure/UCFormField.js +2 -1
  149. package/dist/esm/target/react-web-pure/UCFormFieldErr.d.ts +1 -1
  150. package/dist/esm/target/react-web-pure/UCFormFieldErr.js +4 -1
  151. package/dist/esm/target/react-web-pure/UCFormFieldHelp.d.ts +4 -0
  152. package/dist/esm/target/react-web-pure/UCFormFieldHelp.js +14 -0
  153. package/dist/esm/testing/impl/NodeAppTesterConfigurator.d.ts +15 -0
  154. package/dist/esm/testing/impl/NodeAppTesterConfigurator.js +68 -0
  155. package/dist/esm/testing/impl/SimpleAppDocsEmitter/SimpleAppDocsEmitter.d.ts +7 -0
  156. package/dist/esm/testing/impl/SimpleAppDocsEmitter/SimpleAppDocsEmitter.js +59 -0
  157. package/dist/esm/testing/impl/SimpleAppDocsEmitter/markdown.d.ts +2 -0
  158. package/dist/esm/testing/impl/SimpleAppDocsEmitter/markdown.js +10 -0
  159. package/dist/esm/testing/impl/SimpleAppDocsEmitter/sequence-diagram.d.ts +2 -0
  160. package/dist/esm/testing/impl/SimpleAppDocsEmitter/sequence-diagram.js +92 -0
  161. package/dist/esm/testing/impl/SimpleAppDocsEmitter/tech-summary.d.ts +2 -0
  162. package/dist/esm/testing/impl/SimpleAppDocsEmitter/tech-summary.js +27 -0
  163. package/dist/esm/testing/impl/SimpleAppDocsEmitter/uc-summary.d.ts +2 -0
  164. package/dist/esm/testing/impl/SimpleAppDocsEmitter/uc-summary.js +63 -0
  165. package/dist/esm/testing/impl/VitestAppTestSuiteEmitter.d.ts +2 -0
  166. package/dist/esm/testing/impl/VitestAppTestSuiteEmitter.js +27 -10
  167. package/dist/esm/testing/impl/newNodeAppTester.js +4 -5
  168. package/dist/esm/testing/opts.d.ts +1 -1
  169. package/dist/esm/testing/uc-input.js +5 -2
  170. package/dist/esm/uc/exec.d.ts +42 -21
  171. package/dist/esm/uc/exec.js +48 -13
  172. package/dist/esm/uc/input-field.d.ts +6 -4
  173. package/dist/esm/uc/input-field.js +4 -5
  174. package/dist/esm/uc/side-effect.d.ts +10 -8
  175. package/dist/esm/uc/side-effect.js +5 -6
  176. package/dist/esm/uc/workers/UCInputFilesProcessor.js +3 -3
  177. package/dist/esm/uc/workers/UCInputValidator.js +2 -1
  178. package/dist/esm/uc/workers/UCOutputFilesProcessor.js +1 -1
  179. package/dist/esm/utils/bundling/webpack/loader.js +1 -1
  180. package/dist/esm/utils/index.d.ts +1 -1
  181. package/dist/esm/utils/ioc/bindCommon.d.ts +4 -4
  182. package/dist/esm/utils/ioc/bindCommon.js +17 -15
  183. package/dist/esm/utils/ioc/bindNodeCore.js +5 -0
  184. package/dist/esm/utils/ioc/bindServer.js +8 -2
  185. package/dist/esm/utils/types/utility-types.d.ts +4 -0
  186. package/package.json +19 -16
  187. package/pnpm-workspace.yaml +0 -8
  188. package/tsconfig.build.examples.json +0 -8
  189. package/tsconfig.json +0 -36
  190. package/vitest.config.ts +0 -16
@@ -0,0 +1,59 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
+ return function (target, key) { decorator(target, key, paramIndex); }
12
+ };
13
+ import { inject, injectable } from 'inversify';
14
+ import { APP_DOCS_FILE_NAME } from '../../../convention.js';
15
+ import { techSummary } from './tech-summary.js';
16
+ import { ucSummary } from './uc-summary.js';
17
+ let SimpleAppDocsEmitter = class SimpleAppDocsEmitter {
18
+ fsManager;
19
+ constructor(fsManager) {
20
+ this.fsManager = fsManager;
21
+ }
22
+ async exec({ appPath, ucDefSourcesCheckerOutput, }) {
23
+ const outPath = this.fsManager.path(appPath, APP_DOCS_FILE_NAME);
24
+ const tpl = template(ucDefSourcesCheckerOutput.items);
25
+ await this.fsManager.touch(outPath, tpl);
26
+ return {
27
+ outPath,
28
+ };
29
+ }
30
+ };
31
+ SimpleAppDocsEmitter = __decorate([
32
+ injectable(),
33
+ __param(0, inject('FSManager')),
34
+ __metadata("design:paramtypes", [Object])
35
+ ], SimpleAppDocsEmitter);
36
+ export { SimpleAppDocsEmitter };
37
+ // For now, we can have it here. When it becomes harder to maintain, we can introduce some kind of template engine.
38
+ // Be aware that this will introduce complexities on building the lib.
39
+ // We'll need to include these templates in the build and make them accessible via package.json "exports" or any other mechanism.
40
+ // Hence the choice to keep it simple for now.
41
+ // Defined it as function in case we need to pass args.
42
+ // Using --- for the comment to make it compatible with pandoc
43
+ // See https://stackoverflow.com/a/4829998/1259118
44
+ const template = (items) => `<!---
45
+ All this code has been auto generated.
46
+ DO NOT EDIT.
47
+ Or be prepared to see all your changes erased at the next generation.
48
+ -->
49
+
50
+ # App
51
+
52
+ ## Use Cases
53
+
54
+ ${items.map(ucSummary).join('\n\n')}
55
+
56
+ ## Technical Summary
57
+
58
+ ${techSummary(items)}
59
+ `;
@@ -0,0 +1,2 @@
1
+ export declare function pre(val: string | null | undefined): string;
2
+ export declare function thead(cols: string[]): string;
@@ -0,0 +1,10 @@
1
+ export function pre(val) {
2
+ if (!val) {
3
+ return '-';
4
+ }
5
+ return `\`${val}\``;
6
+ }
7
+ export function thead(cols) {
8
+ return `|#|${cols.join('|')}|
9
+ |---|${cols.map(() => '---').join('|')}|`;
10
+ }
@@ -0,0 +1,2 @@
1
+ import type { OutputItem } from '../../UCDefASTParser.js';
2
+ export declare function ucSequenceDiagram(item: OutputItem): string;
@@ -0,0 +1,92 @@
1
+ import { UC_MAIN_STEP_PREFIX_REGULAR } from '../../../convention.js';
2
+ const CHECK_POLICY = '🔐 Check policy';
3
+ const CHECK_POLICY_COND = 'when any validation fails';
4
+ const CHECK_POLICY_COND_ACTION = 'show failure';
5
+ const CLIENT_CONFIRM_N_COND = 'when does not confirm';
6
+ const CLIENT_CONFIRM_N_COND_ACTION = 'stop everything';
7
+ const CLIENT_CONFIRM_Q = '❓ Sure';
8
+ const CLIENT_CONFIRM_Y = 'Yes';
9
+ const FILL = '✏️ Fill';
10
+ const LB = '<br/>';
11
+ const OK = '👍 OK';
12
+ const SEND = '📤 Send';
13
+ const SUBMIT = '↩️ Submit';
14
+ const TRIGGER = '⤴️ Trigger';
15
+ export function ucSequenceDiagram(item) {
16
+ // Debugger : https://mermaid.live/edit
17
+ // Messages : https://mermaid.js.org/syntax/sequenceDiagram.html#messages
18
+ const client = 'Client';
19
+ const server = 'Server';
20
+ const user = 'User';
21
+ const lines = [`actor ${user}`];
22
+ const { ioIFields, ioOPI0Fields, ioOPI1Fields, lifecycleClientPolicy, lifecycleClientSteps, lifecycleServerPolicy, lifecycleServerSteps, metadataSensitive, } = item;
23
+ let req = TRIGGER;
24
+ if (ioIFields && ioIFields.length > 0) {
25
+ // TODO : Include only fields to fill manually ?
26
+ // Not sure though, as for CLI for example (i.e. noContext), one needs to provide all of them
27
+ req = `${FILL}${LB}${fields(item.ioIFields)}`;
28
+ }
29
+ lines.push(`${user}->>+${client}: ${req}`);
30
+ lines.push(`${user}->>${client}: ${SUBMIT}`);
31
+ if (metadataSensitive?.value) {
32
+ lines.push(...clientConfirm(client, user));
33
+ }
34
+ if (lifecycleClientPolicy) {
35
+ lines.push(...policy(client, user, lifecycleClientPolicy));
36
+ }
37
+ if (lifecycleClientSteps) {
38
+ lines.push(...mainSteps(client, lifecycleClientSteps));
39
+ }
40
+ // This is an approximation. Might need to improve it.
41
+ const hasServer = item.lifecycleServerPolicy?.value;
42
+ if (hasServer) {
43
+ req = SEND;
44
+ if (ioIFields && ioIFields.length > 0) {
45
+ req = `${req}${LB}${fields(item.ioIFields)}`;
46
+ }
47
+ lines.push(`${client}->>+${server}: ${req}`);
48
+ if (lifecycleServerPolicy) {
49
+ lines.push(...policy(server, user, lifecycleServerPolicy));
50
+ }
51
+ if (lifecycleServerSteps) {
52
+ lines.push(...mainSteps(server, lifecycleServerSteps));
53
+ }
54
+ let res = '';
55
+ if (ioOPI0Fields && ioOPI0Fields.length > 0) {
56
+ res += `${res}${LB}${fields(item.ioOPI0Fields)}`;
57
+ }
58
+ if (ioOPI1Fields && ioOPI1Fields?.length > 0) {
59
+ res += `${res}${LB}${fields(item.ioOPI1Fields)}`;
60
+ }
61
+ lines.push(`${server}-->>-${client}: ${OK}${res}`);
62
+ }
63
+ lines.push(`${client}-->>-${user}: ${OK}`);
64
+ return `\`\`\`mermaid
65
+ sequenceDiagram
66
+ ${lines.join('\n ')}
67
+ \`\`\``;
68
+ }
69
+ function clientConfirm(participant, caller) {
70
+ return [
71
+ `${participant}->>${caller}: ${CLIENT_CONFIRM_Q}`,
72
+ `${caller}->>${participant}: ${CLIENT_CONFIRM_Y}`,
73
+ `break ${CLIENT_CONFIRM_N_COND}`,
74
+ ` ${participant}-->${caller}: ${CLIENT_CONFIRM_N_COND_ACTION}`,
75
+ 'end',
76
+ ];
77
+ }
78
+ function fields(fields) {
79
+ return (fields?.map((f) => `${f.value.name}: ${f.value.dataType}`).join(LB) ||
80
+ '');
81
+ }
82
+ function mainSteps(participant, field) {
83
+ return field.map((f) => `${participant}->>${participant}: ${f.value.replace(UC_MAIN_STEP_PREFIX_REGULAR, '').trim()}`);
84
+ }
85
+ function policy(participant, caller, lifecyclePolicyField) {
86
+ return [
87
+ `${participant}->>${participant}: ${CHECK_POLICY} "${lifecyclePolicyField.value}"`,
88
+ `break ${CHECK_POLICY_COND}`,
89
+ ` ${participant}-->${caller}: ${CHECK_POLICY_COND_ACTION}`,
90
+ 'end',
91
+ ];
92
+ }
@@ -0,0 +1,2 @@
1
+ import { type OutputItem } from '../../UCDefASTParser.js';
2
+ export declare function techSummary(items: OutputItem[]): string;
@@ -0,0 +1,27 @@
1
+ import { OUTPUT_ITEM_FIELDS, } from '../../UCDefASTParser.js';
2
+ import { thead } from './markdown.js';
3
+ export function techSummary(items) {
4
+ return `${thead(OUTPUT_ITEM_FIELDS)}
5
+ ${items
6
+ .map((item, idx) => ['', idx + 1, ...OUTPUT_ITEM_FIELDS.map((f) => val(item[f])), ''].join('|'))
7
+ .join('\n')}`;
8
+ }
9
+ function val(value) {
10
+ if (!value) {
11
+ return '';
12
+ }
13
+ const values = Array.isArray(value) ? value : [value];
14
+ // NOTE : <br> won't work for every markdown renderer.
15
+ // See https://stackoverflow.com/questions/11700487/how-do-i-add-a-newline-in-a-markdown-table
16
+ return values.map(fmtVal).join('<br>');
17
+ }
18
+ function fmtVal(field) {
19
+ const { err, value } = field;
20
+ let res = (typeof value === 'string' ? value : value.raw) ?? '';
21
+ if (err) {
22
+ res += `❌ ${err}`;
23
+ }
24
+ res = res.replace(/[\u00A0-\u9999<>&]/g, (i) => `&#${i.charCodeAt(0)};`); // TS generics considered as HTML
25
+ res = res.replaceAll('|', '\\|'); // TS intersection vs Markdown table column
26
+ return res;
27
+ }
@@ -0,0 +1,2 @@
1
+ import type { OutputItem } from '../../UCDefASTParser.js';
2
+ export declare function ucSummary(item: OutputItem): string;
@@ -0,0 +1,63 @@
1
+ import { humanize } from '../../../utils/index.js';
2
+ import { pre, thead } from './markdown.js';
3
+ import { ucSequenceDiagram } from './sequence-diagram.js';
4
+ export function ucSummary(item) {
5
+ return `### ${item.metadataName?.value}
6
+
7
+ ${lifecycle(item)}
8
+
9
+ ${fields(item)}
10
+
11
+ #### Sequence Diagram
12
+
13
+ ${ucSequenceDiagram(item)}`;
14
+ }
15
+ const UC_FIELDS_TABLES_COLS = ['name', 'humanized', 'dataType'];
16
+ function fields(item) {
17
+ const { ioIFields, ioOPI0Fields, ioOPI1Fields } = item;
18
+ return `#### Input (I)
19
+
20
+ ${ucFieldsTable(ioIFields)}
21
+
22
+ #### Output (O)
23
+
24
+ ##### Part 0 (OPI0)
25
+
26
+ ${ucFieldsTable(ioOPI0Fields)}
27
+
28
+ ##### Part 1 (OPI1)
29
+
30
+ ${ucFieldsTable(ioOPI1Fields)}`;
31
+ }
32
+ function ucFieldsTable(fields) {
33
+ if (!fields || fields.length === 0) {
34
+ return 'None';
35
+ }
36
+ return `${thead(UC_FIELDS_TABLES_COLS)}
37
+ ${fields
38
+ ?.map(({ value: { dataType, name } }, idx) => [
39
+ '',
40
+ idx + 1,
41
+ pre(name),
42
+ name ? humanize(name) : '',
43
+ pre(dataType),
44
+ '',
45
+ ].join('|'))
46
+ .join('\n')}`;
47
+ }
48
+ function lifecycle(item) {
49
+ const { lifecycleClientPolicy, lifecycleServerPolicy } = item;
50
+ return `- **Type** : ${pre(lifecycleType(item))}
51
+ - **Client Policy** : ${pre(lifecycleClientPolicy?.value)}
52
+ - **Server Policy** : ${pre(lifecycleServerPolicy?.value)}`;
53
+ }
54
+ function lifecycleType(item) {
55
+ const { lifecycleClientPolicy, lifecycleServerPolicy } = item;
56
+ if (lifecycleClientPolicy && lifecycleServerPolicy) {
57
+ return 'Client / Server';
58
+ }
59
+ if (lifecycleClientPolicy) {
60
+ return 'Client only';
61
+ }
62
+ return 'Server only';
63
+ }
@@ -4,4 +4,6 @@ export declare class VitestAppTestSuiteEmitter implements AppTestSuiteEmitter {
4
4
  private fsManager;
5
5
  constructor(fsManager: FSManager);
6
6
  exec({ appPath, depsMapping, idx, monkeyTestingTimeoutInMs, serverPortRangeStart, }: Input): Promise<Output>;
7
+ private createConfiguratorIfNotExists;
8
+ private mapDeps;
7
9
  }
@@ -11,7 +11,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
11
  return function (target, key) { decorator(target, key, paramIndex); }
12
12
  };
13
13
  import { inject, injectable } from 'inversify';
14
- import { APP_I18N_NAME, APP_INDEX_NAME, APP_MANIFEST_NAME, APP_TEST_DIR_NAME, APP_TEST_MAIN_FILE_NAME, } from '../../convention.js';
14
+ import { APP_I18N_NAME, APP_INDEX_NAME, APP_MANIFEST_NAME, APP_TEST_CONFIGURATOR_FILE_NAME, APP_TEST_CONFIGURATOR_NAME, APP_TEST_DIR_NAME, APP_TEST_MAIN_FILE_NAME, } from '../../convention.js';
15
15
  let VitestAppTestSuiteEmitter = class VitestAppTestSuiteEmitter {
16
16
  fsManager;
17
17
  constructor(fsManager) {
@@ -21,16 +21,29 @@ let VitestAppTestSuiteEmitter = class VitestAppTestSuiteEmitter {
21
21
  const testPath = this.fsManager.path(appPath, APP_TEST_DIR_NAME);
22
22
  // Since we're using 'recursive: true', there will be no error if the directory already exists
23
23
  await this.fsManager.mkdir(testPath, { recursive: true });
24
- const outPath = this.fsManager.path(testPath, APP_TEST_MAIN_FILE_NAME);
25
- let tpl = template(serverPortRangeStart, idx, monkeyTestingTimeoutInMs);
26
- depsMapping?.forEach((to, from) => {
27
- tpl = tpl.replaceAll(`from '${from}'`, `from '${to}'`);
28
- });
29
- await this.fsManager.touch(outPath, tpl);
24
+ await this.createConfiguratorIfNotExists(testPath, depsMapping);
25
+ const testFilePath = this.fsManager.path(testPath, APP_TEST_MAIN_FILE_NAME);
26
+ const tpl = this.mapDeps(depsMapping, template(serverPortRangeStart, idx, monkeyTestingTimeoutInMs));
27
+ await this.fsManager.touch(testFilePath, tpl);
30
28
  return {
31
- outPath,
29
+ outPath: testFilePath,
32
30
  };
33
31
  }
32
+ async createConfiguratorIfNotExists(testPath, depsMapping) {
33
+ const filePath = this.fsManager.path(testPath, APP_TEST_CONFIGURATOR_FILE_NAME);
34
+ if (await this.fsManager.exists(filePath)) {
35
+ return;
36
+ }
37
+ const tpl = this.mapDeps(depsMapping, CONFIGURATOR_TS);
38
+ await this.fsManager.touch(filePath, tpl);
39
+ }
40
+ mapDeps(depsMapping, tpl) {
41
+ let res = tpl;
42
+ depsMapping?.forEach((to, from) => {
43
+ res = res.replaceAll(`from '${from}'`, `from '${to}'`);
44
+ });
45
+ return res;
46
+ }
34
47
  };
35
48
  VitestAppTestSuiteEmitter = __decorate([
36
49
  injectable(),
@@ -38,6 +51,10 @@ VitestAppTestSuiteEmitter = __decorate([
38
51
  __metadata("design:paramtypes", [Object])
39
52
  ], VitestAppTestSuiteEmitter);
40
53
  export { VitestAppTestSuiteEmitter };
54
+ const CONFIGURATOR_TS = `import { NodeAppTesterConfigurator } from 'libmodulor/node-test';
55
+
56
+ export class ${APP_TEST_CONFIGURATOR_NAME} extends NodeAppTesterConfigurator {}
57
+ `;
41
58
  // For now, we can have it here. When it becomes harder to maintain, we can introduce some kind of template engine.
42
59
  // Be aware that this will introduce complexities on building the lib.
43
60
  // We'll need to include these templates in the build and make them accessible via package.json "exports" or any other mechanism.
@@ -72,10 +89,10 @@ import {
72
89
  import { newNodeAppTester } from 'libmodulor/node-test';
73
90
  import { afterAll, afterEach, beforeAll, describe, expect, test } from 'vitest';
74
91
 
75
- import { Configurator } from './Configurator.js';
92
+ import { ${APP_TEST_CONFIGURATOR_NAME} } from './${APP_TEST_CONFIGURATOR_NAME}.js';
76
93
 
77
94
  const appPath = join(import.meta.dirname, '..');
78
- const configurator = new Configurator();
95
+ const configurator = new ${APP_TEST_CONFIGURATOR_NAME}();
79
96
  const runner = await newNodeAppTester(${serverPortRangeStart}, ${idx}, {
80
97
  appPath,
81
98
  configurator,
@@ -5,12 +5,12 @@ import { TARGET_DEFAULT_SERVER_MANAGER_SETTINGS } from '../../target/lib/server/
5
5
  import { NodeExpressServerManager } from '../../target/node-express-server/NodeExpressServerManager.js';
6
6
  import { FAKE_USER_ADMIN, FAKE_USER_REGULAR } from '../../uc/index.js';
7
7
  import { CONTAINER_OPTS } from '../../utils/index.js';
8
- import { bindCommon } from '../../utils/ioc/bindCommon.js';
8
+ import { bindCommon, updateSettings } from '../../utils/ioc/bindCommon.js';
9
9
  import { bindNodeCore } from '../../utils/ioc/bindNodeCore.js';
10
10
  import { bindServer } from '../../utils/ioc/bindServer.js';
11
11
  import { AppTester } from '../AppTester.js';
12
12
  import { optsAllSet } from '../opts.js';
13
- import { SimpleAppDocsEmitter } from './SimpleAppDocsEmitter.js';
13
+ import { SimpleAppDocsEmitter } from './SimpleAppDocsEmitter/SimpleAppDocsEmitter.js';
14
14
  import { TypeScriptLibUCDefASTParser } from './TypeScriptLibUCDefASTParser.js';
15
15
  export async function newNodeAppTester(serverPortRangeStart, idx, args) {
16
16
  const { configurator } = args;
@@ -18,8 +18,6 @@ export async function newNodeAppTester(serverPortRangeStart, idx, args) {
18
18
  const settings = {
19
19
  ...STD_DEFAULT_JWT_MANAGER_SETTINGS,
20
20
  ...TARGET_DEFAULT_SERVER_MANAGER_SETTINGS,
21
- jwt_manager_audience: 'libmodulor-test',
22
- jwt_manager_issuer: 'libmodulor-test',
23
21
  jwt_manager_secret: new TPassword().example(),
24
22
  logger_level,
25
23
  server_basic_auth_entries: {
@@ -31,7 +29,8 @@ export async function newNodeAppTester(serverPortRangeStart, idx, args) {
31
29
  server_stop_mode: 'aggressive',
32
30
  };
33
31
  const container = new Container(CONTAINER_OPTS);
34
- bindCommon(container, () => settings);
32
+ bindCommon(container);
33
+ updateSettings(container, settings);
35
34
  bindNodeCore(container);
36
35
  bindServer(container);
37
36
  container.bind('AppDocsEmitter').to(SimpleAppDocsEmitter);
@@ -43,7 +43,7 @@ export type AppTesterOpts = Partial<Pick<LoggerSettings, 'logger_level'>> & {
43
43
  */
44
44
  aliasPrefix?: AppTesterOptsAliasPrefix;
45
45
  /**
46
- * @defaultValue ['fik-sdk', 'inversify']
46
+ * @defaultValue ['libmodulor', 'inversify']
47
47
  */
48
48
  allowed?: AppTesterOptsImportsList;
49
49
  };
@@ -1,5 +1,6 @@
1
- import { TFile } from '../dt/index.js';
1
+ import { TFile, TFilePath } from '../dt/index.js';
2
2
  import { ucifIsMandatory, ucifMustBeFilledManually, ucifRepeatability, } from '../uc/index.js';
3
+ import { range } from '../utils/index.js';
3
4
  export const DEFAULT_UC_INPUT_FILLERS = [
4
5
  'ALL_WITH_EXAMPLES',
5
6
  'ONLY_MANDATORY_WITH_EXAMPLES',
@@ -39,7 +40,9 @@ function fillWithExample(f) {
39
40
  if (type instanceof TFile) {
40
41
  const example = type.getExamples()?.[0] ?? type.example();
41
42
  // TODO : Consider building a real file with real data (e.g. image, pdf, txt, etc.)
42
- const val = new File(['01010101010101010101010101010101'], example.path, {
43
+ // A fake file filled with 0s and 1s
44
+ const blob = range(TFilePath.FILE_SIZE).map((i) => (i % 2).toString());
45
+ const val = new File(blob, example.uri, {
43
46
  type: example.type,
44
47
  });
45
48
  const [isRepeatable] = ucifRepeatability(f.def);
@@ -1,38 +1,59 @@
1
+ import type { EnumOf } from '../utils/index.js';
1
2
  /**
2
3
  * Mode of execution of a use case
3
- *
4
- * Unlike all the other enums, the values are lowercased for compatibility reasons.
5
- * Indeed, this value is persisted in the database so we need to support all existing deployments.
6
4
  */
7
- export declare enum UCExecMode {
5
+ export declare const UCExecMode: {
8
6
  /**
9
7
  * The use case has been executed programmatically
10
8
  */
11
- AUTO = "auto",
9
+ readonly AUTO: "auto";
12
10
  /**
13
11
  * The use case has been executed explicitly by a user
14
12
  */
15
- USER = "user"
16
- }
13
+ readonly USER: "user";
14
+ };
15
+ export type UCExecMode = EnumOf<typeof UCExecMode>;
17
16
  /**
18
17
  * Result of execution of a use case
19
- *
20
- * - `aborted` : The user aborted the exec (e.g. by not confirming)
21
- * - `failed` : The exec failed
22
- * - `succeeded` : The exec succeeded
23
18
  */
24
- export type UCExecRes = 'aborted' | 'failed' | 'succeeded';
19
+ export declare const UCExecRes: {
20
+ /**
21
+ * The user aborted the exec (e.g. by not confirming)
22
+ */
23
+ readonly ABORTED: "aborted";
24
+ /**
25
+ * The execution failed
26
+ */
27
+ readonly FAILED: "failed";
28
+ /**
29
+ * The execution succeeded
30
+ */
31
+ readonly SUCCEEDED: "succeeded";
32
+ };
33
+ export type UCExecRes = EnumOf<typeof UCExecRes>;
25
34
  /**
26
35
  * State of execution of a use case
27
- *
28
- * - `changing` : An action triggered a change, fields should be disabled
29
- * - `idle` : It can be touched and filled by the user
30
- * - `initializing` : It's initializing in some way, fields should be disabled
31
- * - `submitting` : It's submitting, fields should be disabled and some indicator should show the processing
32
- *
33
36
  * It applies to a form, but it can be applied and generalized to any other interaction mechanism (i.e. cli, voice...).
34
37
  */
35
- export type UCExecState = 'changing' | 'idle' | 'initializing' | 'submitting';
38
+ export declare const UCExecState: {
39
+ /**
40
+ * An action triggered a change, fields should be disabled
41
+ */
42
+ readonly CHANGING: "changing";
43
+ /**
44
+ * It can be touched and filled by the user
45
+ */
46
+ readonly IDLE: "idle";
47
+ /**
48
+ * It's initializing in some way, fields should be disabled
49
+ */
50
+ readonly INITIALIZING: "initializing";
51
+ /**
52
+ * It's submitting, fields should be disabled and some indicator should show the processing
53
+ */
54
+ readonly SUBMITTING: "submitting";
55
+ };
56
+ export type UCExecState = EnumOf<typeof UCExecState>;
36
57
  /**
37
58
  * Check whether the execution corresponds to a "disabled" state
38
59
  *
@@ -45,8 +66,8 @@ export declare function ucIsDisabled(execState: UCExecState): boolean;
45
66
  /**
46
67
  * Check whether the execution corresponds to a "loading" state
47
68
  *
48
- * Typically, this is used to show a `loading` indicator. Thus, it's `true` when `execState === 'submitting'`.
49
- * Note that it's not for `changing` or `initializing` because these are not triggered by the user per sé.
69
+ * Typically, this is used to show a `loading` indicator. Thus, it's `true` when `execState === UCExecState.SUBMITTING`.
70
+ * Note that it's not for `UCExecState.CHANGING` or `UCExecState.INITIALIZING` because these are not triggered by the user per sé.
50
71
  *
51
72
  * @param execState
52
73
  * @returns
@@ -1,20 +1,55 @@
1
1
  /**
2
2
  * Mode of execution of a use case
3
- *
4
- * Unlike all the other enums, the values are lowercased for compatibility reasons.
5
- * Indeed, this value is persisted in the database so we need to support all existing deployments.
6
3
  */
7
- export var UCExecMode;
8
- (function (UCExecMode) {
4
+ export const UCExecMode = {
9
5
  /**
10
6
  * The use case has been executed programmatically
11
7
  */
12
- UCExecMode["AUTO"] = "auto";
8
+ AUTO: 'auto',
13
9
  /**
14
10
  * The use case has been executed explicitly by a user
15
11
  */
16
- UCExecMode["USER"] = "user";
17
- })(UCExecMode || (UCExecMode = {}));
12
+ USER: 'user',
13
+ };
14
+ /**
15
+ * Result of execution of a use case
16
+ */
17
+ export const UCExecRes = {
18
+ /**
19
+ * The user aborted the exec (e.g. by not confirming)
20
+ */
21
+ ABORTED: 'aborted',
22
+ /**
23
+ * The execution failed
24
+ */
25
+ FAILED: 'failed',
26
+ /**
27
+ * The execution succeeded
28
+ */
29
+ SUCCEEDED: 'succeeded',
30
+ };
31
+ /**
32
+ * State of execution of a use case
33
+ * It applies to a form, but it can be applied and generalized to any other interaction mechanism (i.e. cli, voice...).
34
+ */
35
+ export const UCExecState = {
36
+ /**
37
+ * An action triggered a change, fields should be disabled
38
+ */
39
+ CHANGING: 'changing',
40
+ /**
41
+ * It can be touched and filled by the user
42
+ */
43
+ IDLE: 'idle',
44
+ /**
45
+ * It's initializing in some way, fields should be disabled
46
+ */
47
+ INITIALIZING: 'initializing',
48
+ /**
49
+ * It's submitting, fields should be disabled and some indicator should show the processing
50
+ */
51
+ SUBMITTING: 'submitting',
52
+ };
18
53
  /**
19
54
  * Check whether the execution corresponds to a "disabled" state
20
55
  *
@@ -24,19 +59,19 @@ export var UCExecMode;
24
59
  * @returns
25
60
  */
26
61
  export function ucIsDisabled(execState) {
27
- return execState !== 'idle';
62
+ return execState !== UCExecState.IDLE;
28
63
  }
29
64
  /**
30
65
  * Check whether the execution corresponds to a "loading" state
31
66
  *
32
- * Typically, this is used to show a `loading` indicator. Thus, it's `true` when `execState === 'submitting'`.
33
- * Note that it's not for `changing` or `initializing` because these are not triggered by the user per sé.
67
+ * Typically, this is used to show a `loading` indicator. Thus, it's `true` when `execState === UCExecState.SUBMITTING`.
68
+ * Note that it's not for `UCExecState.CHANGING` or `UCExecState.INITIALIZING` because these are not triggered by the user per sé.
34
69
  *
35
70
  * @param execState
36
71
  * @returns
37
72
  */
38
73
  export function ucIsLoading(execState) {
39
- return execState === 'submitting';
74
+ return execState === UCExecState.SUBMITTING;
40
75
  }
41
76
  /**
42
77
  * Check whether the execution corresponds to an "error" result
@@ -45,5 +80,5 @@ export function ucIsLoading(execState) {
45
80
  * @returns
46
81
  */
47
82
  export function ucIsOnErr(execRes) {
48
- return execRes === 'failed';
83
+ return execRes === UCExecRes.FAILED;
49
84
  }
@@ -1,16 +1,18 @@
1
1
  import type { DataType, TBase, UIntQuantity } from '../dt/index.js';
2
+ import type { EnumOf } from '../utils/index.js';
2
3
  import type { UCFieldKey } from './def.js';
3
4
  import type { Value } from './value.js';
4
- export declare enum UCInputFieldFillingMode {
5
+ export declare const UCInputFieldFillingMode: {
5
6
  /**
6
7
  * Set programmatically on behalf of the user (e.g. a foreign key id for a given object)
7
8
  */
8
- AUTO_PRE = "AUTO_PRE",
9
+ readonly AUTO_PRE: "AUTO_PRE";
9
10
  /**
10
11
  * Set manually by the user (e.g. a form field, a cli flag, etc.)
11
12
  */
12
- MANUAL = "MANUAL"
13
- }
13
+ readonly MANUAL: "MANUAL";
14
+ };
15
+ export type UCInputFieldFillingMode = EnumOf<typeof UCInputFieldFillingMode>;
14
16
  export interface UCInputFieldDefCardinality {
15
17
  max?: UIntQuantity;
16
18
  min?: UIntQuantity;
@@ -1,14 +1,13 @@
1
- export var UCInputFieldFillingMode;
2
- (function (UCInputFieldFillingMode) {
1
+ export const UCInputFieldFillingMode = {
3
2
  /**
4
3
  * Set programmatically on behalf of the user (e.g. a foreign key id for a given object)
5
4
  */
6
- UCInputFieldFillingMode["AUTO_PRE"] = "AUTO_PRE";
5
+ AUTO_PRE: 'AUTO_PRE',
7
6
  /**
8
7
  * Set manually by the user (e.g. a form field, a cli flag, etc.)
9
8
  */
10
- UCInputFieldFillingMode["MANUAL"] = "MANUAL";
11
- })(UCInputFieldFillingMode || (UCInputFieldFillingMode = {}));
9
+ MANUAL: 'MANUAL',
10
+ };
12
11
  export function ucifExamples(def) {
13
12
  const { type } = def;
14
13
  const examples = type.getExamples();