libmodulor 0.23.0 → 0.25.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 (132) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +154 -2
  3. package/dist/esm/apps/Helper/src/lib/project.js +6 -6
  4. package/dist/esm/apps/Helper/src/ucds/TestAppUCD.d.ts +2 -1
  5. package/dist/esm/apps/Helper/src/ucds/TestAppUCD.js +8 -0
  6. package/dist/esm/convention.d.ts +3 -0
  7. package/dist/esm/convention.js +3 -0
  8. package/dist/esm/dt/DataTypes.d.ts +1 -2
  9. package/dist/esm/dt/Validation.d.ts +2 -2
  10. package/dist/esm/dt/base/TBase.d.ts +2 -0
  11. package/dist/esm/dt/base/TBase.js +3 -0
  12. package/dist/esm/dt/base/TObject.d.ts +6 -4
  13. package/dist/esm/dt/base/TObject.js +5 -6
  14. package/dist/esm/dt/base/TString.d.ts +2 -1
  15. package/dist/esm/dt/base/TString.js +22 -0
  16. package/dist/esm/dt/final/TFile.d.ts +13 -4
  17. package/dist/esm/dt/final/TFile.js +70 -8
  18. package/dist/esm/dt/final/TFileExtension.d.ts +1 -1
  19. package/dist/esm/dt/final/TFileMimeType.d.ts +2 -6
  20. package/dist/esm/dt/final/TFileMimeType.js +0 -6
  21. package/dist/esm/dt/final/TFilePath.d.ts +7 -0
  22. package/dist/esm/dt/final/TFilePath.js +5 -1
  23. package/dist/esm/dt/index.d.ts +1 -1
  24. package/dist/esm/i18n/WordingManager.d.ts +2 -1
  25. package/dist/esm/i18n/WordingManager.js +23 -2
  26. package/dist/esm/i18n/index.d.ts +1 -1
  27. package/dist/esm/i18n/locales/de.d.ts +2 -0
  28. package/dist/esm/i18n/locales/de.js +62 -0
  29. package/dist/esm/i18n/locales/en.js +8 -0
  30. package/dist/esm/i18n/locales/es.d.ts +2 -0
  31. package/dist/esm/i18n/locales/es.js +62 -0
  32. package/dist/esm/i18n/locales/fr.js +8 -0
  33. package/dist/esm/i18n/types.d.ts +5 -4
  34. package/dist/esm/index.babel.d.ts +1 -0
  35. package/dist/esm/index.babel.js +1 -0
  36. package/dist/esm/index.node-stricli-cli.d.ts +2 -0
  37. package/dist/esm/index.node-stricli-cli.js +2 -0
  38. package/dist/esm/index.vite.d.ts +1 -1
  39. package/dist/esm/index.vite.js +1 -1
  40. package/dist/esm/index.webpack.d.ts +1 -0
  41. package/dist/esm/index.webpack.js +1 -0
  42. package/dist/esm/std/FSManager.d.ts +7 -5
  43. package/dist/esm/std/FSManager.js +5 -6
  44. package/dist/esm/std/FormDataBuilder.d.ts +2 -1
  45. package/dist/esm/std/I18nManager.d.ts +12 -0
  46. package/dist/esm/std/impl/NodeFSManager.js +4 -3
  47. package/dist/esm/std/impl/SimpleMapI18nManager.d.ts +6 -1
  48. package/dist/esm/std/impl/SimpleMapI18nManager.js +41 -12
  49. package/dist/esm/target/lib/react/StyleContextProvider.d.ts +1 -0
  50. package/dist/esm/target/lib/react/form.d.ts +1 -1
  51. package/dist/esm/target/lib/react/form.js +1 -0
  52. package/dist/esm/target/lib/react/useAction.d.ts +1 -1
  53. package/dist/esm/target/lib/react/useAction.js +13 -12
  54. package/dist/esm/target/lib/server/AuthenticationChecker.js +1 -1
  55. package/dist/esm/target/lib/server/PublicApiKeyChecker.js +1 -1
  56. package/dist/esm/target/lib/server/ServerRequestHandler.js +2 -2
  57. package/dist/esm/target/lib/server-express/funcs.js +4 -3
  58. package/dist/esm/target/lib/server-hono/funcs.js +2 -2
  59. package/dist/esm/target/lib/server-node/funcs.js +1 -1
  60. package/dist/esm/target/lib/web/input.d.ts +1 -0
  61. package/dist/esm/target/lib/web/input.js +5 -1
  62. package/dist/esm/target/node-stricli-cli/NodeStricliCLIManager.d.ts +12 -0
  63. package/dist/esm/target/node-stricli-cli/NodeStricliCLIManager.js +118 -0
  64. package/dist/esm/target/react-native-pure/UCFormField.js +2 -1
  65. package/dist/esm/target/react-native-pure/UCFormFieldControl.js +6 -4
  66. package/dist/esm/target/react-native-pure/UCFormFieldErr.d.ts +1 -1
  67. package/dist/esm/target/react-native-pure/UCFormFieldErr.js +4 -1
  68. package/dist/esm/target/react-native-pure/UCFormFieldHelp.d.ts +4 -0
  69. package/dist/esm/target/react-native-pure/UCFormFieldHelp.js +15 -0
  70. package/dist/esm/target/react-web-pure/UCFormField.js +2 -1
  71. package/dist/esm/target/react-web-pure/UCFormFieldErr.d.ts +1 -1
  72. package/dist/esm/target/react-web-pure/UCFormFieldErr.js +4 -1
  73. package/dist/esm/target/react-web-pure/UCFormFieldHelp.d.ts +4 -0
  74. package/dist/esm/target/react-web-pure/UCFormFieldHelp.js +14 -0
  75. package/dist/esm/testing/AppTester.js +4 -5
  76. package/dist/esm/testing/UCDefASTParser.d.ts +24 -6
  77. package/dist/esm/testing/impl/SimpleAppDocsEmitter/SimpleAppDocsEmitter.d.ts +7 -0
  78. package/dist/esm/testing/impl/SimpleAppDocsEmitter/SimpleAppDocsEmitter.js +59 -0
  79. package/dist/esm/testing/impl/SimpleAppDocsEmitter/markdown.d.ts +2 -0
  80. package/dist/esm/testing/impl/SimpleAppDocsEmitter/markdown.js +10 -0
  81. package/dist/esm/testing/impl/SimpleAppDocsEmitter/sequence-diagram.d.ts +2 -0
  82. package/dist/esm/testing/impl/SimpleAppDocsEmitter/sequence-diagram.js +92 -0
  83. package/dist/esm/testing/impl/SimpleAppDocsEmitter/tech-summary.d.ts +2 -0
  84. package/dist/esm/testing/impl/SimpleAppDocsEmitter/tech-summary.js +27 -0
  85. package/dist/esm/testing/impl/SimpleAppDocsEmitter/uc-summary.d.ts +2 -0
  86. package/dist/esm/testing/impl/SimpleAppDocsEmitter/uc-summary.js +63 -0
  87. package/dist/esm/testing/impl/SimpleAppDocsEmitter.js +4 -5
  88. package/dist/esm/testing/impl/TypeScriptLibUCDefASTParser.js +38 -11
  89. package/dist/esm/testing/impl/VitestAppTestSuiteRunner.d.ts +1 -1
  90. package/dist/esm/testing/impl/VitestAppTestSuiteRunner.js +17 -2
  91. package/dist/esm/testing/impl/newNodeAppTester.js +1 -1
  92. package/dist/esm/testing/opts.js +1 -1
  93. package/dist/esm/testing/uc-input.js +5 -2
  94. package/dist/esm/testing/workers/AppTestSuiteRunner.d.ts +2 -0
  95. package/dist/esm/testing/workers/UCExecutor.js +1 -1
  96. package/dist/esm/testing/workers/checkers/AppI18nChecker.d.ts +8 -2
  97. package/dist/esm/testing/workers/checkers/AppI18nChecker.js +44 -2
  98. package/dist/esm/testing/workers/checkers/UCDefSourcesChecker.js +12 -12
  99. package/dist/esm/uc/exec.d.ts +42 -21
  100. package/dist/esm/uc/exec.js +48 -13
  101. package/dist/esm/uc/impl/HTTPUCTransporter.js +2 -2
  102. package/dist/esm/uc/impl/KnexUCDataStore.js +2 -2
  103. package/dist/esm/uc/index.d.ts +0 -1
  104. package/dist/esm/uc/index.js +0 -1
  105. package/dist/esm/uc/input-field.d.ts +6 -4
  106. package/dist/esm/uc/input-field.js +4 -5
  107. package/dist/esm/uc/side-effect.d.ts +10 -8
  108. package/dist/esm/uc/side-effect.js +5 -6
  109. package/dist/esm/uc/workers/UCExecChecker.js +1 -1
  110. package/dist/esm/uc/workers/UCInputFilesProcessor.js +3 -3
  111. package/dist/esm/uc/workers/UCInputValidator.js +2 -1
  112. package/dist/esm/uc/workers/UCOutputFilesProcessor.js +1 -1
  113. package/dist/esm/utils/bundling/babel/plugin.d.ts +2 -0
  114. package/dist/esm/utils/bundling/babel/plugin.js +38 -0
  115. package/dist/esm/utils/bundling/funcs.d.ts +6 -0
  116. package/dist/esm/utils/bundling/funcs.js +20 -0
  117. package/dist/esm/utils/bundling/typescript.d.ts +3 -0
  118. package/dist/esm/utils/bundling/typescript.js +61 -0
  119. package/dist/esm/utils/bundling/vite/plugin.d.ts +6 -0
  120. package/dist/esm/utils/bundling/vite/plugin.js +17 -0
  121. package/dist/esm/utils/bundling/webpack/loader.d.ts +2 -0
  122. package/dist/esm/utils/bundling/webpack/loader.js +12 -0
  123. package/dist/esm/utils/http/HTTPRequestBuilder.js +1 -1
  124. package/dist/esm/utils/index.d.ts +1 -1
  125. package/dist/esm/utils/ioc/bindCommon.js +1 -1
  126. package/dist/esm/utils/terminal/fmt.js +1 -1
  127. package/dist/esm/utils/types/utility-types.d.ts +4 -0
  128. package/package.json +36 -12
  129. package/pnpm-workspace.yaml +1 -4
  130. package/tsconfig.build.examples.json +8 -0
  131. package/tsconfig.json +1 -0
  132. package/vitest.config.ts +16 -0
