libmodulor 0.22.0 → 0.24.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 (92) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +154 -2
  3. package/dist/esm/apps/Helper/src/lib/project.js +4 -4
  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/base/TObject.js +1 -1
  10. package/dist/esm/i18n/index.d.ts +1 -1
  11. package/dist/esm/i18n/locales/de.d.ts +2 -0
  12. package/dist/esm/i18n/locales/de.js +54 -0
  13. package/dist/esm/i18n/locales/es.d.ts +2 -0
  14. package/dist/esm/i18n/locales/es.js +54 -0
  15. package/dist/esm/i18n/types.d.ts +3 -2
  16. package/dist/esm/index.babel.d.ts +1 -0
  17. package/dist/esm/index.babel.js +1 -0
  18. package/dist/esm/index.node-stricli-cli.d.ts +2 -0
  19. package/dist/esm/index.node-stricli-cli.js +2 -0
  20. package/dist/esm/index.react.d.ts +1 -1
  21. package/dist/esm/index.react.js +1 -1
  22. package/dist/esm/index.vite.d.ts +1 -1
  23. package/dist/esm/index.vite.js +1 -1
  24. package/dist/esm/index.webpack.d.ts +1 -0
  25. package/dist/esm/index.webpack.js +1 -0
  26. package/dist/esm/std/I18nManager.d.ts +12 -0
  27. package/dist/esm/std/JWTManager.d.ts +16 -1
  28. package/dist/esm/std/impl/JoseJWTManager.d.ts +3 -2
  29. package/dist/esm/std/impl/JoseJWTManager.js +4 -0
  30. package/dist/esm/std/impl/NodeFSManager.js +1 -1
  31. package/dist/esm/std/impl/SimpleHTTPAPICaller.js +4 -2
  32. package/dist/esm/std/impl/SimpleMapI18nManager.d.ts +6 -1
  33. package/dist/esm/std/impl/SimpleMapI18nManager.js +41 -12
  34. package/dist/esm/target/lib/client/consts.js +1 -0
  35. package/dist/esm/target/lib/react/UCPanel.d.ts +7 -8
  36. package/dist/esm/target/lib/react/useUC.js +11 -1
  37. package/dist/esm/target/lib/server/AuthenticationChecker.js +1 -1
  38. package/dist/esm/target/lib/server/PublicApiKeyChecker.js +1 -1
  39. package/dist/esm/target/lib/server/ServerManager.d.ts +1 -0
  40. package/dist/esm/target/lib/server/ServerRequestHandler.js +2 -2
  41. package/dist/esm/target/lib/server/consts.js +1 -0
  42. package/dist/esm/target/lib/server-express/funcs.js +5 -4
  43. package/dist/esm/target/lib/server-hono/funcs.js +2 -2
  44. package/dist/esm/target/lib/server-node/funcs.d.ts +2 -2
  45. package/dist/esm/target/lib/server-node/funcs.js +11 -1
  46. package/dist/esm/target/lib/server-node/types.d.ts +1 -0
  47. package/dist/esm/target/node-express-server/NodeExpressServerManager.d.ts +2 -2
  48. package/dist/esm/target/node-express-server/NodeExpressServerManager.js +2 -1
  49. package/dist/esm/target/node-hono-server/NodeHonoServerManager.d.ts +2 -2
  50. package/dist/esm/target/node-hono-server/NodeHonoServerManager.js +2 -1
  51. package/dist/esm/target/node-stricli-cli/NodeStricliCLIManager.d.ts +12 -0
  52. package/dist/esm/target/node-stricli-cli/NodeStricliCLIManager.js +118 -0
  53. package/dist/esm/testing/AppTester.js +4 -5
  54. package/dist/esm/testing/UCDefASTParser.d.ts +24 -6
  55. package/dist/esm/testing/impl/SimpleAppDocsEmitter.js +4 -5
  56. package/dist/esm/testing/impl/TypeScriptLibUCDefASTParser.js +38 -11
  57. package/dist/esm/testing/impl/VitestAppTestSuiteRunner.d.ts +1 -1
  58. package/dist/esm/testing/impl/VitestAppTestSuiteRunner.js +17 -2
  59. package/dist/esm/testing/impl/newNodeAppTester.js +3 -2
  60. package/dist/esm/testing/opts.js +1 -1
  61. package/dist/esm/testing/workers/AppTestSuiteRunner.d.ts +2 -0
  62. package/dist/esm/testing/workers/UCExecutor.js +1 -1
  63. package/dist/esm/testing/workers/checkers/AppI18nChecker.d.ts +8 -2
  64. package/dist/esm/testing/workers/checkers/AppI18nChecker.js +44 -2
  65. package/dist/esm/testing/workers/checkers/UCDefSourcesChecker.js +12 -12
  66. package/dist/esm/uc/impl/HTTPUCTransporter.js +2 -2
  67. package/dist/esm/uc/impl/KnexUCDataStore.js +2 -2
  68. package/dist/esm/uc/index.d.ts +0 -1
  69. package/dist/esm/uc/index.js +0 -1
  70. package/dist/esm/uc/workers/UCExecChecker.js +1 -1
  71. package/dist/esm/utils/bundling/babel/plugin.d.ts +2 -0
  72. package/dist/esm/utils/bundling/babel/plugin.js +38 -0
  73. package/dist/esm/utils/bundling/funcs.d.ts +6 -0
  74. package/dist/esm/utils/bundling/funcs.js +20 -0
  75. package/dist/esm/utils/bundling/typescript.d.ts +3 -0
  76. package/dist/esm/utils/bundling/typescript.js +61 -0
  77. package/dist/esm/utils/bundling/vite/plugin.d.ts +6 -0
  78. package/dist/esm/utils/bundling/vite/plugin.js +17 -0
  79. package/dist/esm/utils/bundling/webpack/loader.d.ts +2 -0
  80. package/dist/esm/utils/bundling/webpack/loader.js +12 -0
  81. package/dist/esm/utils/http/HTTPRequestBuilder.js +1 -1
  82. package/dist/esm/utils/http/NDJSONStreamManager.d.ts +2 -1
  83. package/dist/esm/utils/http/NDJSONStreamManager.js +4 -1
  84. package/dist/esm/utils/http/SSEStreamManager.d.ts +2 -1
  85. package/dist/esm/utils/http/SSEStreamManager.js +4 -1
  86. package/dist/esm/utils/ioc/bindCommon.js +1 -1
  87. package/dist/esm/utils/terminal/fmt.js +1 -1
  88. package/package.json +32 -10
  89. package/pnpm-workspace.yaml +1 -4
  90. package/tsconfig.build.examples.json +8 -0
  91. package/tsconfig.json +1 -0
  92. package/vitest.config.ts +16 -0
