libmodulor 0.23.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 +17 -0
- package/README.md +154 -2
- package/dist/esm/apps/Helper/src/lib/project.js +3 -3
- 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.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/impl/NodeFSManager.js +1 -1
- package/dist/esm/std/impl/SimpleMapI18nManager.d.ts +6 -1
- package/dist/esm/std/impl/SimpleMapI18nManager.js +41 -12
- 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/ServerRequestHandler.js +2 -2
- package/dist/esm/target/lib/server-express/funcs.js +2 -2
- package/dist/esm/target/lib/server-hono/funcs.js +2 -2
- package/dist/esm/target/lib/server-node/funcs.js +1 -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/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/ioc/bindCommon.js +1 -1
- package/dist/esm/utils/terminal/fmt.js +1 -1
- package/package.json +30 -8
- package/pnpm-workspace.yaml +1 -4
- package/tsconfig.build.examples.json +8 -0
- package/tsconfig.json +1 -0
- package/vitest.config.ts +16 -0
|
@@ -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
|
+
}
|
|
@@ -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) {
|
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.
|
|
4
|
+
"version": "0.24.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,11 +96,18 @@
|
|
|
81
96
|
"lint:ci": "biome check"
|
|
82
97
|
},
|
|
83
98
|
"devDependencies": {
|
|
84
|
-
"@biomejs/biome": "^2.3.
|
|
99
|
+
"@biomejs/biome": "^2.3.8",
|
|
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.25",
|
|
106
|
+
"wrangler": "^4.51.0"
|
|
85
107
|
},
|
|
86
108
|
"peerDependencies": {
|
|
87
109
|
"@hono/node-server": "^1.19.6",
|
|
88
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
110
|
+
"@modelcontextprotocol/sdk": "^1.23.0",
|
|
89
111
|
"@stricli/core": "^1.2.4",
|
|
90
112
|
"buffer": "^6.0.3",
|
|
91
113
|
"cookie-parser": "^1.4.7",
|
|
@@ -93,14 +115,14 @@
|
|
|
93
115
|
"express-fileupload": "^1.5.2",
|
|
94
116
|
"fast-check": "^4.3.0",
|
|
95
117
|
"helmet": "^8.1.0",
|
|
96
|
-
"hono": "^4.10.
|
|
118
|
+
"hono": "^4.10.7",
|
|
97
119
|
"inversify": "^7.10.4",
|
|
98
|
-
"jose": "^6.1.
|
|
120
|
+
"jose": "^6.1.2",
|
|
99
121
|
"knex": "^3.1.0",
|
|
100
|
-
"next": "^15.5.
|
|
122
|
+
"next": "^15.5.7",
|
|
101
123
|
"pg": "^8.16.3",
|
|
102
|
-
"react": "^19.2.
|
|
103
|
-
"react-dom": "^19.2.
|
|
124
|
+
"react": "^19.2.1",
|
|
125
|
+
"react-dom": "^19.2.1",
|
|
104
126
|
"react-native": "^0.81.5",
|
|
105
127
|
"reflect-metadata": "^0.2.2",
|
|
106
128
|
"sqlite3": "^5.1.7",
|
package/pnpm-workspace.yaml
CHANGED
package/tsconfig.json
CHANGED
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { loadEnv } from 'vite';
|
|
2
|
+
import { defineConfig } from 'vitest/config';
|
|
3
|
+
|
|
4
|
+
export default defineConfig(({ mode }) => ({
|
|
5
|
+
test: {
|
|
6
|
+
coverage: {
|
|
7
|
+
exclude: ['src/apps/**/test', 'src/**/*.test.ts'],
|
|
8
|
+
include: ['src'],
|
|
9
|
+
reporter: ['html', 'lcov', 'text'],
|
|
10
|
+
reportOnFailure: false,
|
|
11
|
+
},
|
|
12
|
+
env: loadEnv(mode, process.cwd(), ''),
|
|
13
|
+
exclude: ['**/node_modules/**', '**/dist/**', '**/dist-examples/**'],
|
|
14
|
+
reporters: ['verbose'],
|
|
15
|
+
},
|
|
16
|
+
}));
|