@@ -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
  }
@@ -51,7 +51,7 @@ let HTTPUCTransporter = class HTTPUCTransporter {
51
51
  break;
52
52
  }
53
53
  default:
54
- ((_) => { })(publicApiKeyCheckType);
54
+ publicApiKeyCheckType;
55
55
  }
56
56
  if (auth) {
57
57
  switch (authType) {
@@ -86,7 +86,7 @@ let HTTPUCTransporter = class HTTPUCTransporter {
86
86
  break;
87
87
  }
88
88
  default:
89
- ((_) => { })(authType);
89
+ authType;
90
90
  }
91
91
  }
92
92
  const res = await this.httpAPICaller.exec({
@@ -112,7 +112,7 @@ let KnexUCDataStore = class KnexUCDataStore {
112
112
  case 'sqlite3':
113
113
  return [];
114
114
  default:
115
- ((_) => { })(type);
115
+ (type);
116
116
  return [];
117
117
  }
118
118
  }
@@ -156,7 +156,7 @@ let KnexUCDataStore = class KnexUCDataStore {
156
156
  this.fillConfigForSQLite3();
157
157
  break;
158
158
  default:
159
- ((_) => { })(type);
159
+ (type);
160
160
  }
161
161
  }
162
162
  fillConfigForPG() {
@@ -48,7 +48,6 @@ export * from './utils/fmtVal.js';
48
48
  export * from './utils/recIs.js';
49
49
  export * from './utils/rInput.js';
50
50
  export * from './utils/rVal.js';
51
- export * from './utils/stripUCDLifecycleServer.js';
52
51
  export * from './utils/ucHTTPContract.js';
53
52
  export * from './utils/ucMountingPoint.js';
54
53
  export * from './value.js';
@@ -48,7 +48,6 @@ export * from './utils/fmtVal.js';
48
48
  export * from './utils/recIs.js';
49
49
  export * from './utils/rInput.js';
50
50
  export * from './utils/rVal.js';
51
- export * from './utils/stripUCDLifecycleServer.js';
52
51
  export * from './utils/ucHTTPContract.js';
53
52
  export * from './utils/ucMountingPoint.js';
54
53
  export * from './value.js';
@@ -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();
@@ -1,8 +1,9 @@
1
- export declare enum UCOutputSideEffectType {
1
+ import type { EnumOf } from '../utils/index.js';
2
+ export declare const UCOutputSideEffectType: {
2
3
  /**
3
4
  * Trigger a clearing of the auth on the calling system (e.g. `SignOut`).
4
5
  */
5
- CLEAR_AUTH = "CLEAR_AUTH",
6
+ readonly CLEAR_AUTH: "CLEAR_AUTH";
6
7
  /**
7
8
  * Trigger a redirect on the calling system (e.g. after the final round of an OAuth1 flow)
8
9
  *
@@ -11,18 +12,19 @@ export declare enum UCOutputSideEffectType {
11
12
  *
12
13
  * It expects a field `redirect: URL` in `output.parts._0.items[0]`.
13
14
  */
14
- REDIRECT = "REDIRECT",
15
+ readonly REDIRECT: "REDIRECT";
15
16
  /**
16
17
  * Trigger a setting of the auth on the calling system (e.g. `SignIn` / `SignUp`).
17
18
  *
18
19
  * It expects a field `jwt: JWT` in `output.parts._0.items[0]`.
19
20
  */
20
- SET_AUTH = "SET_AUTH"
21
- }
21
+ readonly SET_AUTH: "SET_AUTH";
22
+ };
23
+ export type UCOutputSideEffectType = EnumOf<typeof UCOutputSideEffectType>;
22
24
  export type UCOutputSideEffect = {
23
- type: UCOutputSideEffectType.CLEAR_AUTH;
25
+ type: typeof UCOutputSideEffectType.CLEAR_AUTH;
24
26
  } | {
25
- type: UCOutputSideEffectType.REDIRECT;
27
+ type: typeof UCOutputSideEffectType.REDIRECT;
26
28
  } | {
27
- type: UCOutputSideEffectType.SET_AUTH;
29
+ type: typeof UCOutputSideEffectType.SET_AUTH;
28
30
  };
@@ -1,9 +1,8 @@
1
- export var UCOutputSideEffectType;
2
- (function (UCOutputSideEffectType) {
1
+ export const UCOutputSideEffectType = {
3
2
  /**
4
3
  * Trigger a clearing of the auth on the calling system (e.g. `SignOut`).
5
4
  */
6
- UCOutputSideEffectType["CLEAR_AUTH"] = "CLEAR_AUTH";
5
+ CLEAR_AUTH: 'CLEAR_AUTH',
7
6
  /**
8
7
  * Trigger a redirect on the calling system (e.g. after the final round of an OAuth1 flow)
9
8
  *
@@ -12,11 +11,11 @@ export var UCOutputSideEffectType;
12
11
  *
13
12
  * It expects a field `redirect: URL` in `output.parts._0.items[0]`.
14
13
  */
15
- UCOutputSideEffectType["REDIRECT"] = "REDIRECT";
14
+ REDIRECT: 'REDIRECT',
16
15
  /**
17
16
  * Trigger a setting of the auth on the calling system (e.g. `SignIn` / `SignUp`).
18
17
  *
19
18
  * It expects a field `jwt: JWT` in `output.parts._0.items[0]`.
20
19
  */
21
- UCOutputSideEffectType["SET_AUTH"] = "SET_AUTH";
22
- })(UCOutputSideEffectType || (UCOutputSideEffectType = {}));
20
+ SET_AUTH: 'SET_AUTH',
21
+ };
@@ -59,7 +59,7 @@ let UCExecChecker = class UCExecChecker {
59
59
  output.allowed = typeof server === 'object';
60
60
  break;
61
61
  default:
62
- ((_) => { })(lifecycle);
62
+ lifecycle;
63
63
  }
64
64
  return output;
65
65
  }
