libmodulor 0.3.0 → 0.5.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 (247) hide show
  1. package/CHANGELOG.md +29 -1
  2. package/README.md +7 -182
  3. package/dist/esm/app/workers/AppSrcFilePathBuilder.d.ts +16 -0
  4. package/dist/esm/app/workers/AppSrcFilePathBuilder.js +6 -4
  5. package/dist/esm/apps/Helper/index.js +1 -0
  6. package/dist/esm/apps/Helper/src/ucds/GenerateAppsTestsUCD.js +3 -2
  7. package/dist/esm/bundlers/vite/StripUCDLifecycleServerPlugin.js +3 -0
  8. package/dist/esm/convention.d.ts +1 -0
  9. package/dist/esm/convention.js +17 -4
  10. package/dist/esm/dt/Validation.d.ts +8 -0
  11. package/dist/esm/dt/Validation.js +8 -0
  12. package/dist/esm/dt/base/TBase.d.ts +2 -1
  13. package/dist/esm/dt/base/TBoolean.js +2 -0
  14. package/dist/esm/dt/base/TInt.js +3 -0
  15. package/dist/esm/dt/base/TNumber.js +2 -0
  16. package/dist/esm/dt/base/TObject.d.ts +15 -0
  17. package/dist/esm/dt/base/TObject.js +14 -0
  18. package/dist/esm/dt/base/TString.js +1 -1
  19. package/dist/esm/dt/final/TAmount.js +1 -0
  20. package/dist/esm/dt/final/TCountryISO3166Alpha2.js +1 -0
  21. package/dist/esm/dt/final/TCurrencyISO4217.js +1 -0
  22. package/dist/esm/dt/final/TDateTimeFormat.js +1 -0
  23. package/dist/esm/dt/final/TEmail.js +2 -0
  24. package/dist/esm/dt/final/TEmoji.js +4 -0
  25. package/dist/esm/dt/final/TFile.js +3 -0
  26. package/dist/esm/dt/final/THostAddress.js +2 -0
  27. package/dist/esm/dt/final/TIPv6.js +1 -0
  28. package/dist/esm/dt/final/TJWT.js +8 -0
  29. package/dist/esm/dt/final/TPercentage.js +5 -0
  30. package/dist/esm/dt/final/TSQLQuery.js +1 -0
  31. package/dist/esm/dt/final/TSSHPrivateKey.js +3 -1
  32. package/dist/esm/dt/final/TSemVerVersion.js +1 -0
  33. package/dist/esm/dt/final/TShellCommand.js +1 -0
  34. package/dist/esm/dt/final/TURL.js +2 -0
  35. package/dist/esm/dt/final/TUUID.js +1 -0
  36. package/dist/esm/dt/final/TYesNo.js +1 -1
  37. package/dist/esm/i18n/WordingManager.d.ts +16 -0
  38. package/dist/esm/i18n/types.d.ts +5 -0
  39. package/dist/esm/icon/Icon.d.ts +7 -0
  40. package/dist/esm/index.d.ts +3 -0
  41. package/dist/esm/index.js +4 -0
  42. package/dist/esm/index.react-native-pure.d.ts +10 -0
  43. package/dist/esm/index.react-native-pure.js +10 -0
  44. package/dist/esm/product/manifest.d.ts +15 -0
  45. package/dist/esm/products/Helper/index.js +3 -0
  46. package/dist/esm/products/Helper/manifest.d.ts +6 -1
  47. package/dist/esm/std/BufferManager.d.ts +18 -0
  48. package/dist/esm/std/ClockManager.d.ts +5 -0
  49. package/dist/esm/std/EnvironmentManager.d.ts +10 -0
  50. package/dist/esm/std/HTTPAPICaller.d.ts +6 -0
  51. package/dist/esm/std/I18nManager.d.ts +26 -0
  52. package/dist/esm/std/JWTManager.d.ts +26 -0
  53. package/dist/esm/std/JobManager.d.ts +6 -0
  54. package/dist/esm/std/LLMManager.d.ts +25 -0
  55. package/dist/esm/std/LLMManager.js +1 -0
  56. package/dist/esm/std/PromptManager.d.ts +8 -0
  57. package/dist/esm/std/SettingsManager.d.ts +19 -0
  58. package/dist/esm/std/SettingsManager.js +9 -0
  59. package/dist/esm/std/impl/ConsoleLogger.js +7 -1
  60. package/dist/esm/std/impl/FakeEmailManager.js +1 -0
  61. package/dist/esm/std/impl/FakeJobManager.js +1 -0
  62. package/dist/esm/std/impl/FetchHTTPAPICallExecutor.d.ts +9 -0
  63. package/dist/esm/std/impl/FetchHTTPAPICallExecutor.js +11 -0
  64. package/dist/esm/std/impl/MistralAILLMManager.d.ts +17 -0
  65. package/dist/esm/std/impl/MistralAILLMManager.js +56 -0
  66. package/dist/esm/std/impl/NodeCryptoManager.js +6 -1
  67. package/dist/esm/std/impl/NodeDeterministicCryptoManager.d.ts +14 -0
  68. package/dist/esm/std/impl/NodeDeterministicCryptoManager.js +17 -3
  69. package/dist/esm/std/impl/NodeFSManager.js +10 -0
  70. package/dist/esm/std/impl/NodeHTTPAPICallExecutorAgentBuilder.js +2 -0
  71. package/dist/esm/std/impl/NodePromptManager.js +3 -0
  72. package/dist/esm/std/impl/OllamaLLMManager.d.ts +20 -0
  73. package/dist/esm/std/impl/OllamaLLMManager.js +56 -0
  74. package/dist/esm/std/impl/OpenAILLMManager.d.ts +17 -0
  75. package/dist/esm/std/impl/OpenAILLMManager.js +51 -0
  76. package/dist/esm/std/impl/SimpleHTTPAPICaller.js +14 -0
  77. package/dist/esm/std/impl/SimpleMapI18nManager.js +4 -2
  78. package/dist/esm/std/impl/StdDateClockManager.js +3 -0
  79. package/dist/esm/std/impl/UCDataStoreExternalResourceManager.js +3 -0
  80. package/dist/esm/std/impl/WebCryptoManager.js +9 -0
  81. package/dist/esm/std/index.d.ts +1 -0
  82. package/dist/esm/std/index.js +1 -0
  83. package/dist/esm/target/lib/cli/renderer.js +3 -0
  84. package/dist/esm/target/lib/client/consts.d.ts +3 -0
  85. package/dist/esm/target/lib/client/consts.js +3 -0
  86. package/dist/esm/target/lib/mcp-server/MCPServerBooter.js +1 -0
  87. package/dist/esm/target/lib/react/UCContainer.js +1 -0
  88. package/dist/esm/target/lib/react/UCPanel.js +4 -0
  89. package/dist/esm/target/lib/react/entrypoint.d.ts +2 -0
  90. package/dist/esm/target/lib/react/useUC.d.ts +8 -0
  91. package/dist/esm/target/lib/react/useUC.js +22 -0
  92. package/dist/esm/target/lib/react/useUCOR.d.ts +15 -0
  93. package/dist/esm/target/lib/react/useUCOR.js +45 -0
  94. package/dist/esm/target/lib/rn/input.d.ts +15 -0
  95. package/dist/esm/target/lib/rn/input.js +28 -0
  96. package/dist/esm/target/lib/server/AuthenticationChecker.js +2 -1
  97. package/dist/esm/target/lib/server/BasicAuthenticationChecker.js +1 -0
  98. package/dist/esm/target/lib/server/CSPDirectivesBuilder.js +13 -0
  99. package/dist/esm/target/lib/server/CustomerFacingErrorBuilder.js +3 -0
  100. package/dist/esm/target/lib/server/PrivateApiKeyAuthenticationChecker.js +1 -0
  101. package/dist/esm/target/lib/server/PublicApiKeyChecker.js +1 -1
  102. package/dist/esm/target/lib/server/RequestChecker.js +5 -4
  103. package/dist/esm/target/lib/server/RequestHandler.d.ts +5 -0
  104. package/dist/esm/target/lib/server/RequestLogger.js +5 -0
  105. package/dist/esm/target/lib/server/ServerManager.d.ts +19 -0
  106. package/dist/esm/target/lib/server/consts.d.ts +3 -0
  107. package/dist/esm/target/lib/server/consts.js +3 -0
  108. package/dist/esm/target/lib/web/input.d.ts +21 -0
  109. package/dist/esm/target/lib/web/input.js +4 -0
  110. package/dist/esm/target/node-core-cli/NodeCoreCLIManager.js +2 -2
  111. package/dist/esm/target/node-express-server/NodeExpressServerManager.js +5 -0
  112. package/dist/esm/target/node-express-server/lib/AuthCookieCreator.js +1 -1
  113. package/dist/esm/target/node-express-server/middlewares/AuthenticationCheckerMiddlewareBuilder.js +1 -0
  114. package/dist/esm/target/node-express-server/middlewares/PublicApiKeyCheckerMiddlewareBuilder.js +1 -0
  115. package/dist/esm/target/node-express-server/middlewares/RequestCheckerMiddlewareBuilder.js +1 -0
  116. package/dist/esm/target/node-express-server/middlewares/RequestHandlerMiddlewareBuilder.js +8 -0
  117. package/dist/esm/target/node-express-server/middlewares/RequestLoggerMiddlewareBuilder.js +1 -0
  118. package/dist/esm/target/node-mcp-server/NodeLocalStdioMCPServerManager.d.ts +10 -0
  119. package/dist/esm/target/node-mcp-server/NodeLocalStdioMCPServerManager.js +14 -0
  120. package/dist/esm/target/react-native-pure/UCAutoExecLoader.d.ts +2 -0
  121. package/dist/esm/target/react-native-pure/UCAutoExecLoader.js +5 -0
  122. package/dist/esm/target/react-native-pure/UCEntrypointTouchable.d.ts +4 -0
  123. package/dist/esm/target/react-native-pure/UCEntrypointTouchable.js +6 -0
  124. package/dist/esm/target/react-native-pure/UCExecTouchable.d.ts +4 -0
  125. package/dist/esm/target/react-native-pure/UCExecTouchable.js +9 -0
  126. package/dist/esm/target/react-native-pure/UCForm.d.ts +4 -0
  127. package/dist/esm/target/react-native-pure/UCForm.js +13 -0
  128. package/dist/esm/target/react-native-pure/UCFormField.d.ts +11 -0
  129. package/dist/esm/target/react-native-pure/UCFormField.js +32 -0
  130. package/dist/esm/target/react-native-pure/UCFormFieldControl.d.ts +11 -0
  131. package/dist/esm/target/react-native-pure/UCFormFieldControl.js +37 -0
  132. package/dist/esm/target/react-native-pure/UCFormFieldDesc.d.ts +7 -0
  133. package/dist/esm/target/react-native-pure/UCFormFieldDesc.js +11 -0
  134. package/dist/esm/target/react-native-pure/UCFormFieldErr.d.ts +7 -0
  135. package/dist/esm/target/react-native-pure/UCFormFieldErr.js +5 -0
  136. package/dist/esm/target/react-native-pure/UCFormFieldLabel.d.ts +7 -0
  137. package/dist/esm/target/react-native-pure/UCFormFieldLabel.js +8 -0
  138. package/dist/esm/target/react-native-pure/UCFormSubmitControl.d.ts +9 -0
  139. package/dist/esm/target/react-native-pure/UCFormSubmitControl.js +8 -0
  140. package/dist/esm/target/react-web-pure/UCEntrypointTouchable.d.ts +1 -1
  141. package/dist/esm/target/react-web-pure/UCExecTouchable.d.ts +1 -1
  142. package/dist/esm/target/react-web-pure/UCExecTouchable.js +1 -1
  143. package/dist/esm/target/react-web-pure/UCFormFieldControl.d.ts +1 -1
  144. package/dist/esm/target/react-web-pure/UCFormFieldControl.js +3 -3
  145. package/dist/esm/testing/AppTester.d.ts +4 -0
  146. package/dist/esm/testing/AppTester.js +16 -0
  147. package/dist/esm/testing/AppTesterConfigurator.d.ts +68 -0
  148. package/dist/esm/testing/UCDataStoreTester.d.ts +9 -0
  149. package/dist/esm/testing/UCDataStoreTester.js +13 -0
  150. package/dist/esm/testing/impl/SimpleAppDocsEmitter.js +22 -2
  151. package/dist/esm/testing/impl/SimpleAppTesterConfigurator.js +1 -0
  152. package/dist/esm/testing/impl/SimpleHTMLAppTestReportEmitter.js +9 -3
  153. package/dist/esm/testing/impl/TypeScriptLibUCDefASTParser.js +12 -4
  154. package/dist/esm/testing/impl/VitestAppTestSuiteEmitter.js +6 -0
  155. package/dist/esm/testing/opts.d.ts +38 -0
  156. package/dist/esm/testing/opts.js +1 -1
  157. package/dist/esm/testing/uc-input.js +2 -0
  158. package/dist/esm/testing/workers/AppTesterCtxInitializer.js +7 -0
  159. package/dist/esm/testing/workers/UCExecutor.js +1 -0
  160. package/dist/esm/testing/workers/checkers/AppIndexChecker.js +1 -0
  161. package/dist/esm/testing/workers/checkers/UCDefSourcesChecker.js +4 -0
  162. package/dist/esm/uc/UC.js +19 -1
  163. package/dist/esm/uc/UCInputField.d.ts +28 -0
  164. package/dist/esm/uc/UCInputField.js +42 -0
  165. package/dist/esm/uc/data.d.ts +3 -0
  166. package/dist/esm/uc/def.d.ts +7 -0
  167. package/dist/esm/uc/exec.d.ts +39 -0
  168. package/dist/esm/uc/exec.js +29 -0
  169. package/dist/esm/uc/ext.d.ts +30 -1
  170. package/dist/esm/uc/helpers/UCOutputBuilder.js +5 -0
  171. package/dist/esm/uc/helpers/UCOutputReader.js +3 -1
  172. package/dist/esm/uc/impl/HTTPUCTransporter.js +4 -0
  173. package/dist/esm/uc/impl/InMemoryUCDataStore.js +7 -0
  174. package/dist/esm/uc/impl/KnexUCDataStore.d.ts +4 -0
  175. package/dist/esm/uc/impl/KnexUCDataStore.js +14 -0
  176. package/dist/esm/uc/impl/SimpleUCManager.js +6 -0
  177. package/dist/esm/uc/input-field.d.ts +60 -0
  178. package/dist/esm/uc/input-field.js +33 -0
  179. package/dist/esm/uc/input.d.ts +24 -0
  180. package/dist/esm/uc/lifecycle/client/IdleClientMain.js +1 -0
  181. package/dist/esm/uc/lifecycle/server/IdleServerMain.js +2 -0
  182. package/dist/esm/uc/manager.d.ts +11 -0
  183. package/dist/esm/uc/metadata.d.ts +10 -0
  184. package/dist/esm/uc/opi-layout.d.ts +3 -0
  185. package/dist/esm/uc/opi.d.ts +8 -0
  186. package/dist/esm/uc/output-field.d.ts +9 -0
  187. package/dist/esm/uc/output-part.d.ts +22 -0
  188. package/dist/esm/uc/output.d.ts +3 -0
  189. package/dist/esm/uc/policies/RoleRegularUCPolicy.js +1 -0
  190. package/dist/esm/uc/policies/funcs.js +1 -0
  191. package/dist/esm/uc/policy.d.ts +22 -0
  192. package/dist/esm/uc/sec.d.ts +9 -0
  193. package/dist/esm/uc/server.d.ts +10 -0
  194. package/dist/esm/uc/settings.d.ts +25 -0
  195. package/dist/esm/uc/side-effect.d.ts +16 -0
  196. package/dist/esm/uc/side-effect.js +16 -0
  197. package/dist/esm/uc/utils/rInput.d.ts +12 -0
  198. package/dist/esm/uc/utils/rInput.js +2 -0
  199. package/dist/esm/uc/utils/rVal.d.ts +25 -0
  200. package/dist/esm/uc/utils/rVal.js +27 -0
  201. package/dist/esm/uc/utils/recIs.d.ts +9 -0
  202. package/dist/esm/uc/utils/recIs.js +12 -1
  203. package/dist/esm/uc/utils/stripUCDLifecycleServer.d.ts +13 -0
  204. package/dist/esm/uc/utils/stripUCDLifecycleServer.js +17 -0
  205. package/dist/esm/uc/utils/ucifcoIsForArray.d.ts +6 -0
  206. package/dist/esm/uc/utils/ucifcoIsForArray.js +6 -0
  207. package/dist/esm/uc/workers/SimpleAggregateFinder.d.ts +12 -0
  208. package/dist/esm/uc/workers/SimpleAggregateFinder.js +12 -0
  209. package/dist/esm/uc/workers/UCBuilder.d.ts +7 -0
  210. package/dist/esm/uc/workers/UCBuilder.js +7 -0
  211. package/dist/esm/uc/workers/UCExecChecker.js +2 -0
  212. package/dist/esm/uc/workers/UCInputFilesProcessor.js +10 -4
  213. package/dist/esm/uc/workers/UCOutputFilesProcessor.js +6 -2
  214. package/dist/esm/utils/async/sleep.d.ts +10 -0
  215. package/dist/esm/utils/async/sleep.js +10 -0
  216. package/dist/esm/utils/http/appendData.js +5 -1
  217. package/dist/esm/utils/ioc/ContainerPrinter.js +2 -0
  218. package/dist/esm/utils/ioc/bindCommon.js +4 -0
  219. package/dist/esm/utils/ioc/bindNodeCLI.js +2 -0
  220. package/dist/esm/utils/ioc/bindNodeCore.js +1 -0
  221. package/dist/esm/utils/ioc/bindProduct.js +2 -0
  222. package/dist/esm/utils/ioc/bindRN.js +1 -0
  223. package/dist/esm/utils/ioc/bindServer.js +1 -0
  224. package/dist/esm/utils/ioc/bindWeb.js +2 -0
  225. package/dist/esm/utils/ioc/container.js +6 -0
  226. package/dist/esm/utils/numbers/units.js +3 -0
  227. package/dist/esm/utils/types/funcs.d.ts +35 -0
  228. package/dist/esm/utils/types/funcs.js +35 -0
  229. package/dist/esm/utils/types/utility-types.d.ts +17 -0
  230. package/dist/esm/utils/types/utility-types.js +1 -0
  231. package/package.json +16 -9
  232. package/docs/assets/trading-buy-asset-sequence-diagram.png +0 -0
  233. package/docs/assets/trading-target-mcp-server.png +0 -0
  234. package/docs/assets/trading-target-web-human.png +0 -0
  235. package/docs/assets/trading-target-web.png +0 -0
  236. package/docs/getting-started/001_Create_the_project.md +0 -168
  237. package/docs/getting-started/002_Create_the_App.md +0 -49
  238. package/docs/getting-started/003_Create_the_UseCase.md +0 -205
  239. package/docs/getting-started/004_Test_the_App.md +0 -114
  240. package/docs/getting-started/005_Create_the_Product.md +0 -46
  241. package/docs/getting-started/006_Create_the_server_Target.md +0 -130
  242. package/docs/getting-started/007_Create_the_web_Target.md +0 -262
  243. package/docs/getting-started/008_Switch_to_a_persistent_data_storage.md +0 -55
  244. package/docs/getting-started/009_Define_wording_for_humans.md +0 -42
  245. package/docs/getting-started/010_Create_the_cli_Target.md +0 -102
  246. package/docs/getting-started/011_Create_the_mcp_server_Target.md +0 -157
  247. package/docs/getting-started/012_Summary.md +0 -29
