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.
- package/CHANGELOG.md +21 -0
- package/README.md +154 -2
- package/dist/esm/apps/Helper/src/lib/project.js +4 -4
- package/dist/esm/apps/Helper/src/ucds/TestAppUCD.d.ts +2 -1
- package/dist/esm/apps/Helper/src/ucds/TestAppUCD.js +8 -0
- package/dist/esm/convention.d.ts +3 -0
- package/dist/esm/convention.js +3 -0
- package/dist/esm/dt/DataTypes.d.ts +1 -2
- package/dist/esm/dt/base/TObject.js +1 -1
- package/dist/esm/i18n/index.d.ts +1 -1
- package/dist/esm/i18n/locales/de.d.ts +2 -0
- package/dist/esm/i18n/locales/de.js +54 -0
- package/dist/esm/i18n/locales/es.d.ts +2 -0
- package/dist/esm/i18n/locales/es.js +54 -0
- package/dist/esm/i18n/types.d.ts +3 -2
- package/dist/esm/index.babel.d.ts +1 -0
- package/dist/esm/index.babel.js +1 -0
- package/dist/esm/index.node-stricli-cli.d.ts +2 -0
- package/dist/esm/index.node-stricli-cli.js +2 -0
- package/dist/esm/index.react.d.ts +1 -1
- package/dist/esm/index.react.js +1 -1
- package/dist/esm/index.vite.d.ts +1 -1
- package/dist/esm/index.vite.js +1 -1
- package/dist/esm/index.webpack.d.ts +1 -0
- package/dist/esm/index.webpack.js +1 -0
- package/dist/esm/std/I18nManager.d.ts +12 -0
- package/dist/esm/std/JWTManager.d.ts +16 -1
- package/dist/esm/std/impl/JoseJWTManager.d.ts +3 -2
- package/dist/esm/std/impl/JoseJWTManager.js +4 -0
- package/dist/esm/std/impl/NodeFSManager.js +1 -1
- package/dist/esm/std/impl/SimpleHTTPAPICaller.js +4 -2
- package/dist/esm/std/impl/SimpleMapI18nManager.d.ts +6 -1
- package/dist/esm/std/impl/SimpleMapI18nManager.js +41 -12
- package/dist/esm/target/lib/client/consts.js +1 -0
- package/dist/esm/target/lib/react/UCPanel.d.ts +7 -8
- package/dist/esm/target/lib/react/useUC.js +11 -1
- package/dist/esm/target/lib/server/AuthenticationChecker.js +1 -1
- package/dist/esm/target/lib/server/PublicApiKeyChecker.js +1 -1
- package/dist/esm/target/lib/server/ServerManager.d.ts +1 -0
- package/dist/esm/target/lib/server/ServerRequestHandler.js +2 -2
- package/dist/esm/target/lib/server/consts.js +1 -0
- package/dist/esm/target/lib/server-express/funcs.js +5 -4
- package/dist/esm/target/lib/server-hono/funcs.js +2 -2
- package/dist/esm/target/lib/server-node/funcs.d.ts +2 -2
- package/dist/esm/target/lib/server-node/funcs.js +11 -1
- package/dist/esm/target/lib/server-node/types.d.ts +1 -0
- package/dist/esm/target/node-express-server/NodeExpressServerManager.d.ts +2 -2
- package/dist/esm/target/node-express-server/NodeExpressServerManager.js +2 -1
- package/dist/esm/target/node-hono-server/NodeHonoServerManager.d.ts +2 -2
- package/dist/esm/target/node-hono-server/NodeHonoServerManager.js +2 -1
- package/dist/esm/target/node-stricli-cli/NodeStricliCLIManager.d.ts +12 -0
- package/dist/esm/target/node-stricli-cli/NodeStricliCLIManager.js +118 -0
- package/dist/esm/testing/AppTester.js +4 -5
- package/dist/esm/testing/UCDefASTParser.d.ts +24 -6
- package/dist/esm/testing/impl/SimpleAppDocsEmitter.js +4 -5
- package/dist/esm/testing/impl/TypeScriptLibUCDefASTParser.js +38 -11
- package/dist/esm/testing/impl/VitestAppTestSuiteRunner.d.ts +1 -1
- package/dist/esm/testing/impl/VitestAppTestSuiteRunner.js +17 -2
- package/dist/esm/testing/impl/newNodeAppTester.js +3 -2
- package/dist/esm/testing/opts.js +1 -1
- package/dist/esm/testing/workers/AppTestSuiteRunner.d.ts +2 -0
- package/dist/esm/testing/workers/UCExecutor.js +1 -1
- package/dist/esm/testing/workers/checkers/AppI18nChecker.d.ts +8 -2
- package/dist/esm/testing/workers/checkers/AppI18nChecker.js +44 -2
- package/dist/esm/testing/workers/checkers/UCDefSourcesChecker.js +12 -12
- package/dist/esm/uc/impl/HTTPUCTransporter.js +2 -2
- package/dist/esm/uc/impl/KnexUCDataStore.js +2 -2
- package/dist/esm/uc/index.d.ts +0 -1
- package/dist/esm/uc/index.js +0 -1
- package/dist/esm/uc/workers/UCExecChecker.js +1 -1
- package/dist/esm/utils/bundling/babel/plugin.d.ts +2 -0
- package/dist/esm/utils/bundling/babel/plugin.js +38 -0
- package/dist/esm/utils/bundling/funcs.d.ts +6 -0
- package/dist/esm/utils/bundling/funcs.js +20 -0
- package/dist/esm/utils/bundling/typescript.d.ts +3 -0
- package/dist/esm/utils/bundling/typescript.js +61 -0
- package/dist/esm/utils/bundling/vite/plugin.d.ts +6 -0
- package/dist/esm/utils/bundling/vite/plugin.js +17 -0
- package/dist/esm/utils/bundling/webpack/loader.d.ts +2 -0
- package/dist/esm/utils/bundling/webpack/loader.js +12 -0
- package/dist/esm/utils/http/HTTPRequestBuilder.js +1 -1
- package/dist/esm/utils/http/NDJSONStreamManager.d.ts +2 -1
- package/dist/esm/utils/http/NDJSONStreamManager.js +4 -1
- package/dist/esm/utils/http/SSEStreamManager.d.ts +2 -1
- package/dist/esm/utils/http/SSEStreamManager.js +4 -1
- package/dist/esm/utils/ioc/bindCommon.js +1 -1
- package/dist/esm/utils/terminal/fmt.js +1 -1
- package/package.json +32 -10
- package/pnpm-workspace.yaml +1 -4
- package/tsconfig.build.examples.json +8 -0
- package/tsconfig.json +1 -0
- 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
|
|
103
|
+
const fields = type
|
|
104
|
+
.getProperties()
|
|
105
|
+
.map((p) => {
|
|
103
106
|
const field = {
|
|
104
107
|
err: null,
|
|
105
|
-
value:
|
|
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
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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(
|
|
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: '
|
|
22
|
-
jwt_manager_issuer: '
|
|
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);
|
package/dist/esm/testing/opts.js
CHANGED
|
@@ -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
|
}
|
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
97
|
-
if (
|
|
98
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
(
|
|
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
|
-
(
|
|
159
|
+
(type);
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
fillConfigForPG() {
|
package/dist/esm/uc/index.d.ts
CHANGED
|
@@ -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';
|
package/dist/esm/uc/index.js
CHANGED
|
@@ -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';
|
|
@@ -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,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,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,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
|
+
}
|
|
@@ -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
|