@@ -66,9 +66,9 @@ let UCInputFilesProcessor = class UCInputFilesProcessor {
66
66
  await this.fsManager.touch(destPath, await file.arrayBuffer());
67
67
  }
68
68
  else {
69
- const { path } = file;
70
- await this.fsManager.cp(path, destPath);
71
- await this.fsManager.rm(path);
69
+ const { uri } = file;
70
+ await this.fsManager.cp(uri, destPath);
71
+ await this.fsManager.rm(uri);
72
72
  }
73
73
  return fileNameRef;
74
74
  }
@@ -34,7 +34,8 @@ let UCInputValidator = class UCInputValidator {
34
34
  let message = this.i18nManager.t(key, { vars: { expected } });
35
35
  if (field) {
36
36
  const { label } = this.wordingManager.ucif(field);
37
- message = `${label} ${message ? message.toLowerCase() : ''}`.trim();
37
+ message = `${message.charAt(0).toLowerCase()}${message.slice(1)}`;
38
+ message = `${label} ${message}`.trim();
38
39
  }
39
40
  throw new IllegalArgumentError(message);
40
41
  }
@@ -44,7 +44,7 @@ let UCOutputFilesProcessor = class UCOutputFilesProcessor {
44
44
  filePath = this.fsManager.path(this.s().uc_files_directory_path, fileName); // => /path/to/files/20230110143732-155eb8d3-9af5-430e-b856-248007859df1.jpg
45
45
  }