@@ -0,0 +1,4 @@
1
+ import { type ReactElement } from 'react';
2
+ import type { UCInput, UCOPIBase } from '../../uc/index.js';
3
+ import type { UCFormProps } from '../lib/react/form.js';
4
+ export declare function UCForm<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ disabled, execState, onChange, onSubmit, uc, }: UCFormProps<I, OPI0, OPI1>): ReactElement;
@@ -0,0 +1,13 @@
1
+ import React, {} from 'react';
2
+ import { View } from 'react-native';
3
+ import { UCFormField } from './UCFormField.js';
4
+ import { UCFormSubmitControl, } from './UCFormSubmitControl.js';
5
+ export function UCForm({ disabled, execState, onChange, onSubmit, uc, }) {
6
+ const onPress = async () => {
7
+ await onSubmit();
8
+ };
9
+ return (React.createElement(View, null,
10
+ uc.inputFieldsForForm().map((f) => (React.createElement(View, { key: f.key },
11
+ React.createElement(UCFormField, { disabled: disabled, execState: execState, field: f, onChange: onChange })))),
12
+ React.createElement(UCFormSubmitControl, { execState: execState, disabled: disabled, onPress: onPress, uc: uc })));
13
+ }
@@ -0,0 +1,11 @@
1
+ import { type ReactElement } from 'react';
2
+ import type { DataType } from '../../dt/index.js';
3
+ import { type Props as FormFieldControlProps } from './UCFormFieldControl.js';
4
+ import { type Props as FormFieldLabelProps } from './UCFormFieldLabel.js';
5
+ declare const ELEMENTS: readonly ["control", "desc", "err", "label"];
6
+ type Element = (typeof ELEMENTS)[number];
7
+ type Props<T extends DataType> = FormFieldControlProps<T> & FormFieldLabelProps<T> & {
8
+ only?: Element[];
9
+ };
10
+ export declare function UCFormField<T extends DataType>({ disabled, execState, field, onChange: onChangeBase, only, }: Props<T>): ReactElement;
11
+ export {};
@@ -0,0 +1,32 @@
1
+ import React, { useState } from 'react';
2
+ import { useDIContext } from '../lib/react/DIContextProvider.js';
3
+ import { UCFormFieldControl, } from './UCFormFieldControl.js';
4
+ import { UCFormFieldDesc } from './UCFormFieldDesc.js';
5
+ import { UCFormFieldErr } from './UCFormFieldErr.js';
6
+ import { UCFormFieldLabel, } from './UCFormFieldLabel.js';
7
+ const ELEMENTS = ['control', 'desc', 'err', 'label'];
8
+ export function UCFormField({ disabled, execState, field, onChange: onChangeBase, only, }) {
9
+ const { i18nManager } = useDIContext();
10
+ const { type } = field.def;
11
+ const [errMsg, setErrMsg] = useState(null);
12
+ const elements = only ?? ELEMENTS;
13
+ const onChange = (f, op, v) => {
14
+ setErrMsg(null);
15
+ const vArr = Array.isArray(v) ? v : [v];
16
+ for (const vv of vArr) {
17
+ const validation = type.assign(vv).validate();
18
+ const violation = validation.get();
19
+ if (violation) {
20
+ const [key, expected] = violation;
21
+ setErrMsg(i18nManager.t(key, { vars: { expected } }));
22
+ break;
23
+ }
24
+ }
25
+ onChangeBase(f, op, v);
26
+ };
27
+ return (React.createElement(React.Fragment, null,
28
+ elements.includes('label') && React.createElement(UCFormFieldLabel, { field: field }),
29
+ elements.includes('control') && (React.createElement(UCFormFieldControl, { disabled: disabled, execState: execState, field: field, onChange: onChange })),
30
+ elements.includes('err') && errMsg && (React.createElement(UCFormFieldErr, { errMsg: errMsg })),
31
+ elements.includes('desc') && React.createElement(UCFormFieldDesc, { field: field })));
32
+ }
@@ -0,0 +1,11 @@
1
+ import { type ReactElement } from 'react';
2
+ import type { DataType, ErrorMessage } from '../../dt/index.js';
3
+ import { type UCInputField } from '../../uc/index.js';
4
+ import type { UCFormFieldControlOnChange } from '../lib/react/form.js';
5
+ import type { UCPanelState } from '../lib/react/panel.js';
6
+ export type Props<T extends DataType> = UCPanelState & {
7
+ errMsg?: ErrorMessage | null;
8
+ field: UCInputField<T>;
9
+ onChange: UCFormFieldControlOnChange<T>;
10
+ };
11
+ export declare function UCFormFieldControl<T extends DataType>({ errMsg, execState, field, onChange: onChangeBase, }: Props<T>): ReactElement;
@@ -0,0 +1,37 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { TextInput } from 'react-native';
3
+ import { UCInputFieldChangeOperator, ucifRepeatability, } from '../../uc/index.js';
4
+ import { isBlank } from '../../utils/index.js';
5
+ import { rnInputDef } from '../lib/rn/input.js';
6
+ const MULTIPLE_VALUES_SEPARATOR = ',';
7
+ export function UCFormFieldControl({ errMsg = null, execState, field, onChange: onChangeBase, }) {
8
+ const [internalValue, setInternalValue] = useState(field.getValue());
9
+ // biome-ignore lint/correctness/useExhaustiveDependencies: false positive : It is actually necessary (only `field` does not trigger the effect)
10
+ useEffect(() => {
11
+ setInternalValue(field.getValue());
12
+ }, [field.getValue()]);
13
+ const attrs = rnInputDef(field, execState, errMsg);
14
+ const onChangeText = (value) => {
15
+ const [isRepeatable] = ucifRepeatability(field.def);
16
+ if (isRepeatable && typeof value === 'string') {
17
+ const valueArr = value
18
+ .split(MULTIPLE_VALUES_SEPARATOR)
19
+ .map((v) => v.trim());
20
+ onChangeBase(field, UCInputFieldChangeOperator.SET, valueArr);
21
+ }
22
+ else {
23
+ onChangeBase(field, UCInputFieldChangeOperator.SET, value);
24
+ }
25
+ setInternalValue(value);
26
+ };
27
+ let valueAsString = '';
28
+ if (!isBlank(internalValue)) {
29
+ if (Array.isArray(internalValue)) {
30
+ valueAsString = internalValue.join(MULTIPLE_VALUES_SEPARATOR);
31
+ }
32
+ else {
33
+ valueAsString = internalValue.toString();
34
+ }
35
+ }
36
+ return (React.createElement(TextInput, { ...attrs.spec, onChangeText: onChangeText, value: valueAsString }));
37
+ }
@@ -0,0 +1,7 @@
1
+ import { type ReactElement } from 'react';
2
+ import type { DataType } from '../../dt/index.js';
3
+ import type { UCInputField } from '../../uc/index.js';
4
+ export interface Props<T extends DataType> {
5
+ field: UCInputField<T>;
6
+ }
7
+ export declare function UCFormFieldDesc<T extends DataType>({ field, }: Props<T>): ReactElement | null;
@@ -0,0 +1,11 @@
1
+ import React, {} from 'react';
2
+ import { Text } from 'react-native';
3
+ import { useDIContext } from '../lib/react/DIContextProvider.js';
4
+ export function UCFormFieldDesc({ field, }) {
5
+ const { wordingManager } = useDIContext();
6
+ const { desc } = wordingManager.ucif(field);
7
+ if (!desc) {
8
+ return null;
9
+ }
10
+ return React.createElement(Text, null, desc);
11
+ }
@@ -0,0 +1,7 @@
1
+ import { type ReactElement } from 'react';
2
+ import type { ErrorMessage } from '../../dt/index.js';
3
+ interface Props {
4
+ errMsg: ErrorMessage;
5
+ }
6
+ export declare function UCFormFieldErr({ errMsg }: Props): ReactElement;
7
+ export {};
@@ -0,0 +1,5 @@
1
+ import React, {} from 'react';
2
+ import { Text } from 'react-native';
3
+ export function UCFormFieldErr({ errMsg }) {
4
+ return React.createElement(Text, null, errMsg);
5
+ }
@@ -0,0 +1,7 @@
1
+ import { type ReactElement } from 'react';
2
+ import type { DataType } from '../../dt/index.js';
3
+ import type { UCInputField } from '../../uc/index.js';
4
+ export interface Props<T extends DataType> {
5
+ field: UCInputField<T>;
6
+ }
7
+ export declare function UCFormFieldLabel<T extends DataType>({ field, }: Props<T>): ReactElement;
@@ -0,0 +1,8 @@
1
+ import React, {} from 'react';
2
+ import { Text } from 'react-native';
3
+ import { useDIContext } from '../lib/react/DIContextProvider.js';
4
+ export function UCFormFieldLabel({ field, }) {
5
+ const { wordingManager } = useDIContext();
6
+ const { label } = wordingManager.ucif(field);
7
+ return React.createElement(Text, null, label);
8
+ }
@@ -0,0 +1,9 @@
1
+ import { type ReactElement } from 'react';
2
+ import type { UCInput, UCOPIBase } from '../../uc/index.js';
3
+ import type { UCPanelCtx } from '../lib/react/panel.js';
4
+ export type UCFormSubmitOnPress = () => Promise<void>;
5
+ type Props<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = UCPanelCtx<I, OPI0, OPI1> & {
6
+ onPress?: UCFormSubmitOnPress;
7
+ };
8
+ export declare function UCFormSubmitControl<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ execState, disabled, onPress, uc }: Props<I, OPI0, OPI1>): ReactElement;
9
+ export {};
@@ -0,0 +1,8 @@
1
+ import React, {} from 'react';
2
+ import { Pressable, Text } from 'react-native';
3
+ import { useDIContext } from '../lib/react/DIContextProvider.js';
4
+ export function UCFormSubmitControl({ execState, disabled, onPress, uc }) {
5
+ const { wordingManager } = useDIContext();
6
+ return (React.createElement(Pressable, { onPress: onPress, disabled: disabled },
7
+ React.createElement(Text, null, wordingManager.ucISubmit(uc.def, execState))));
8
+ }
@@ -1,4 +1,4 @@
1
1
  import { type ReactElement } from 'react';