@@ -11,7 +11,8 @@ 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 typescript, { isClassDeclaration, isObjectLiteralExpression, isPropertyAssignment, } from 'typescript';
14
+ import typescript, { isClassDeclaration, isObjectLiteralExpression, isPropertyAssignment, SyntaxKind, } from 'typescript';
15
+ // https://ts-ast-viewer.com
15
16
  // To avoid the following error when used in a consumer :
16
17
  // 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
18
  // CommonJS modules can always be imported via the default export
@@ -99,20 +100,46 @@ let TypeScriptLibUCDefASTParser = class TypeScriptLibUCDefASTParser {
99
100
  }
100
101
  getTypeFields(node) {
101
102
  const type = this.typeChecker.getTypeAtLocation(node);
102
- const fields = type.getProperties().map((p) => {
103
+ const fields = type
104
+ .getProperties()
105
+ .map((p) => {
103
106
  const field = {
104
107
  err: null,
105
- value: p.getName(),
108
+ value: {
109
+ dataType: null,
110
+ name: null,
111
+ raw: null,
112
+ type: null,
113
+ },
106
114
  };
107
115
  const declarations = p.getDeclarations();
108
- if (declarations) {
109
- const [first] = declarations;
110
- if (first && isPropertySignature(first)) {
111
- field.value = first
112
- .getText()
113
- .replaceAll('\n', '')
114
- .replaceAll(';', '');
115
- }
116
+ if (!declarations) {
117
+ return field;
118
+ }
119
+ const [first] = declarations;
120
+ if (first && isPropertySignature(first)) {
121
+ field.value.raw = first
122
+ .getText()
123
+ .replaceAll('\n', '')
124
+ .replaceAll(';', '')
125
+ .replaceAll(/\s+/g, ' ');
126
+ first.forEachChild((node1) => {
127
+ if (isIdentifier(node1)) {
128
+ field.value.name = node1.getText();
129
+ }
130
+ else if (isTypeReferenceNode(node1)) {
131
+ field.value.type = node1.getText();
132
+ node1.forEachChild((node2) => {
133
+ if (isIdentifier(node2) ||
134
+ isTypeReferenceNode(node2) ||
135
+ node2.kind === SyntaxKind.BooleanKeyword ||
136
+ node2.kind === SyntaxKind.NumberKeyword ||
137
+ node2.kind === SyntaxKind.StringKeyword) {
138
+ field.value.dataType = node2.getText();
139
+ }
140
+ });
141
+ }
142
+ });
116
143
  }
117
144
  return field;
118
145
  });
@@ -5,7 +5,7 @@ export declare class VitestAppTestSuiteRunner implements AppTestSuiteRunner {
5
5
  private fsManager;
6
6
  private shellCommandExecutor;
7
7
  constructor(fsManager: FSManager, shellCommandExecutor: ShellCommandExecutor);
8
- exec({ appPath, skipCoverage, updateSnapshots, }: Input): Promise<void>;
8
+ exec({ appPath, only, skipCoverage, updateSnapshots, }: Input): Promise<void>;
9
9
  coverageReportEntrypointPath(appPath: FilePath): Promise<FilePath>;
10
10
  private coverageReportPath;
11
11
  }
@@ -19,18 +19,33 @@ let VitestAppTestSuiteRunner = class VitestAppTestSuiteRunner {
19
19
  this.fsManager = fsManager;
20
20
  this.shellCommandExecutor = shellCommandExecutor;
21
21
  }
22
- async exec({ appPath, skipCoverage, updateSnapshots, }) {
22
+ async exec({ appPath, only, skipCoverage, updateSnapshots, }) {
23
23
  const testPath = this.fsManager.path(appPath, APP_TEST_DIR_NAME);
24
24
  const args = [
25
25
  'run',
26
26
  '--color',
27
+ // https://vitest.dev/guide/cli.html#dir
27
28
  '--dir',
28
29
  appPath,
29
30
  ];
31
+ if (only) {
32
+ args.push(
33
+ // https://vitest.dev/guide/cli.html#testnamepattern
34
+ '--testNamePattern', only);
35
+ }
30
36
  if (!skipCoverage) {
31
- args.push('--coverage.enabled', '--coverage.exclude', testPath, '--coverage.include', appPath, '--coverage.reportsDirectory', this.coverageReportPath(appPath));
37
+ args.push(
38
+ // https://vitest.dev/guide/cli.html#coverage-enabled
39
+ '--coverage.enabled',
40
+ // https://vitest.dev/guide/cli.html#coverage-exclude
41
+ '--coverage.exclude', testPath,
42
+ // https://vitest.dev/guide/cli.html#coverage-include
43
+ '--coverage.include', appPath,
44
+ // https://vitest.dev/guide/cli.html#coverage-reportsdirectory
45
+ '--coverage.reportsDirectory', this.coverageReportPath(appPath));
32
46
  }
33
47
  if (updateSnapshots) {
48
+ // https://vitest.dev/guide/cli.html#update
34
49
  args.push('--update');
35
50
  }
36
51
  await this.shellCommandExecutor.exec({
@@ -18,8 +18,8 @@ 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: 'fik',
22
- jwt_manager_issuer: 'fik',
21
+ jwt_manager_audience: 'libmodulor-test',
22
+ jwt_manager_issuer: 'libmodulor-test',
23
23
  jwt_manager_secret: new TPassword().example(),
24
24
  logger_level,
25
25
  server_basic_auth_entries: {
@@ -28,6 +28,7 @@ export async function newNodeAppTester(serverPortRangeStart, idx, args) {
28
28
  server_binding_port: serverPortRangeStart + idx,
29
29
  server_private_api_key_entries: [new TApiKey().example()],
30
30
  server_public_api_key_entries: [new TApiKey().example()],
31
+ server_stop_mode: 'aggressive',
31
32
  };
32
33
  const container = new Container(CONTAINER_OPTS);
33
34
  bindCommon(container, () => settings);
@@ -4,7 +4,7 @@ export const DEFAULT_APP_TESTER_OPTS = {
4
4
  imports: {
5
5
  external: {
6
6
  aliasPrefix: '@',
7
- allowed: ['inversify', 'libmodulor'],
7
+ allowed: ['libmodulor', 'inversify'],
8
8
  },
9
9
  internal: {
10
10
  maxDepth: '../../',
@@ -1,7 +1,9 @@
1
1
  import type { FilePath } from '../../dt/index.js';
2
2
  import type { Worker } from '../../std/index.js';
3
+ import type { UCName } from '../../uc/index.js';
3
4
  export interface Input {
4
5
  appPath: FilePath;
6
+ only: UCName | null;
5
7
  skipCoverage: boolean;
6
8
  updateSnapshots: boolean;
7
9
  }
@@ -104,7 +104,7 @@ let UCExecutor = class UCExecutor {
104
104
  break;
105
105
  }
106
106
  default:
107
- ((_) => { })(transportType);
107
+ transportType;
108
108
  }
109
109
  if (!ucor) {
110
110
  throw new Error(ERR_CLIENT_EXPECTED_UCOR(name));
@@ -1,10 +1,12 @@
1
1
  import type { AppManifest } from '../../../app/index.js';
2
2
  import type { ErrorMessage } from '../../../dt/index.js';
3
- import type { I18n } from '../../../i18n/index.js';
3
+ import { type I18n } from '../../../i18n/index.js';
4
4
  import type { Worker } from '../../../std/index.js';
5
+ import type { Output as UCDefSourcesCheckerOutput } from './UCDefSourcesChecker.js';
5
6
  export interface Input {
6
7
  appI18n: I18n;
7
8
  appManifest: Pick<AppManifest, 'languageCodes'>;
9
+ ucDefSourcesCheckerOutput: UCDefSourcesCheckerOutput;
8
10
  }
9
11
  export interface Output {
10
12
  errors: ErrorMessage[];
@@ -13,7 +15,11 @@ export declare class AppI18nChecker implements Worker<Input, Promise<Output>> {
13
15
  private static I18N_KEY_PATTERN;
14
16
  private output;
15
17
  constructor();
16
- exec({ appI18n, appManifest }: Input): Promise<Output>;
18
+ exec({ appI18n, appManifest, ucDefSourcesCheckerOutput, }: Input): Promise<Output>;
17
19
  private makeSureLanguagesAreConsistent;
18
20
  private makeSureKeysAndLabelsAreValid;
21
+ private makeSureNonDefaultLanguagesAreFullyTranslated;
22
+ private checkUC;
23
+ private checkIOFields;
24
+ private checkKey;
19
25
  }
@@ -9,9 +9,11 @@ var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  };
10
10
  var AppI18nChecker_1;
11
11
  import { injectable } from 'inversify';
12
+ import { I18N_DEFAULT_LANG, } from '../../../i18n/index.js';
12
13
  const ERR_I18N_MISMATCH = () => 'The languageCodes in app manifest must match with the keys in i18n';
13
14
  const ERR_I18N_KEY_INVALID = (key) => `The i18n key '${key}' must respect the i18n key pattern`;
14
- const ERR_I18N_LABEL_NO_DOT = (key) => `The i18n key '${key}' is a label, thus should not ends with a dot`;
15
+ const ERR_I18N_LABEL_NO_DOT = (key) => `The i18n key '${key}' is a label, thus it should not end with a dot`;
16
+ const ERR_I18N_MISSING_TRANS = (key, lang) => `The i18n key '${key}' is missing for lang '${lang}'`;
15
17
  let AppI18nChecker = class AppI18nChecker {
16
18
  static { AppI18nChecker_1 = this; }
17
19
  static I18N_KEY_PATTERN = /(dt_([A-Z][A-Za-z0-9]+)_([A-Za-z0-9]+)_(desc|label))|(err_([A-Za-z_]+))|(uc_([A-Z][A-Za-z0-9]+)_(client_confirm_(cancel|confirm|message|title)|desc|label|i_submit_(changing|idle|initializing|submitting)|op_(0|1)_(empty|label)))|(ucif_([a-z]([A-Za-z0-9]+)?)_(desc|label))|(ucof_([a-z]([A-Za-z0-9]+)?)_(desc|label))|(validation_([a-z]+)_([A-Z][A-Za-z0-9]+))/;
@@ -19,9 +21,10 @@ let AppI18nChecker = class AppI18nChecker {
19
21
  constructor() {
20
22
  this.output = { errors: [] };
21
23
  }
22
- async exec({ appI18n, appManifest }) {
24
+ async exec({ appI18n, appManifest, ucDefSourcesCheckerOutput, }) {
23
25
  this.makeSureLanguagesAreConsistent(appI18n, appManifest);
24
26
  this.makeSureKeysAndLabelsAreValid(appI18n);
27
+ this.makeSureNonDefaultLanguagesAreFullyTranslated(appI18n, ucDefSourcesCheckerOutput);
25
28
  return this.output;
26
29
  }
27
30
  makeSureLanguagesAreConsistent(appI18n, appManifest) {
@@ -44,6 +47,45 @@ let AppI18nChecker = class AppI18nChecker {
44
47
  }
45
48
  }
46
49
  }
50
+ makeSureNonDefaultLanguagesAreFullyTranslated(i18n, ucDefSourcesCheckerOutput) {
51
+ for (const [lang, translations] of Object.entries(i18n)) {
52
+ if (lang === I18N_DEFAULT_LANG) {
53
+ // We assume the code is in English so it's fine not to have all the translations in this language.
54
+ // For instance, a field named "name" will be humanized as "Name", which is totally ok.
55
+ continue;
56
+ }
57
+ for (const { metadataName, ioIFields, ioOPI0Fields, ioOPI1Fields, } of ucDefSourcesCheckerOutput.items) {
58
+ this.checkUC(lang, translations, 'label', metadataName);
59
+ for (const [prefix, fields] of [
60
+ ['ucif', ioIFields],
61
+ ['ucof', ioOPI0Fields],
62
+ ['ucof', ioOPI1Fields],
63
+ ]) {
64
+ this.checkIOFields(lang, translations, prefix, 'label', fields);
65
+ }
66
+ }
67
+ }
68
+ }
69
+ checkUC(lang, translations, suffix, metadataName) {
70
+ if (!metadataName) {
71
+ return;
72
+ }
73
+ this.checkKey(lang, translations, `uc_${metadataName.value}_${suffix}`);
74
+ }
75
+ checkIOFields(lang, translations, prefix, suffix, fields) {
76
+ if (!fields) {
77
+ return;
78
+ }
79
+ for (const f of fields) {
80
+ this.checkKey(lang, translations, `${prefix}_${f.value.name}_${suffix}`);
81
+ }
82
+ }
83
+ checkKey(lang, translations, key) {
84
+ if (key in translations) {
85
+ return;
86
+ }
87
+ this.output.errors.push(ERR_I18N_MISSING_TRANS(key, lang));
88
+ }
47
89
  };
48
90
  AppI18nChecker = AppI18nChecker_1 = __decorate([
49
91
  injectable(),
@@ -18,7 +18,7 @@ const ERR_UCD_CONST_NAME = (name) => `The UCD const name '${name}' must follow t
18
18
  const ERR_UCD_FILE_SUFFIX = (fileName) => `The file '${fileName}' must end with ${UC_DEF_FILE_NAME_SUFFIX}`;
19
19
  const ERR_UCD_IMPORTS_EXTERNAL_ALLOWED = (aliasPrefix, allowed, text) => `External imports must be an alias '${aliasPrefix}*' or be one of ${allowed} (Got ${text})`;
20
20
  const ERR_UCD_IMPORTS_INTERNAL_MAX_DEPTH = (maxDepth) => `Internal imports must not be deeper than ${maxDepth}`;
21
- const ERR_UCD_INPUT_FIELD_PATTERN = () => `The input field def must match ${UC_INPUT_FIELD_PATTERN}`;
21
+ const ERR_UCD_INPUT_FIELD_DECLARATION = (raw) => `The input field def must match 'name: UCInputFieldValue<DataType>' (Got '${raw}')`;
22
22
  const ERR_UCD_INPUT_TYPE_NAME = (ucName) => `The input type must be named ${ucName}${UC_INPUT_SUFFIX}`;
23
23
  const ERR_UCD_OPI_TYPE_NAME = (ucName, idx) => `The OPI must be named ${ucName}${UC_OPI_SUFFIX}${idx}`;
24
24
  // TODO : Improve the check* methods that look a little bit hacky
@@ -93,16 +93,16 @@ let UCDefSourcesChecker = class UCDefSourcesChecker {
93
93
  };
94
94
  item.ioIFields = fields;
95
95
  for (const f of item.ioIFields) {
96
- const parts = f.value.split(':');
97
- if (parts.length !== 2) {
98
- continue;
96
+ const { dataType, name, raw, type } = f.value;
97
+ if (dataType &&
98
+ name &&
99
+ raw &&
100
+ type &&
101
+ type.match(new RegExp(UC_INPUT_FIELD_PATTERN)) !== null) {
102
+ }
103
+ else {
104
+ f.err = ERR_UCD_INPUT_FIELD_DECLARATION(raw);
99
105
  }
100
- const [_name, type] = parts;
101
- // trim because we process `name: Type` if the code is linted correctly
102
- f.err =
103
- type?.trim().match(new RegExp(UC_INPUT_FIELD_PATTERN)) !== null
104
- ? null
105
- : ERR_UCD_INPUT_FIELD_PATTERN();
106
106
  }
107
107
  }
108
108
  checkMainStep(lifecycle, step, item) {
@@ -120,7 +120,7 @@ let UCDefSourcesChecker = class UCDefSourcesChecker {
120
120
  item.lifecycleServerSteps.push({ err: null, value: step });
121
121
  break;
122
122
  default:
123
- ((_) => { })(lifecycle);
123
+ lifecycle;
124
124
  }
125
125
  }
126
126
  checkMetadata(metadata, item) {
@@ -177,7 +177,7 @@ let UCDefSourcesChecker = class UCDefSourcesChecker {
177
177
  };
178
178
  break;
179
179
  default:
180
- ((_) => { })(lifecycle);
180
+ lifecycle;
181
181
  }
182
182
  }
183
183
  async processFiles(appPath, paths) {
@@ -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';
@@ -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
  }
@@ -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;
@@ -1,12 +1,13 @@
1
1
  import type { HTTPAPICallExecutorResBody, Worker } from '../../std/index.js';
2
2
  type Encoding = 'utf-8';
3
3
  interface I<D extends object = object> {
4
+ abortController: AbortController;
4
5
  encoding?: Encoding | undefined;
5
6
  onData: (data: D) => Promise<void>;
6
7
  reader: ReturnType<HTTPAPICallExecutorResBody['getReader']>;
7
8
  }
8
9
  export declare class NDJSONStreamManager implements Worker<I, Promise<void>> {
9
10
  private static DEFAULT_ENCODING;
10
- exec({ encoding, onData, reader, }: I): Promise<void>;
11
+ exec({ abortController, encoding, onData, reader, }: I): Promise<void>;
11
12
  }
12
13
  export {};
@@ -10,10 +10,13 @@ import { NDJSON_DATA_SEP } from './nd-json.js';
10
10
  let NDJSONStreamManager = class NDJSONStreamManager {
11
11
  static { NDJSONStreamManager_1 = this; }
12
12
  static DEFAULT_ENCODING = 'utf-8';
13
- async exec({ encoding = NDJSONStreamManager_1.DEFAULT_ENCODING, onData, reader, }) {
13
+ async exec({ abortController, encoding = NDJSONStreamManager_1.DEFAULT_ENCODING, onData, reader, }) {
14
14
  const decoder = new TextDecoder(encoding);
15
15
  let buffer = '';
16
16
  while (true) {
17
+ if (abortController.signal.aborted) {
18
+ return;
19
+ }
17
20
  const { done, value } = await reader.read();
18
21
  if (done) {
19
22
  return;
@@ -1,12 +1,13 @@
1
1
  import type { HTTPAPICallExecutorResBody, Worker } from '../../std/index.js';
2
2
  type Encoding = 'utf-8';
3
3
  interface I<D extends object = object> {
4
+ abortController: AbortController;
4
5
  encoding?: Encoding | undefined;
5
6
  onData: (data: D) => Promise<void>;
6
7
  reader: ReturnType<HTTPAPICallExecutorResBody['getReader']>;
7
8
  }
8
9
  export declare class SSEStreamManager implements Worker<I, Promise<void>> {
9
10
  private static DEFAULT_ENCODING;
10
- exec({ encoding, onData, reader, }: I): Promise<void>;
11
+ exec({ abortController, encoding, onData, reader, }: I): Promise<void>;
11
12
  }
12
13
  export {};
@@ -11,10 +11,13 @@ import { isSSEError, parseDataLine, SSE_DATA_SEP, SSE_MSG_SEP } from './sse.js';
11
11
  let SSEStreamManager = class SSEStreamManager {
12
12
  static { SSEStreamManager_1 = this; }
13
13
  static DEFAULT_ENCODING = 'utf-8';
14
- async exec({ encoding = SSEStreamManager_1.DEFAULT_ENCODING, onData, reader, }) {
14
+ async exec({ abortController, encoding = SSEStreamManager_1.DEFAULT_ENCODING, onData, reader, }) {
15
15
  const decoder = new TextDecoder(encoding);
16
16
  let buffer = '';
17
17
  while (true) {
18
+ if (abortController.signal.aborted) {
19
+ return;
20
+ }
18
21
  const { done, value } = await reader.read();
19
22
  if (done) {
20
23
  return;
@@ -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