46
46
  else {
47
- filePath = fileNameRef.path;
47
+ filePath = fileNameRef.uri;
48
48
  }
49
49
  if (keepOnlyFileName) {
50
50
  const { base } = await this.fsManager.info(filePath);
@@ -0,0 +1,2 @@
1
+ import { type PluginObj } from '@babel/core';
2
+ export declare const Plugin: PluginObj;
@@ -0,0 +1,38 @@
1
+ import { types as t } from '@babel/core';
2
+ import { UC_LIFECYCLE_PROP_NAME, UC_LIFECYCLE_SERVER_PROP_NAME, } from '../../../convention.js';
3
+ import { isFileEligible } from '../funcs.js';
4
+ // Using `PluginObj` instead of `satisfies PluginObj`.
5
+ // Otherwise TypeScript is not happy and triggers a TS2209.
6
+ export const Plugin = {
7
+ name: 'libmodulor-plugin',
8
+ visitor: {
9
+ ObjectExpression(path, state) {
10
+ if (!isFileEligible(state.filename, ['js', 'ts'])) {
11
+ return;
12
+ }
13
+ const lifecycle = findLifecycleProp(path);
14
+ if (!lifecycle) {
15
+ return;
16
+ }
17
+ const lifecycleObj = lifecycle.value;
18
+ const server = findServerProp(lifecycleObj);
19
+ if (!server) {
20
+ return;
21
+ }
22
+ server.value = t.booleanLiteral(true);
23
+ },
24
+ },
25
+ };
26
+ function findLifecycleProp(path) {
27
+ return path.node.properties.find((p) => t.isObjectProperty(p) &&
28
+ t.isIdentifier(p.key, {
29
+ name: UC_LIFECYCLE_PROP_NAME,
30
+ }) &&
31
+ t.isObjectExpression(p.value));
32
+ }
33
+ function findServerProp(lifecycleObj) {
34
+ return lifecycleObj.properties.find((p) => t.isObjectProperty(p) &&
35
+ t.isIdentifier(p.key, {
36
+ name: UC_LIFECYCLE_SERVER_PROP_NAME,
37
+ }));
38
+ }
@@ -0,0 +1,6 @@
1
+ import type { FileName } from '../../dt/index.js';
2
+ export type InputCode = string;
3
+ export type OutputCode = string;
4
+ export type StrippableFileExtension = 'js' | 'ts';
5
+ export declare function isFileEligible(fileName: FileName | undefined, exts: StrippableFileExtension[]): boolean;
6
+ export declare function assertTransformedCorrectly(transformed: OutputCode, fileName: FileName | undefined): void;
@@ -0,0 +1,20 @@
1
+ import { UC_DEF_SUFFIX } from '../../convention.js';
2
+ export function isFileEligible(fileName, exts) {
3
+ if (!fileName) {
4
+ return false;
5
+ }
6
+ for (const ext of exts) {
7
+ if (fileName.endsWith(`${UC_DEF_SUFFIX}.${ext}`)) {
8
+ return true;
9
+ }
10
+ }
11
+ return false;
12
+ }
13
+ export function assertTransformedCorrectly(transformed, fileName) {
14
+ const match = transformed.match(/server: (.*)ServerMain/g);
15
+ if (match !== null) {
16
+ // biome-ignore lint/suspicious/noConsole: we want it
17
+ console.warn(transformed);
18
+ throw new Error(`[WARNING] The following file might not have been transformed correctly : ${fileName} (see transformed above)`);
19
+ }
20
+ }
@@ -0,0 +1,3 @@
1
+ import type { FileName } from '../../dt/index.js';
2
+ import type { InputCode, OutputCode } from './funcs.js';
3
+ export declare function transform(code: InputCode, fileName: FileName): OutputCode;
@@ -0,0 +1,61 @@
1
+ import ts from 'typescript';
2
+ import { UC_DEF_SUFFIX, UC_LIFECYCLE_PROP_NAME, UC_LIFECYCLE_SERVER_PROP_NAME, } from '../../convention.js';
3
+ export function transform(code, fileName) {
4
+ const sourceFile = ts.createSourceFile(fileName, code, ts.ScriptTarget.ESNext);
5
+ const result = ts.transform(sourceFile, [transformer()]);
6
+ const transformed = result.transformed[0];
7
+ if (!transformed) {
8
+ throw new Error(`Could not transform file : ${fileName}`);
9
+ }
10
+ const printer = ts.createPrinter();
11
+ return printer.printFile(transformed);
12
+ }
13
+ function transformer() {
14
+ return (context) => {
15
+ return (sourceFile) => {
16
+ const { factory } = context;
17
+ function visit(node) {
18
+ if (!isUCDDeclaration(sourceFile, node)) {
19
+ return ts.visitEachChild(node, visit, context);
20
+ }
21
+ const rootObj = node.initializer;
22
+ const lifecycle = findLifecycleProp(sourceFile, rootObj);
23
+ if (!lifecycle) {
24
+ return ts.visitEachChild(node, visit, context);
25
+ }
26
+ const lifecycleObj = lifecycle.initializer;
27
+ const server = findServerProp(sourceFile, lifecycleObj);
28
+ if (!server) {
29
+ return ts.visitEachChild(node, visit, context);
30
+ }
31
+ // Nodes are immutable so we need to re-create the whole tree
32
+ const newServer = factory.updatePropertyAssignment(server, server.name, factory.createTrue());
33
+ const newLifecycleObj = factory.updateObjectLiteralExpression(lifecycleObj, lifecycleObj.properties.map((p) => p === server ? newServer : p));
34
+ const newLifecycle = factory.updatePropertyAssignment(lifecycle, lifecycle.name, newLifecycleObj);
35
+ const newRootObj = factory.updateObjectLiteralExpression(rootObj, rootObj.properties.map((p) => p === lifecycle ? newLifecycle : p));
36
+ return factory.updateVariableDeclaration(node, node.name, node.exclamationToken, node.type, newRootObj);
37
+ }
38
+ return ts.visitNode(sourceFile, visit);
39
+ };
40
+ };
41
+ }
42
+ function isUCDDeclaration(sourceFile, node) {
43
+ if (!ts.isVariableDeclaration(node)) {
44
+ return false;
45
+ }
46
+ const name = node.name.getText(sourceFile);
47
+ return (name.endsWith(UC_DEF_SUFFIX) &&
48
+ !!node.initializer &&
49
+ ts.isObjectLiteralExpression(node.initializer));
50
+ }
51
+ function findLifecycleProp(sourceFile, rootObj) {
52
+ return rootObj.properties.find((p) => ts.isPropertyAssignment(p) &&
53
+ ts.isIdentifier(p.name) &&
54
+ p.name.getText(sourceFile) === UC_LIFECYCLE_PROP_NAME &&
55
+ ts.isObjectLiteralExpression(p.initializer));
56
+ }
57
+ function findServerProp(sourceFile, lifecycleObj) {
58
+ return lifecycleObj.properties.find((p) => ts.isPropertyAssignment(p) &&
59
+ ts.isIdentifier(p.name) &&
60
+ p.name.getText(sourceFile) === UC_LIFECYCLE_SERVER_PROP_NAME);
61
+ }
@@ -0,0 +1,6 @@
1
+ export declare const Plugin: {
2
+ name: string;
3
+ transform: (this: import("rollup").TransformPluginContext, code: string, id: string) => {
4
+ code: string;
5
+ };
6
+ };
@@ -0,0 +1,17 @@
1
+ import { assertTransformedCorrectly, isFileEligible } from '../funcs.js';
2
+ import { transform } from '../typescript.js';
3
+ export const Plugin = {
4
+ name: 'libmodulor-plugin',
5
+ transform: (code, id) => {
6
+ if (!isFileEligible(id, ['ts'])) {
7
+ return {
8
+ code,
9
+ };
10
+ }
11
+ const transformed = transform(code, id);
12
+ assertTransformedCorrectly(transformed, id);
13
+ return {
14
+ code: transformed,
15
+ };
16
+ },
17
+ };
@@ -0,0 +1,2 @@
1
+ import { type InputCode, type OutputCode } from '../funcs.js';
2
+ export default function loader(source: InputCode): OutputCode;
@@ -0,0 +1,12 @@
1
+ import { assertTransformedCorrectly, isFileEligible, } from '../funcs.js';
2
+ import { transform } from '../typescript.js';
3
+ export default function loader(source) {
4
+ // @ts-expect-error : magically made available by Webpack at execution
5
+ const fileName = this.resourcePath;
6
+ if (!isFileEligible(fileName, ['ts'])) {
7
+ return source;
8
+ }
9
+ const transformed = transform(source, fileName);
10
+ assertTransformedCorrectly(transformed, fileName);
11
+ return transformed;
12
+ }
@@ -41,7 +41,7 @@ let HTTPRequestBuilder = class HTTPRequestBuilder {
41
41
  break;
42
42
  }
43
43
  default:
44
- ((_) => { })(envelope);
44
+ envelope;
45
45
  return output;
46
46
  }