2
- import type { UCEntrypointTouchableProps } from '../../index.react.js';
3
2
  import type { UCInput, UCOPIBase } from '../../uc/index.js';
3
+ import type { UCEntrypointTouchableProps } from '../lib/react/touchable.js';
4
4
  export declare function UCEntrypointTouchable<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ path, wording }: UCEntrypointTouchableProps<I, OPI0, OPI1>): ReactElement;
@@ -1,4 +1,4 @@
1
1
  import { type ReactElement } from 'react';
2
- import { type UCExecTouchableProps } from '../../index.react.js';
3
2
  import type { UCInput, UCOPIBase } from '../../uc/index.js';
3
+ import type { UCExecTouchableProps } from '../lib/react/touchable.js';
4
4
  export declare function UCExecTouchable<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ disabled, execState, onSubmit, uc, }: UCExecTouchableProps<I, OPI0, OPI1>): ReactElement;
@@ -1,5 +1,5 @@
1
1
  import React, {} from 'react';
2
- import { useDIContext } from '../../index.react.js';
2
+ import { useDIContext } from '../lib/react/DIContextProvider.js';
3
3
  export function UCExecTouchable({ disabled, execState, onSubmit, uc, }) {
4
4
  const { wordingManager } = useDIContext();
5
5
  const label = wordingManager.ucISubmit(uc.def, execState);
@@ -8,4 +8,4 @@ export type Props<T extends DataType> = UCPanelState & {
8
8
  field: UCInputField<T>;
9
9
  onChange: UCFormFieldControlOnChange<T>;
10
10
  };
11
- export declare function UCFormFieldControl<T extends DataType>({ disabled, errMsg, execState, field, onChange: onChangeBase, }: Props<T>): ReactElement;
11
+ export declare function UCFormFieldControl<T extends DataType>({ errMsg, execState, field, onChange: onChangeBase, }: Props<T>): ReactElement;
@@ -4,7 +4,7 @@ import { htmlInputDef } from '../lib/web/input.js';
4
4
  const CHECKED_FIELD_TYPES = ['checkbox', 'radio'];
5
5
  const FILE_FIELD_TYPES = ['file'];
6
6
  const MULTIPLE_VALUES_SEPARATOR = ',';
7
- export function UCFormFieldControl({ disabled, errMsg = null, execState, field, onChange: onChangeBase, }) {
7
+ export function UCFormFieldControl({ errMsg = null, execState, field, onChange: onChangeBase, }) {
8
8
  const attrs = htmlInputDef(field, execState, errMsg);
9
9
  const onChange = (e) => {
10
10
  const target = e.currentTarget;
@@ -28,7 +28,7 @@ export function UCFormFieldControl({ disabled, errMsg = null, execState, field,
28
28
  }
29
29
  };
30
30
  if (attrs.internal?.multiline) {
31
- return (React.createElement("textarea", { ...attrs.spec, disabled: disabled, onChange: onChange }));
31
+ return React.createElement("textarea", { ...attrs.spec, onChange: onChange });
32
32
  }
33
- return React.createElement("input", { ...attrs.spec, disabled: disabled, onChange: onChange });
33
+ return React.createElement("input", { ...attrs.spec, onChange: onChange });
34
34
  }
@@ -43,6 +43,10 @@ export declare class AppTester {
43
43
  private ucExecutor;
44
44
  private configurator;
45
45
  private ctx;
46
+ /**
47
+ * We use a "safe" one to avoid any "infinite loop" while trying to import/resolve a file.
48
+ * This can happen in case of circular dependencies for example.
49
+ */
46
50
  private safeSrcImporter;
47
51
  private testResults;
48
52
  private testSummary;
@@ -14,6 +14,8 @@ import { inject, injectable } from 'inversify';
14
14
  import { I18nEN } from '../i18n/locales/en.js';
15
15
  import { I18nFR } from '../i18n/locales/fr.js';
16
16
  import { FAKE_USER_ADMIN, UCBuilder, UCInputFieldChangeOperator, ucHTTPContract, } from '../uc/index.js';
17
+ // We inject directly the implementation because we'll generate all the reports and not only the one that is bound to the interface.
18
+ // We can plan a setting à la Vitest where we specify the types of reports to generate though.
17
19
  import { SimpleHTMLAppTestReportEmitter } from './impl/SimpleHTMLAppTestReportEmitter.js';
18
20
  import { optsAllSet } from './opts.js';
19
21
  import { defaultUCAuthSetters } from './uc-auth.js';
@@ -40,7 +42,12 @@ let AppTester = class AppTester {
40
42
  ucExecutor;
41
43
  configurator;
42
44
  ctx;
45
+ /**
46
+ * We use a "safe" one to avoid any "infinite loop" while trying to import/resolve a file.
47
+ * This can happen in case of circular dependencies for example.
48
+ */
43
49
  safeSrcImporter;
50
+ // biome-ignore lint/suspicious/noExplicitAny: can be anything
44
51
  testResults;
45
52
  testSummary;
46
53
  ucDefSourcesCheckerOutput;
@@ -134,7 +141,9 @@ let AppTester = class AppTester {
134
141
  const inputFiller = (uc) => {
135
142
  uc.fill(input);
136
143
  };
144
+ // biome-ignore lint/suspicious/noExplicitAny: can be anything
137
145
  const { out } = await this.execUC({
146
+ // TODO : Pass the appropriate one so we test the real flow and not the auth
138
147
  auth: FAKE_USER_ADMIN,
139
148
  authName: 'ADMIN',
140
149
  inputFiller,
@@ -148,6 +157,7 @@ let AppTester = class AppTester {
148
157
  ...input,
149
158
  appManifest: this.ctx.appManifest,
150
159
  });
160
+ // TODO : Add errors mapping to configurator so the developer can override this default behavior
151
161
  let status = 'warning';
152
162
  if (!out.err) {
153
163
  status = 'success';
@@ -169,6 +179,9 @@ let AppTester = class AppTester {
169
179
  let sideEffects = await this.configurator.sideEffects(this.ctx);
170
180
  if (flow) {
171
181
  name = `${flow.name} > ${name}`;
182
+ // For regular uc tests, side effects are cleared between each execution
183
+ // But it's not the case for a flow, thus each flow uc test shares the same side effects ref
184
+ // To have the side effects at each stage, we take a snapshot (to be improved as this is not performant at all)
172
185
  if (sideEffects) {
173
186
  const snapshot = JSON.parse(JSON.stringify(Array.from(sideEffects.entries())));
174
187
  sideEffects = new Map(snapshot);
@@ -205,6 +218,7 @@ let AppTester = class AppTester {
205
218
  async init({ appPath, configurator, serverClientSettings, srcImporter, }) {
206
219
  this.configurator = configurator;
207
220
  this.safeSrcImporter = (path) => Promise.race([
221
+ // We can cast because it fails or looses the race.
208
222
  awaitForSrcImport(path),
209
223
  srcImporter(path),
210
224
  ]);
@@ -222,6 +236,7 @@ let AppTester = class AppTester {
222
236
  await this.initServer();
223
237
  }
224
238
  async ucTestData(ucdRef) {
239
+ // Auth setters
225
240
  const defaultASs = defaultUCAuthSetters();
226
241
  let asEntries = Object.entries(defaultASs);
227
242
  const asConfig = await this.configurator.authSettersConfig();
@@ -236,6 +251,7 @@ let AppTester = class AppTester {
236
251
  asEntries.push(...Object.entries(add));
237
252
  }
238
253
  }
254
+ // Input fillers
239
255
  const defaultIFs = defaultUCInputFillers();
240
256
  const ifEntries = Object.entries(defaultIFs);
241
257
  const specificIFs = await this.configurator.inputFillers();
@@ -6,21 +6,89 @@ import type { DefaultUCAuthSetter, UCAuthSetterSet } from './uc-auth.js';
6
6
  import type { CustomUCInputFiller, UCInputFillerSet } from './uc-input.js';
7
7
  import type { UCExecutorAssertion } from './workers/UCExecutor.js';
8
8
  export type AppTesterConfiguratorAuthSettersConfig = {
9
+ /**
10
+ * Specific auth setters to add to the default ones
11
+ */
9
12
  add?: UCAuthSetterSet;
13
+ /**
14
+ * Default auth setters to exclude
15
+ *
16
+ * For instance, if your app does not care about auth (e.g. only client side app), you can safely exclude everything except {@link ANONYMOUS}
17
+ */
10
18
  exclude?: Set<DefaultUCAuthSetter>;
11
19
  };
12
20
  export type AppTesterConfiguratorInputFillers<I extends UCInput = any, OPI0 extends UCOPIBase = any, OPI1 extends UCOPIBase = any> = Map<UCName, UCInputFillerSet<CustomUCInputFiller, I, OPI0, OPI1>>;
13
21
  export type AppTesterConfiguratorSideEffects = Map<string, any>;
14
22
  export type AppTesterConfiguratorSideEffectsSerialized = [string, any][];
15
23
  export type AppTesterConfiguratorSpecificAssertions<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = Map<CryptoManagerHash, UCExecutorAssertion<I, OPI0, OPI1>>;
24
+ /**
25
+ * Configure the tester for a specific app
26
+ *
27
+ * @defaultValue See {@link SimpleAppTesterConfigurator}
28
+ */
16
29
  export interface AppTesterConfigurator {
30
+ /**
31
+ * Auth setters config to add some or exclude default ones
32
+ */
17
33
  authSettersConfig(): Promise<AppTesterConfiguratorAuthSettersConfig | undefined>;
34
+ /**
35
+ * Override the implementations needed by the use cases, in `ctx.container`
36
+ *
37
+ * @param ctx
38
+ */
18
39
  bindImplementations(ctx: AppTesterCtx): Promise<void>;
40
+ /**
41
+ * Clear what needs to be cleared after a use case execution
42
+ *
43
+ * For instance, this includes the data store, some fake queue processor checked in side effects, etc.
44
+ *
45
+ * @param ctx
46
+ */
19
47
  clearExecution(ctx: AppTesterCtx): Promise<void>;
48
+ /**
49
+ * Define specific flows to test multiple use cases sequentially
50
+ *
51
+ * For example : SignUp > SignIn > SignOut > ResetPassword, etc.
52
+ */
20
53
  flows(): Promise<AppTesterFlow[]>;
54
+ /**
55
+ * Define specific input fillers, per use case, in addition to the default ones
56
+ *
57
+ * @see defaultInputFillers
58
+ */
21
59
  inputFillers(): Promise<AppTesterConfiguratorInputFillers | undefined>;
60
+ /**
61
+ * Override the `ctx.opts()`, in case the app has some specificities
62
+ */
22
63
  opts(): Promise<AppTesterCtx['opts']>;
64
+ /**
65
+ * Seed some data in any data store needed by the use cases
66
+ *
67
+ * @param ctx
68
+ */
23
69
  seed(ctx: AppTesterCtx): Promise<void>;
70
+ /**
71
+ * Register the side effects that need to be tracked
72
+ *
73
+ * For instance, this is where you register {@link FakeEmailManager.entries} to check the emails sent by use cases.
74
+ *
75
+ * Or it can also be the entries of some fake job processor to check the jobs dispatched by use cases.
76
+ *
77
+ * Note that it works only if there are no `specificAssertions` for the given use case.
78
+ *
79
+ * Otherwise, you need to assert side effects manually.
80
+ *
81
+ * @param ctx
82
+ */
24
83
  sideEffects(ctx: AppTesterCtx): Promise<AppTesterConfiguratorSideEffects | undefined>;
84
+ /**
85
+ * Define specific assertions for a specific use case
86
+ *
87
+ * Otherwise, it matches the snapshot.
88
+ *
89
+ * For instance, you can use this if a specific use case performs some random processing (e.g. generating random data).
90
+ *
91
+ * Generally speaking, it's always better to have deterministic tests, so it's usually better to bind deterministic implementations in the tests.
92
+ */
25
93
  specificAssertions(): Promise<AppTesterConfiguratorSpecificAssertions | undefined>;
26
94
  }
@@ -3,6 +3,15 @@ import { type UCDataStore } from '../uc/index.js';
3
3
  interface Input {
4
4
  ucDataStore: UCDataStore;
5
5
  }
6
+ /**
7
+ * Test that a {@link UCDataStore} conforms to the spec
8
+ *
9
+ * By default it runs tests on the projection mechanism.
10
+ * Therefore, you need to create one in your implementation when creating your test suite.
11
+ * See `src/uc/impl/KnexUCDataStore.test.ts` for an example.
12
+ *
13
+ * Otherwise you can just `skipProjectionTesting`, although it's not recommended.
14
+ */
6
15
  export declare class UCDataStoreTester implements Worker<Input, Promise<void>> {
7
16
  private clockManager;
8
17
  private cryptoManager;
@@ -18,6 +18,15 @@ import { UCExecMode, } from '../uc/index.js';
18
18
  const ERR_SHOULD_NOT_EXIST_AFTER_DESTROY = 'It should not exist after destroy';
19
19
  const ERR_SHOULD_EXIST_AFTER_INSTALL = 'It should exist after install';
20
20
  const ERR_SHOULD_RETURN_X_RECORDS = (n) => `It should return ${n} record(s)`;
21
+ /**
22
+ * Test that a {@link UCDataStore} conforms to the spec
23
+ *
24
+ * By default it runs tests on the projection mechanism.
25
+ * Therefore, you need to create one in your implementation when creating your test suite.
26
+ * See `src/uc/impl/KnexUCDataStore.test.ts` for an example.
27
+ *
28
+ * Otherwise you can just `skipProjectionTesting`, although it's not recommended.
29
+ */
21
30
  let UCDataStoreTester = class UCDataStoreTester {
22
31
  static { UCDataStoreTester_1 = this; }
23
32
  clockManager;
@@ -60,6 +69,7 @@ let UCDataStoreTester = class UCDataStoreTester {
60
69
  await ucDataStore.clear();
61
70
  this.readRes = await ucDataStore.read();
62
71
  this.expectXRecords(0);
72
+ // Write a last one in case need to watch data in the DB
63
73
  await this.ucDataStore.write({
64
74
  aggregateId: this.cryptoManager.randomUUID(),
65
75
  appName: APP_NAME_PLACEHOLDER,
@@ -116,9 +126,12 @@ let UCDataStoreTester = class UCDataStoreTester {
116
126
  ];
117
127
  }
118
128
  buildFiltersTestData() {
129
+ // biome-ignore lint/style/noNonNullAssertion: we're in a test
119
130
  const entry = this.entries[0];
120
131
  const [aggregateId, appName, ucNames, organizationId, userId] = entry;
132
+ // biome-ignore lint/style/noNonNullAssertion: we're in a test
121
133
  const name = ucNames[0];
134
+ // TODO : Enhance these with a combination of filters
122
135
  return [
123
136
  [{ aggregateId }, 2],
124
137
  [{ aggregateId: [aggregateId] }, 2],
@@ -33,6 +33,13 @@ SimpleAppDocsEmitter = __decorate([
33
33
  __metadata("design:paramtypes", [Object])
34
34
  ], SimpleAppDocsEmitter);
35
35
  export { SimpleAppDocsEmitter };
36
+ // For now, we can have it here. When it becomes harder to maintain, we can introduce some kind of template engine.
37
+ // Be aware that this will introduce complexities on building the lib.
38
+ // We'll need to include these templates in the build and make them accessible via package.json "exports" or any other mechanism.
39
+ // Hence the choice to keep it simple for now.
40
+ // Defined it as function in case we need to pass args.
41
+ // Using --- for the comment to make it compatible with pandoc
42
+ // See https://stackoverflow.com/a/4829998/1259118
36
43
  const template = (cols, items) => `<!---
37
44
  All this code has been auto generated.
38
45
  DO NOT EDIT.
@@ -55,6 +62,9 @@ ${diagram(item)}`)
55
62
  |---|${cols.map((_c) => '---').join('|')}|
56
63
  ${items.map((item, idx) => ['', idx + 1, ...cols.map((c) => fmtTechSummaryField(item[c])), ''].join('|')).join('\n')}
57
64
  `;
65
+ /*
66
+ * Diagram
67
+ */
58
68
  const CHECK_POLICY = '🔐 Check policy';
59
69
  const CHECK_POLICY_COND = 'when any validation fails';
60
70
  const CHECK_POLICY_COND_ACTION = 'show failure';
@@ -69,6 +79,8 @@ const SEND = '📤 Send';
69
79
  const SUBMIT = '↩️ Submit';
70
80
  const TRIGGER = '⤴️ Trigger';
71
81
  function diagram(item) {
82
+ // Debugger : https://mermaid.live/edit
83
+ // Messages : https://mermaid.js.org/syntax/sequenceDiagram.html#messages
72
84
  const client = 'Client';
73
85
  const server = 'Server';
74
86
  const user = 'User';
@@ -76,6 +88,8 @@ function diagram(item) {
76
88
  const { ioIFields, ioOPI0Fields, ioOPI1Fields, lifecycleClientPolicy, lifecycleClientSteps, lifecycleServerPolicy, lifecycleServerSteps, metadataSensitive, } = item;
77
89
  let req = TRIGGER;
78
90
  if (ioIFields && ioIFields.length > 0) {
91
+ // TODO : Include only fields to fill manually
92
+ // Not sure though, as for CLI for example (i.e. noContext), one needs to provide all of them
79
93
  req = `${FILL}${LB}${diagramUCFields(item.ioIFields)}`;
80
94
  }
81
95
  lines.push(`${user}->>+${client}: ${req}`);
@@ -89,6 +103,7 @@ function diagram(item) {
89
103
  if (lifecycleClientSteps) {
90
104
  lines.push(...diagramUCMainSteps(client, lifecycleClientSteps));
91
105
  }
106
+ // This is an approximation. Might need to improve it.
92
107
  const hasServer = item.lifecycleServerPolicy?.value;
93
108
  if (hasServer) {
94
109
  req = SEND;
@@ -142,11 +157,16 @@ function diagramUCPolicy(participant, caller, lifecyclePolicyField) {
142
157
  'end',
143
158
  ];
144
159
  }
160
+ /*
161
+ * Technical Summary
162
+ */
145
163
  function fmtTechSummaryField(field) {
146
164
  if (!field) {
147
165
  return '';
148
166
  }
149
167
  const values = Array.isArray(field) ? field : [field];
168
+ // NOTE : <br> won't work for every markdown renderer.
169
+ // See https://stackoverflow.com/questions/11700487/how-do-i-add-a-newline-in-a-markdown-table
150
170
  return values.map(fmtTechSummaryFieldVal).join('<br>');
151
171
  }
152
172
  function fmtTechSummaryFieldVal(field) {
@@ -155,7 +175,7 @@ function fmtTechSummaryFieldVal(field) {
155
175
  if (err) {
156
176
  res += `❌ ${err}`;
157
177
  }
158
- res = res.replace(/[\u00A0-\u9999<>\&]/g, (i) => `&#${i.charCodeAt(0)};`);
159
- res = res.replaceAll('|', '\\|');
178
+ res = res.replace(/[\u00A0-\u9999<>\&]/g, (i) => `&#${i.charCodeAt(0)};`); // TS generics considered as HTML
179
+ res = res.replaceAll('|', '\\|'); // TS intersection vs Markdown table column
160
180
  return res;
161
181
  }
@@ -24,6 +24,7 @@ export class SimpleAppTesterConfigurator {
24
24
  return undefined;
25
25
  }
26
26
  async seed(_ctx) {
27
+ // Nothing to do
27
28
  }
28
29
  async sideEffects(_ctx) {
29
30
  return undefined;
@@ -19,6 +19,7 @@ let SimpleHTMLAppTestReportEmitter = class SimpleHTMLAppTestReportEmitter {
19
19
  }
20
20
  async exec({ appPath, testResults, testSummary, }) {
21
21
  const reportPath = this.reportPath(appPath);
22
+ // Since we're using 'recursive: true', there will be no error if the directory already exists
22
23
  await this.fsManager.mkdir(reportPath, { recursive: true });
23
24
  const tpl = template(appPath, testResults, testSummary);
24
25
  const outPath = await this.entrypointPath(appPath);
@@ -43,6 +44,11 @@ SimpleHTMLAppTestReportEmitter = __decorate([
43
44
  __metadata("design:paramtypes", [Object])
44
45
  ], SimpleHTMLAppTestReportEmitter);
45
46
  export { SimpleHTMLAppTestReportEmitter };
47
+ // For now, we can have it here. When it becomes harder to maintain, we can introduce some kind of template engine.
48
+ // Be aware that this will introduce complexities on building the lib.
49
+ // We'll need to include these templates in the build and make them accessible via package.json "exports" or any other mechanism.
50
+ // Hence the choice to keep it simple for now.
51
+ // Defined it as function in case we need to pass args.
46
52
  const template = (appPath, testResults, testSummary) => `<!DOCTYPE html>
47
53
  <html lang="en">
48
54
  <head>
@@ -142,9 +148,9 @@ const template = (appPath, testResults, testSummary) => `<!DOCTYPE html>
142
148
  </html>
143
149
  `;
144
150
  const STATUS_COLOR_MAPPING = {
145
- danger: '#ff4136',
146
- success: '#42e6a4',
147
- warning: '#ffff00',
151
+ danger: '#ff4136', // red
152
+ success: '#42e6a4', // green
153
+ warning: '#ffff00', // yellow
148
154
  };
149
155
  function statusStyles() {
150
156
  return Object.entries(STATUS_COLOR_MAPPING)
@@ -12,6 +12,9 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
12
  };
13
13
  import { inject, injectable } from 'inversify';
14
14
  import { isClassDeclaration, isObjectLiteralExpression, isPropertyAssignment, } from 'typescript';
15
+ // To avoid the following error when used in a consumer :
16
+ // SyntaxError: Named export 'ModuleKind' not found. The requested module 'typescript' is a CommonJS module, which may not support all module.exports as named exports.
17
+ // CommonJS modules can always be imported via the default export
15
18
  import typescript from 'typescript';
16
19
  const { ModuleKind, ModuleResolutionKind, ScriptTarget, createProgram, flattenDiagnosticMessageText, forEachChild, getPreEmitDiagnostics, isIdentifier, isImportDeclaration, isPropertySignature, isStringLiteral, isTypeReferenceNode, isVariableStatement, } = typescript;
17
20
  import { UC_MAIN_CLIENT_SUFFIX, UC_MAIN_SERVER_SUFFIX, UC_MAIN_STEP_PREFIX_REGULAR, UC_MAIN_SUFFIX, UC_POLICY_SUFFIX, } from '../../convention.js';
@@ -89,8 +92,10 @@ let TypeScriptLibUCDefASTParser = class TypeScriptLibUCDefASTParser {
89
92
  target: ScriptTarget[(compilerOptionsBase.target ??
90
93
  target)],
91
94
  };
92
- this.compilerOptions.jsx = undefined;
93
- this.compilerOptions.lib = undefined;
95
+ // @ts-ignore
96
+ this.compilerOptions.jsx = undefined; // Otherwise it triggers the following error since TS 5.5 : jsx is a string value; tsconfig JSON must be parsed with parseJsonSourceFileConfigFileContent or getParsedCommandLineOfConfigFile before passing to createProgram
97
+ // @ts-ignore
98
+ this.compilerOptions.lib = undefined; // Otherwise it triggers errors saying it does not find them
94
99
  }
95
100
  getTypeFields(node) {
96
101
  const type = this.typeChecker.getTypeAtLocation(node);
@@ -114,9 +119,12 @@ let TypeScriptLibUCDefASTParser = class TypeScriptLibUCDefASTParser {
114
119
  return fields;
115
120
  }
116
121
  processConstDeclaration(node, onMainStep, onPolicy, onMetadata) {
122
+ // TODO : Improve this whole pattern by making it more robust
123
+ // I think there is a risk of it to break in some cases (e.g. if there are other properties named main, policy, etc.)
117
124
  const metadataPropertyName = 'metadata';
118
125
  const nodes = [];
119
126
  const populateNodes = (node1) => {
127
+ // "main: SendClientMain" => "main", ":", "SendClientMain" => 3
120
128
  if (isPropertyAssignment(node1) && node1.getChildCount() === 3) {
121
129
  const propertyName = node1.getChildAt(0).getText();
122
130
  if (propertyName === UC_MAIN_SUFFIX.toLocaleLowerCase() ||
@@ -137,7 +145,7 @@ let TypeScriptLibUCDefASTParser = class TypeScriptLibUCDefASTParser {
137
145
  this.processLifecycleMain('server', node1, onMainStep);
138
146
  }
139
147
  else if (text.endsWith(UC_POLICY_SUFFIX)) {
140
- const parent = node1.parent.getText();
148
+ const parent = node1.parent.getText(); // { main: X(Client|Server)Main, policy: XUCPolicy }
141
149
  if (parent.includes(UC_MAIN_CLIENT_SUFFIX)) {
142
150
  this.processLifecyclePolicy('client', node1, onPolicy);
143
151
  }
@@ -211,7 +219,7 @@ let TypeScriptLibUCDefASTParser = class TypeScriptLibUCDefASTParser {
211
219
  value = Boolean(value);
212
220
  }
213
221
  else {
214
- value = value.substring(1, v.length - 1);
222
+ value = value.substring(1, v.length - 1); // To remove the single quotes
215
223
  }
216
224
  metadataLike[k] = value;
217
225
  }