47
47
  return output;
@@ -23,4 +23,4 @@ export { humanize } from './strings/humanize.js';
23
23
  export { truncate } from './strings/truncate.js';
24
24
  export { fmtBold, fmtCommand, fmtPadEndFor, fmtSection, } from './terminal/fmt.js';
25
25
  export { assertIsDefined, isBlank, range, sample, tupleOf, } from './types/funcs.js';
26
- export type { ExtractStrict, RecursiveNonNullable, StringKeys, } from './types/utility-types.js';
26
+ export type { EnumOf, ExtractStrict, RecursiveNonNullable, StringKeys, } from './types/utility-types.js';
@@ -49,7 +49,7 @@ export function bindCommon(container, settingsFunc) {
49
49
  .bind('I18nManager')
50
50
  .to(SimpleMapI18nManager)
51
51
  .inSingletonScope();
52
- container.bind('I18n').toConstantValue({});
52
+ container.bind('I18n').toConstantValue({ en: {} });
53
53
  container.bind('Logger').to(ConsoleLogger);
54
54
  container.bind('Settings').toConstantValue(settings);
55
55
  container
@@ -5,7 +5,7 @@ export function fmtCommand(cmd, details, padEnd) {
5
5
  return ` ${cmd.padEnd(padEnd)}${details ?? ''}`;
6
6
  }
7
7
  export function fmtPadEndFor(s) {
8
- const longest = s.sort((a, b) => a.length - b.length).reverse()[0];
8
+ const longest = [...s].sort((a, b) => a.length - b.length).reverse()[0];
9
9
  return (longest?.length ?? 1) + 10;
10
10
  }
11
11
  export function fmtSection(s) {
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Get an enum-like type with the keys of the object
3
+ */
4
+ export type EnumOf<T extends object> = T[keyof T];
1
5
  /**
2
6
  * Extract a subset of a union type in a strict manner
3
7
  *
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "libmodulor",
3
3
  "description": "A TypeScript library to create platform-agnostic applications",
4
- "version": "0.23.0",
4
+ "version": "0.25.0",
5
5
  "license": "LGPL-3.0",
6
6
  "author": "Chafik H'nini <chafik.hnini@gmail.com>",
7
7
  "homepage": "https://libmodulor.c100k.eu",
@@ -23,12 +23,21 @@
23
23
  ".": {
24
24
  "import": "./dist/esm/index.js"
25
25
  },
26
+ "./babel": {
27
+ "import": "./dist/esm/index.babel.js"
28
+ },
26
29
  "./cloudflare-worker-hono": {
27
30
  "import": "./dist/esm/index.cloudflare-worker-hono.js"
28
31
  },
32
+ "./locales/de": {
33
+ "import": "./dist/esm/i18n/locales/de.js"
34
+ },
29
35
  "./locales/en": {
30
36
  "import": "./dist/esm/i18n/locales/en.js"
31
37
  },
38
+ "./locales/es": {
39
+ "import": "./dist/esm/i18n/locales/es.js"
40
+ },
32
41
  "./locales/fr": {
33
42
  "import": "./dist/esm/i18n/locales/fr.js"
34
43
  },
@@ -44,6 +53,9 @@
44
53
  "./node-mcp": {
45
54
  "import": "./dist/esm/index.node-mcp.js"
46
55
  },
56
+ "./node-stricli-cli": {
57
+ "import": "./dist/esm/index.node-stricli-cli.js"
58
+ },
47
59
  "./node-test": {
48
60
  "import": "./dist/esm/index.node-test.js"
49
61
  },
@@ -73,6 +85,9 @@
73
85
  },
74
86
  "./web": {
75
87
  "import": "./dist/esm/index.web.js"
88
+ },
89
+ "./webpack": {
90
+ "import": "./dist/esm/index.webpack.js"
76
91
  }
77
92
  },
78
93
  "bin": "./dist/esm/products/Helper/index.js",
@@ -81,26 +96,35 @@
81
96
  "lint:ci": "biome check"
82
97
  },
83
98
  "devDependencies": {
84
- "@biomejs/biome": "^2.3.4"
99
+ "@biomejs/biome": "^2.3.10",
100
+ "@react-native-community/slider": "^4.5.7",
101
+ "@types/react": "^19.2.7",
102
+ "@types/react-dom": "^19.2.3",
103
+ "babel-plugin-parameter-decorator": "^1.0.16",
104
+ "babel-plugin-transform-typescript-metadata": "^0.3.2",
105
+ "expo": "^54.0.29",
106
+ "expo-document-picker": "~14.0.8",
107
+ "expo-image-picker": "^17.0.10",
108
+ "wrangler": "^4.55.0"
85
109
  },
86
110
  "peerDependencies": {
87
- "@hono/node-server": "^1.19.6",
88
- "@modelcontextprotocol/sdk": "^1.21.0",
111
+ "@hono/node-server": "^1.19.7",
112
+ "@modelcontextprotocol/sdk": "^1.25.1",
89
113
  "@stricli/core": "^1.2.4",
90
114
  "buffer": "^6.0.3",
91
115
  "cookie-parser": "^1.4.7",
92
- "express": "^5.1.0",
116
+ "express": "^5.2.1",
93
117
  "express-fileupload": "^1.5.2",
94
- "fast-check": "^4.3.0",
118
+ "fast-check": "^4.4.0",
95
119
  "helmet": "^8.1.0",
96
- "hono": "^4.10.4",
97
- "inversify": "^7.10.4",
98
- "jose": "^6.1.0",
120
+ "hono": "^4.11.1",
121
+ "inversify": "^7.10.7",
122
+ "jose": "^6.1.3",
99
123
  "knex": "^3.1.0",
100
- "next": "^15.5.6",
124
+ "next": "^15.5.9",
101
125
  "pg": "^8.16.3",
102
- "react": "^19.2.0",
103
- "react-dom": "^19.2.0",
126
+ "react": "^19.2.3",
127
+ "react-dom": "^19.2.3",
104
128
  "react-native": "^0.81.5",
105
129
  "reflect-metadata": "^0.2.2",
106
130
  "sqlite3": "^5.1.7",
@@ -1,11 +1,8 @@
1
1
  minimumReleaseAge: 2880
2
- packages:
3
- - examples/basic
4
- - examples/standalone
5
- - examples/supertrader
6
2
  onlyBuiltDependencies:
7
3
  - '@biomejs/biome'
8
4
  - '@tailwindcss/oxide'
9
5
  - esbuild
10
6
  - sharp
11
7
  - sqlite3
8
+ - workerd