libmodulor 0.5.0 → 0.6.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/.github/dependabot.yml +19 -0
- package/CHANGELOG.md +17 -0
- package/README.md +10 -4
- package/dist/esm/apps/Helper/src/i18n.js +4 -0
- package/dist/esm/apps/Helper/src/lib/project.d.ts +2 -0
- package/dist/esm/apps/Helper/src/lib/project.js +120 -0
- package/dist/esm/apps/Helper/src/manifest.d.ts +5 -0
- package/dist/esm/apps/Helper/src/manifest.js +5 -0
- package/dist/esm/apps/Helper/src/ucds/CreateProjectUCD.d.ts +15 -0
- package/dist/esm/apps/Helper/src/ucds/CreateProjectUCD.js +118 -0
- package/dist/esm/dt/index.d.ts +1 -1
- package/dist/esm/index.node.d.ts +1 -0
- package/dist/esm/index.node.js +1 -0
- package/dist/esm/index.react.d.ts +1 -1
- package/dist/esm/products/Helper/container.js +4 -0
- package/dist/esm/products/Helper/index.js +2 -0
- package/dist/esm/std/ShellCommandExecutor.d.ts +19 -0
- package/dist/esm/std/ShellCommandExecutor.js +1 -0
- package/dist/esm/std/impl/NodeSpawnShellCommandExecutor.d.ts +4 -0
- package/dist/esm/std/impl/NodeSpawnShellCommandExecutor.js +41 -0
- package/dist/esm/std/index.d.ts +1 -0
- package/dist/esm/std/index.js +1 -0
- package/dist/esm/target/lib/react/form.d.ts +26 -2
- package/dist/esm/target/lib/react/form.js +18 -1
- package/dist/esm/target/react-native-pure/UCForm.js +2 -2
- package/dist/esm/target/react-native-pure/UCFormField.d.ts +2 -9
- package/dist/esm/target/react-native-pure/UCFormField.js +9 -20
- package/dist/esm/target/react-native-pure/UCFormFieldControl.d.ts +3 -10
- package/dist/esm/target/react-native-pure/UCFormFieldControl.js +8 -8
- package/dist/esm/target/react-native-pure/UCFormFieldDesc.d.ts +2 -5
- package/dist/esm/target/react-native-pure/UCFormFieldDesc.js +2 -2
- package/dist/esm/target/react-native-pure/UCFormFieldErr.d.ts +2 -6
- package/dist/esm/target/react-native-pure/UCFormFieldLabel.d.ts +2 -5
- package/dist/esm/target/react-native-pure/UCFormFieldLabel.js +2 -2
- package/dist/esm/target/react-native-pure/UCFormSubmitControl.d.ts +2 -7
- package/dist/esm/target/react-native-pure/UCFormSubmitControl.js +1 -1
- package/dist/esm/target/react-web-pure/UCForm.js +1 -1
- package/dist/esm/target/react-web-pure/UCFormField.d.ts +2 -9
- package/dist/esm/target/react-web-pure/UCFormField.js +9 -20
- package/dist/esm/target/react-web-pure/UCFormFieldControl.d.ts +3 -10
- package/dist/esm/target/react-web-pure/UCFormFieldControl.js +20 -5
- package/dist/esm/target/react-web-pure/UCFormFieldDesc.d.ts +2 -5
- package/dist/esm/target/react-web-pure/UCFormFieldDesc.js +2 -2
- package/dist/esm/target/react-web-pure/UCFormFieldErr.d.ts +2 -6
- package/dist/esm/target/react-web-pure/UCFormFieldLabel.d.ts +2 -5
- package/dist/esm/target/react-web-pure/UCFormFieldLabel.js +3 -3
- package/dist/esm/target/react-web-pure/UCFormSubmitControl.d.ts +2 -4
- package/dist/esm/target/react-web-pure/UCFormSubmitControl.js +1 -1
- package/package.json +8 -9
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# To get started with Dependabot version updates, you'll need to specify which
|
|
2
|
+
# package ecosystems to update and where the package manifests are located.
|
|
3
|
+
# Please see the documentation for all configuration options:
|
|
4
|
+
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
|
5
|
+
|
|
6
|
+
version: 2
|
|
7
|
+
updates:
|
|
8
|
+
- package-ecosystem: "npm"
|
|
9
|
+
directory: "/"
|
|
10
|
+
schedule:
|
|
11
|
+
interval: "weekly"
|
|
12
|
+
ignore:
|
|
13
|
+
- dependency-name: "inversify"
|
|
14
|
+
versions: ["7.x"]
|
|
15
|
+
groups:
|
|
16
|
+
dev:
|
|
17
|
+
dependency-type: "development"
|
|
18
|
+
prod:
|
|
19
|
+
dependency-type: "production"
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## v0.6.0 (2025-02-28)
|
|
4
|
+
|
|
5
|
+
**BREAKING**
|
|
6
|
+
|
|
7
|
+
- Extract common react elements on web and rn, renaming some of the props : check the new props names and the new `validateFormField` to simplify your overrides
|
|
8
|
+
- Remove `helper` from the exports map : it makes no sense to expose it as it is an executable (see `npx libmodulor` below)
|
|
9
|
+
|
|
10
|
+
**Added**
|
|
11
|
+
|
|
12
|
+
- Introduce the `npx libmodulor CreateProject` command
|
|
13
|
+
- Introduce `select` to target `react-web-pure` : it now renders an HTML `select` when the UC input field `hasOptions()`
|
|
14
|
+
|
|
15
|
+
**Misc**
|
|
16
|
+
|
|
17
|
+
- Bump `react` to `19.0.0`
|
|
18
|
+
- Add a new "Style the web Target" tutorial step showing how to use `tailwindcss` and `daisyUI` to provide custom components
|
|
19
|
+
|
|
3
20
|
## v0.5.0 (2025-02-24)
|
|
4
21
|
|
|
5
22
|
**BREAKING**
|
package/README.md
CHANGED
|
@@ -27,11 +27,17 @@ Applications created with `libmodulor` have **6 main properties** :
|
|
|
27
27
|
|
|
28
28
|
## 🚀 Getting Started
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
If you're discovering `libmodulor`, we recommend reading the [📖 Introduction](https://github.com/c100k/libmodulor/blob/v0.6.0/docs/Introduction.md) first. It will give you an overview of what `libmodulor` is and how it works.
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
If you want to learn by doing, you can follow the [🚀 Tutorial](https://github.com/c100k/libmodulor/blob/v0.6.0/docs/Tutorial.md). It contains multiple steps showing you the basics of `libmodulor`. We'll build a small Trading app that will allow us to buy an asset from `curl`, a SPA, a CLI, Claude Desktop, an Android mobile app and an iOS mobile app !
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
If you're felling adventurous, create a project and start building your own application, with your own apps, use cases, products, targets :
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
npx libmodulor CreateProject --outPath ~/Downloads --projectName libmodulor-projx
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Finally, for more advanced uses, check out the [📜 Guides](https://github.com/c100k/libmodulor/blob/v0.6.0/docs/Guides.md).
|
|
35
41
|
|
|
36
42
|
## 👨💻 Contribute
|
|
37
43
|
|
|
@@ -39,4 +45,4 @@ If you think you can help in any way, feel free to contact me (cf. `author` in `
|
|
|
39
45
|
|
|
40
46
|
## ⚖️ License
|
|
41
47
|
|
|
42
|
-
[LGPL-3.0](
|
|
48
|
+
[LGPL-3.0](https://github.com/c100k/libmodulor/blob/v0.6.0/LICENSE)
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export const I18n = {
|
|
2
2
|
en: {
|
|
3
3
|
err_unknown_app: 'Unknown app : {{appPath}}',
|
|
4
|
+
uc_CreateProject_desc: 'Create a project by initializing a git repo, creating basic config files and installing the required dependencies',
|
|
5
|
+
uc_CreateProject_label: 'Create a project',
|
|
4
6
|
uc_DeleteGeneratedAppsTests_desc: 'Delete the automated test suite generated for each app',
|
|
5
7
|
uc_DeleteGeneratedAppsTests_label: 'Delete generated apps tests',
|
|
6
8
|
uc_GenerateAppsTests_desc: 'Generate an automated test suite for each app',
|
|
@@ -9,6 +11,8 @@ export const I18n = {
|
|
|
9
11
|
uc_TestApp_label: 'Test app',
|
|
10
12
|
ucif_appPath_desc: 'The path of the app',
|
|
11
13
|
ucif_appsPath_desc: 'The path to the directory containing all the apps',
|
|
14
|
+
ucif_projectName_desc: "Name of the project conforming to the package.json's spec (i.e. a-z, 0-9, -)",
|
|
15
|
+
ucif_outPath_desc: 'Path to a directory where to create the project. Do not include the project name in it. It is created recursively if missing.',
|
|
12
16
|
ucif_monkeyTestingTimeoutInMs_desc: 'These tests can take longer than the usual default of 5000ms because they try lots of possibilities',
|
|
13
17
|
ucif_depsMapping_desc: 'The mapping of dependencies in case some of them need a specific pattern (e.g. one directory above the default)',
|
|
14
18
|
ucif_serverPortRangeStart_desc: 'The port number to start with when generating the server to test (incremented by 1) for each app',
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
const GITIGNORE = `coverage
|
|
2
|
+
dist
|
|
3
|
+
node_modules
|
|
4
|
+
src/apps/**/test/reports
|
|
5
|
+
src/apps/**/test/*.test.ts
|
|
6
|
+
src/products/**/rn/.expo
|
|
7
|
+
.env
|
|
8
|
+
`;
|
|
9
|
+
const BIOME_JSON = `{
|
|
10
|
+
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
|
|
11
|
+
"files": {
|
|
12
|
+
"ignore": ["coverage", "dist", "node_modules"],
|
|
13
|
+
"ignoreUnknown": true
|
|
14
|
+
},
|
|
15
|
+
"formatter": {
|
|
16
|
+
"indentStyle": "space",
|
|
17
|
+
"indentWidth": 4
|
|
18
|
+
},
|
|
19
|
+
"javascript": {
|
|
20
|
+
"formatter": {
|
|
21
|
+
"quoteStyle": "single"
|
|
22
|
+
},
|
|
23
|
+
"parser": {
|
|
24
|
+
"unsafeParameterDecoratorsEnabled": true
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
`;
|
|
29
|
+
const PACKAGE_JSON = (name) => `{
|
|
30
|
+
"name": "${name}",
|
|
31
|
+
"version": "0.1.0",
|
|
32
|
+
"type": "module",
|
|
33
|
+
"private": true,
|
|
34
|
+
"scripts": {
|
|
35
|
+
"lint": "biome check --write .",
|
|
36
|
+
"test": "tsc && vitest run --passWithNoTests"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"inversify": "^6.2.2",
|
|
40
|
+
"libmodulor": "^0.5.0",
|
|
41
|
+
"reflect-metadata": "^0.2.2"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@biomejs/biome": "^1.9.4",
|
|
45
|
+
"@types/node": "^22.13.5",
|
|
46
|
+
"@vitest/coverage-v8": "^3.0.7",
|
|
47
|
+
"buffer": "^6.0.3",
|
|
48
|
+
"cookie-parser": "^1.4.7",
|
|
49
|
+
"express": "^4.21.2",
|
|
50
|
+
"express-fileupload": "^1.5.1",
|
|
51
|
+
"fast-check": "^3.23.2",
|
|
52
|
+
"helmet": "^8.0.0",
|
|
53
|
+
"jose": "^6.0.8",
|
|
54
|
+
"typescript": "^5.7.3",
|
|
55
|
+
"vite": "^6.2.0",
|
|
56
|
+
"vitest": "^3.0.7"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
`;
|
|
60
|
+
const README_MD = (name) => `# ${name}
|
|
61
|
+
|
|
62
|
+
🚀🚀🚀
|
|
63
|
+
`;
|
|
64
|
+
const TSCONFIG_JSON = `{
|
|
65
|
+
"compilerOptions": {
|
|
66
|
+
"allowSyntheticDefaultImports": true,
|
|
67
|
+
"declaration": true,
|
|
68
|
+
"lib": ["dom", "esnext"],
|
|
69
|
+
"module": "NodeNext",
|
|
70
|
+
"moduleResolution": "NodeNext",
|
|
71
|
+
"noEmit": true,
|
|
72
|
+
"removeComments": true,
|
|
73
|
+
"skipLibCheck": true,
|
|
74
|
+
"sourceMap": true,
|
|
75
|
+
"target": "ESNext",
|
|
76
|
+
|
|
77
|
+
"strict": true,
|
|
78
|
+
"allowUnreachableCode": false,
|
|
79
|
+
"allowUnusedLabels": false,
|
|
80
|
+
"exactOptionalPropertyTypes": true,
|
|
81
|
+
"noFallthroughCasesInSwitch": true,
|
|
82
|
+
"noPropertyAccessFromIndexSignature": true,
|
|
83
|
+
"noImplicitOverride": true,
|
|
84
|
+
"noImplicitReturns": true,
|
|
85
|
+
"noUncheckedIndexedAccess": true,
|
|
86
|
+
"noUnusedLocals": true,
|
|
87
|
+
"noUnusedParameters": true,
|
|
88
|
+
"verbatimModuleSyntax": true,
|
|
89
|
+
|
|
90
|
+
"emitDecoratorMetadata": true,
|
|
91
|
+
"experimentalDecorators": true,
|
|
92
|
+
|
|
93
|
+
"jsx": "react"
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
`;
|
|
97
|
+
const VITEST_CONFIG_TS = `import { defineConfig } from 'vitest/config';
|
|
98
|
+
|
|
99
|
+
export default defineConfig({
|
|
100
|
+
test: {
|
|
101
|
+
coverage: {
|
|
102
|
+
enabled: true,
|
|
103
|
+
exclude: ['src/apps/**/test', 'src/**/*.test.ts'],
|
|
104
|
+
include: ['src'],
|
|
105
|
+
reporter: ['html', 'lcov', 'text'],
|
|
106
|
+
},
|
|
107
|
+
reporters: ['verbose'],
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
`;
|
|
111
|
+
export function projectFiles(name) {
|
|
112
|
+
return new Map([
|
|
113
|
+
['.gitignore', GITIGNORE],
|
|
114
|
+
['biome.json', BIOME_JSON],
|
|
115
|
+
['package.json', PACKAGE_JSON(name)],
|
|
116
|
+
['README.md', README_MD(name)],
|
|
117
|
+
['tsconfig.json', TSCONFIG_JSON],
|
|
118
|
+
['vitest.config.ts', VITEST_CONFIG_TS],
|
|
119
|
+
]);
|
|
120
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type DirPath, type Slug } from '../../../../dt/index.js';
|
|
2
|
+
import type { FSManager, Logger, ShellCommandExecutor } from '../../../../std/index.js';
|
|
3
|
+
import { type UCDef, type UCInput, type UCInputFieldValue, type UCMain, type UCMainInput } from '../../../../uc/index.js';
|
|
4
|
+
export interface CreateProjectInput extends UCInput {
|
|
5
|
+
outPath: UCInputFieldValue<DirPath>;
|
|
6
|
+
projectName: UCInputFieldValue<Slug>;
|
|
7
|
+
}
|
|
8
|
+
export declare class CreateProjectClientMain implements UCMain<CreateProjectInput> {
|
|
9
|
+
private fsManager;
|
|
10
|
+
private logger;
|
|
11
|
+
private shellCommandExecutor;
|
|
12
|
+
constructor(fsManager: FSManager, logger: Logger, shellCommandExecutor: ShellCommandExecutor);
|
|
13
|
+
exec({ uc }: UCMainInput<CreateProjectInput>): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
export declare const CreateProjectUCD: UCDef<CreateProjectInput>;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
|
+
};
|
|
13
|
+
import { inject, injectable } from 'inversify';
|
|
14
|
+
import { APPS_ROOT_PATH, PRODUCTS_ROOT_PATH } from '../../../../convention.js';
|
|
15
|
+
import { TDirPath, TSlug, } from '../../../../dt/index.js';
|
|
16
|
+
import { EverybodyUCPolicy, } from '../../../../uc/index.js';
|
|
17
|
+
import { projectFiles } from '../lib/project.js';
|
|
18
|
+
import { Manifest } from '../manifest.js';
|
|
19
|
+
let CreateProjectClientMain = class CreateProjectClientMain {
|
|
20
|
+
fsManager;
|
|
21
|
+
logger;
|
|
22
|
+
shellCommandExecutor;
|
|
23
|
+
constructor(fsManager, logger, shellCommandExecutor) {
|
|
24
|
+
this.fsManager = fsManager;
|
|
25
|
+
this.logger = logger;
|
|
26
|
+
this.shellCommandExecutor = shellCommandExecutor;
|
|
27
|
+
}
|
|
28
|
+
async exec({ uc }) {
|
|
29
|
+
const outPath = uc.reqVal0('outPath');
|
|
30
|
+
const projectName = uc.reqVal0('projectName');
|
|
31
|
+
const cwd = this.fsManager.path(outPath, projectName);
|
|
32
|
+
this.logger.info('Creating root dir : %s', cwd);
|
|
33
|
+
await this.fsManager.mkdir(cwd, { recursive: true });
|
|
34
|
+
this.logger.info('Initializing git repository');
|
|
35
|
+
await this.shellCommandExecutor.exec({
|
|
36
|
+
bin: 'git',
|
|
37
|
+
opts: { args: ['init'], cwd },
|
|
38
|
+
});
|
|
39
|
+
this.logger.info('Creating config files');
|
|
40
|
+
const files = projectFiles(projectName);
|
|
41
|
+
for await (const [fileName, content] of files) {
|
|
42
|
+
const path = this.fsManager.path(cwd, fileName);
|
|
43
|
+
await this.fsManager.touch(path, content);
|
|
44
|
+
}
|
|
45
|
+
const dirs = [APPS_ROOT_PATH, PRODUCTS_ROOT_PATH];
|
|
46
|
+
this.logger.info('Creating apps and products directories');
|
|
47
|
+
for await (const dirPath of dirs) {
|
|
48
|
+
const path = this.fsManager.path(cwd, ...dirPath);
|
|
49
|
+
await this.fsManager.mkdir(path, { recursive: true });
|
|
50
|
+
await this.fsManager.touch(this.fsManager.path(path, '.gitkeep'), '');
|
|
51
|
+
}
|
|
52
|
+
this.logger.info('Installing dependencies');
|
|
53
|
+
await this.shellCommandExecutor.exec({
|
|
54
|
+
bin: 'yarn',
|
|
55
|
+
opts: { args: ['install'], cwd },
|
|
56
|
+
});
|
|
57
|
+
this.logger.info('Committing');
|
|
58
|
+
const cmdArgs = [
|
|
59
|
+
['branch', '-M', 'master'],
|
|
60
|
+
['add', '.'],
|
|
61
|
+
['commit', '-am', '"chore: initial commit"'],
|
|
62
|
+
];
|
|
63
|
+
for await (const args of cmdArgs) {
|
|
64
|
+
await this.shellCommandExecutor.exec({
|
|
65
|
+
bin: 'git',
|
|
66
|
+
opts: { args, cwd },
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
const devCmds = ['lint', 'test'];
|
|
70
|
+
for await (const cmd of devCmds) {
|
|
71
|
+
this.logger.info('Testing dev command : yarn %s', cmd);
|
|
72
|
+
await this.shellCommandExecutor.exec({
|
|
73
|
+
bin: 'yarn',
|
|
74
|
+
opts: { args: [cmd], cwd },
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
this.logger.info('Done ! Project ready ! ✅ 🚀');
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
CreateProjectClientMain = __decorate([
|
|
81
|
+
injectable(),
|
|
82
|
+
__param(0, inject('FSManager')),
|
|
83
|
+
__param(1, inject('Logger')),
|
|
84
|
+
__param(2, inject('ShellCommandExecutor')),
|
|
85
|
+
__metadata("design:paramtypes", [Object, Object, Object])
|
|
86
|
+
], CreateProjectClientMain);
|
|
87
|
+
export { CreateProjectClientMain };
|
|
88
|
+
export const CreateProjectUCD = {
|
|
89
|
+
ext: {
|
|
90
|
+
cmd: {
|
|
91
|
+
mountAt: 'CreateProject',
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
io: {
|
|
95
|
+
i: {
|
|
96
|
+
fields: {
|
|
97
|
+
outPath: {
|
|
98
|
+
cardinality: {
|
|
99
|
+
min: 0,
|
|
100
|
+
},
|
|
101
|
+
type: new TDirPath()
|
|
102
|
+
.setDefaultValue('./')
|
|
103
|
+
.setExamples([['~', 'Desktop'].join('/')]),
|
|
104
|
+
},
|
|
105
|
+
projectName: {
|
|
106
|
+
type: new TSlug(),
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
lifecycle: {
|
|
112
|
+
client: {
|
|
113
|
+
main: CreateProjectClientMain,
|
|
114
|
+
policy: EverybodyUCPolicy,
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
metadata: Manifest.ucReg.CreateProject,
|
|
118
|
+
};
|
package/dist/esm/dt/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { TInt, type TIntConstraints } from './base/TInt.js';
|
|
|
4
4
|
export { TNumber, type TNumberConstraints } from './base/TNumber.js';
|
|
5
5
|
export { TObject, type TObjectConstraints, TObjectShapeValidationStrategy, } from './base/TObject.js';
|
|
6
6
|
export { TString, type TStringConstraints } from './base/TString.js';
|
|
7
|
-
export { TUInt, type TUIntConstraints } from './base/TUInt.js';
|
|
7
|
+
export { TUInt, type TUIntConstraints, type UInt } from './base/TUInt.js';
|
|
8
8
|
export { type Address, TAddress } from './final/TAddress.js';
|
|
9
9
|
export { type Amount, TAmount } from './final/TAmount.js';
|
|
10
10
|
export { type ApiKey, TApiKey } from './final/TApiKey.js';
|
package/dist/esm/index.node.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export { NodeFormDataBuilder } from './std/impl/NodeFormDataBuilder.js';
|
|
|
6
6
|
export { NodeFSManager } from './std/impl/NodeFSManager.js';
|
|
7
7
|
export { NodeHTTPAPICallExecutorAgentBuilder } from './std/impl/NodeHTTPAPICallExecutorAgentBuilder.js';
|
|
8
8
|
export { NodePromptManager } from './std/impl/NodePromptManager.js';
|
|
9
|
+
export { NodeSpawnShellCommandExecutor } from './std/impl/NodeSpawnShellCommandExecutor.js';
|
|
9
10
|
export { NodeCoreCLIManager } from './target/node-core-cli/NodeCoreCLIManager.js';
|
|
10
11
|
export { NodeExpressServerManager } from './target/node-express-server/NodeExpressServerManager.js';
|
|
11
12
|
export { bindNodeCLI } from './utils/ioc/bindNodeCLI.js';
|
package/dist/esm/index.node.js
CHANGED
|
@@ -6,6 +6,7 @@ export { NodeFormDataBuilder } from './std/impl/NodeFormDataBuilder.js';
|
|
|
6
6
|
export { NodeFSManager } from './std/impl/NodeFSManager.js';
|
|
7
7
|
export { NodeHTTPAPICallExecutorAgentBuilder } from './std/impl/NodeHTTPAPICallExecutorAgentBuilder.js';
|
|
8
8
|
export { NodePromptManager } from './std/impl/NodePromptManager.js';
|
|
9
|
+
export { NodeSpawnShellCommandExecutor } from './std/impl/NodeSpawnShellCommandExecutor.js';
|
|
9
10
|
export { NodeCoreCLIManager } from './target/node-core-cli/NodeCoreCLIManager.js';
|
|
10
11
|
export { NodeExpressServerManager } from './target/node-express-server/NodeExpressServerManager.js';
|
|
11
12
|
export { bindNodeCLI } from './utils/ioc/bindNodeCLI.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { DIContext, useDIContext, DIContextProvider, type DIContextT, } from './target/lib/react/DIContextProvider.js';
|
|
2
|
-
export type { UCFormFieldControlOnChange, UCFormProps, RenderUCForm, } from './target/lib/react/form.js';
|
|
2
|
+
export type { UCFormFieldControlOnChange, UCFormFieldControlProps, UCFormFieldDescProps, UCFormFieldElement, UCFormFieldErrProps, UCFormFieldLabelProps, UCFormFieldProps, UCFormProps, UCFormSubmitControlProps, UC_FORM_FIELD_ELEMENTS, RenderUCForm, validateFormField, } from './target/lib/react/form.js';
|
|
3
3
|
export type { UCPanelCtx, UCPanelOnDone, UCPanelOnError, UCPanelOnInit, UCPanelOnStartSubmitting, UCPanelOnSubmit, UCPanelState, } from './target/lib/react/panel.js';
|
|
4
4
|
export type { UCEntrypointTouchableProps, RenderUCEntrypointTouchable, RenderUCExecTouchable, UCExecTouchableProps, } from './target/lib/react/touchable.js';
|
|
5
5
|
export { UCContainer } from './target/lib/react/UCContainer.js';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Container } from 'inversify';
|
|
2
|
+
import { NodeSpawnShellCommandExecutor } from '../../std/impl/NodeSpawnShellCommandExecutor.js';
|
|
2
3
|
import { VitestAppTestSuiteEmitter } from '../../testing/impl/VitestAppTestSuiteEmitter.js';
|
|
3
4
|
import { VitestAppTestSuiteRunner } from '../../testing/impl/VitestAppTestSuiteRunner.js';
|
|
4
5
|
import { CONTAINER_OPTS } from '../../utils/index.js';
|
|
@@ -19,4 +20,7 @@ container
|
|
|
19
20
|
container
|
|
20
21
|
.bind('AppTestSuiteRunner')
|
|
21
22
|
.to(VitestAppTestSuiteRunner);
|
|
23
|
+
container
|
|
24
|
+
.bind('ShellCommandExecutor')
|
|
25
|
+
.to(NodeSpawnShellCommandExecutor);
|
|
22
26
|
export default container;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { FilePath } from '../dt/index.js';
|
|
2
|
+
import type { Worker } from './Worker.js';
|
|
3
|
+
export type ShellCommandExecutorCommandArg = string;
|
|
4
|
+
export type ShellCommandExecutorCommandBin = 'docker' | 'file' | 'git' | 'open' | 'ssh-keygen' | 'ssh-keyscan' | 'unzip' | 'yarn' | 'zip' | (string & {});
|
|
5
|
+
export type ShellCommandExecutorEnv = Record<string, string>;
|
|
6
|
+
export type ShellCommandExecutorInstruction = string;
|
|
7
|
+
export type ShellCommandExecutorScript = string;
|
|
8
|
+
export type ShellCommandExecutorShebang = '#!/bin/bash';
|
|
9
|
+
export interface ShellCommandExecutorInput {
|
|
10
|
+
bin: ShellCommandExecutorCommandBin;
|
|
11
|
+
opts?: {
|
|
12
|
+
args?: ShellCommandExecutorCommandArg[];
|
|
13
|
+
cwd?: FilePath;
|
|
14
|
+
env?: ShellCommandExecutorEnv;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export type ShellCommandExecutorOutput = string;
|
|
18
|
+
export interface ShellCommandExecutor extends Worker<ShellCommandExecutorInput, Promise<ShellCommandExecutorOutput>> {
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ShellCommandExecutor, ShellCommandExecutorInput, ShellCommandExecutorOutput } from '../ShellCommandExecutor.js';
|
|
2
|
+
export declare class NodeSpawnShellCommandExecutor implements ShellCommandExecutor {
|
|
3
|
+
exec({ bin, opts, }: ShellCommandExecutorInput): Promise<ShellCommandExecutorOutput>;
|
|
4
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { spawn } from 'node:child_process';
|
|
8
|
+
import { injectable } from 'inversify';
|
|
9
|
+
let NodeSpawnShellCommandExecutor = class NodeSpawnShellCommandExecutor {
|
|
10
|
+
async exec({ bin, opts, }) {
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
let stderr = '';
|
|
13
|
+
let stdout = '';
|
|
14
|
+
const proc = spawn(bin, opts?.args || [], {
|
|
15
|
+
cwd: opts?.cwd,
|
|
16
|
+
env: opts?.env,
|
|
17
|
+
});
|
|
18
|
+
proc.stderr.on('data', (chunk) => {
|
|
19
|
+
stderr += chunk;
|
|
20
|
+
});
|
|
21
|
+
proc.stdout.on('data', (chunk) => {
|
|
22
|
+
stdout += chunk;
|
|
23
|
+
});
|
|
24
|
+
proc.stdout.on('error', (err) => {
|
|
25
|
+
reject(err);
|
|
26
|
+
});
|
|
27
|
+
proc.on('close', (code, signal) => {
|
|
28
|
+
if (code === 0) {
|
|
29
|
+
resolve(stdout);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
reject(new Error(`Command failed with exit code (${code}), signal (${signal}), stderr (${stderr}) stdout (${stdout})`));
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
NodeSpawnShellCommandExecutor = __decorate([
|
|
39
|
+
injectable()
|
|
40
|
+
], NodeSpawnShellCommandExecutor);
|
|
41
|
+
export { NodeSpawnShellCommandExecutor };
|
package/dist/esm/std/index.d.ts
CHANGED
package/dist/esm/std/index.js
CHANGED
|
@@ -1,10 +1,34 @@
|
|
|
1
1
|
import type { ReactElement } from 'react';
|
|
2
|
-
import type { DataType } from '../../../dt/index.js';
|
|
2
|
+
import type { DataType, ErrorMessage } from '../../../dt/index.js';
|
|
3
|
+
import type { I18nManager } from '../../../std/index.js';
|
|
3
4
|
import type { UCInput, UCInputField, UCInputFieldChangeOperator, UCInputFieldValue, UCOPIBase } from '../../../uc/index.js';
|
|
4
|
-
import type { UCPanelCtx, UCPanelOnSubmit } from './panel.js';
|
|
5
|
+
import type { UCPanelCtx, UCPanelOnSubmit, UCPanelState } from './panel.js';
|
|
5
6
|
export type UCFormFieldControlOnChange<T extends DataType = DataType> = (f: UCInputField<T>, op: UCInputFieldChangeOperator, v: UCInputFieldValue<T>) => void;
|
|
7
|
+
export type UCFormFieldControlProps<T extends DataType> = UCPanelState & {
|
|
8
|
+
errMsg?: ErrorMessage | null;
|
|
9
|
+
f: UCInputField<T>;
|
|
10
|
+
onChange: UCFormFieldControlOnChange<T>;
|
|
11
|
+
};
|
|
12
|
+
export type UCFormFieldDescProps<T extends DataType> = {
|
|
13
|
+
f: UCInputField<T>;
|
|
14
|
+
};
|
|
15
|
+
export type UCFormFieldErrProps = {
|
|
16
|
+
errMsg?: ErrorMessage | null;
|
|
17
|
+
};
|
|
18
|
+
export type UCFormFieldLabelProps<T extends DataType> = {
|
|
19
|
+
f: UCInputField<T>;
|
|
20
|
+
};
|
|
21
|
+
export declare const UC_FORM_FIELD_ELEMENTS: readonly ["control", "desc", "err", "label"];
|
|
22
|
+
export type UCFormFieldElement = (typeof UC_FORM_FIELD_ELEMENTS)[number];
|
|
23
|
+
export type UCFormFieldProps<T extends DataType> = UCFormFieldControlProps<T> & {
|
|
24
|
+
only?: UCFormFieldElement[];
|
|
25
|
+
};
|
|
6
26
|
export type UCFormProps<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = UCPanelCtx<I, OPI0, OPI1> & {
|
|
7
27
|
onChange: UCFormFieldControlOnChange;
|
|
8
28
|
onSubmit: UCPanelOnSubmit;
|
|
9
29
|
};
|
|
30
|
+
export type UCFormSubmitControlProps<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = UCPanelCtx<I, OPI0, OPI1> & {
|
|
31
|
+
onPress?: () => Promise<void>;
|
|
32
|
+
};
|
|
10
33
|
export type RenderUCForm<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = (props: UCFormProps<I, OPI0, OPI1>) => ReactElement;
|
|
34
|
+
export declare function validateFormField<T extends DataType = DataType>(i18nManager: I18nManager, f: UCInputField<T>, v: UCInputFieldValue<T>): ErrorMessage | null;
|
|
@@ -1 +1,18 @@
|
|
|
1
|
-
export
|
|
1
|
+
export const UC_FORM_FIELD_ELEMENTS = [
|
|
2
|
+
'control',
|
|
3
|
+
'desc',
|
|
4
|
+
'err',
|
|
5
|
+
'label',
|
|
6
|
+
];
|
|
7
|
+
export function validateFormField(i18nManager, f, v) {
|
|
8
|
+
const vArr = Array.isArray(v) ? v : [v];
|
|
9
|
+
for (const vv of vArr) {
|
|
10
|
+
const validation = f.def.type.assign(vv).validate();
|
|
11
|
+
const violation = validation.get();
|
|
12
|
+
if (violation) {
|
|
13
|
+
const [key, expected] = violation;
|
|
14
|
+
return i18nManager.t(key, { vars: { expected } });
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import React, {} from 'react';
|
|
2
2
|
import { View } from 'react-native';
|
|
3
3
|
import { UCFormField } from './UCFormField.js';
|
|
4
|
-
import { UCFormSubmitControl
|
|
4
|
+
import { UCFormSubmitControl } from './UCFormSubmitControl.js';
|
|
5
5
|
export function UCForm({ disabled, execState, onChange, onSubmit, uc, }) {
|
|
6
6
|
const onPress = async () => {
|
|
7
7
|
await onSubmit();
|
|
8
8
|
};
|
|
9
9
|
return (React.createElement(View, null,
|
|
10
10
|
uc.inputFieldsForForm().map((f) => (React.createElement(View, { key: f.key },
|
|
11
|
-
React.createElement(UCFormField, { disabled: disabled, execState: execState,
|
|
11
|
+
React.createElement(UCFormField, { disabled: disabled, execState: execState, f: f, onChange: onChange })))),
|
|
12
12
|
React.createElement(UCFormSubmitControl, { execState: execState, disabled: disabled, onPress: onPress, uc: uc })));
|
|
13
13
|
}
|
|
@@ -1,11 +1,4 @@
|
|
|
1
1
|
import { type ReactElement } from 'react';
|
|
2
2
|
import type { DataType } from '../../dt/index.js';
|
|
3
|
-
import { type
|
|
4
|
-
|
|
5
|
-
declare const ELEMENTS: readonly ["control", "desc", "err", "label"];
|
|
6
|
-
type Element = (typeof ELEMENTS)[number];
|
|
7
|
-
type Props<T extends DataType> = FormFieldControlProps<T> & FormFieldLabelProps<T> & {
|
|
8
|
-
only?: Element[];
|
|
9
|
-
};
|
|
10
|
-
export declare function UCFormField<T extends DataType>({ disabled, execState, field, onChange: onChangeBase, only, }: Props<T>): ReactElement;
|
|
11
|
-
export {};
|
|
3
|
+
import { type UCFormFieldProps } from '../lib/react/form.js';
|
|
4
|
+
export declare function UCFormField<T extends DataType>({ disabled, execState, f, onChange: onChangeBase, only, }: UCFormFieldProps<T>): ReactElement;
|
|
@@ -1,32 +1,21 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
2
|
import { useDIContext } from '../lib/react/DIContextProvider.js';
|
|
3
|
-
import {
|
|
3
|
+
import { UC_FORM_FIELD_ELEMENTS, validateFormField, } from '../lib/react/form.js';
|
|
4
|
+
import { UCFormFieldControl } from './UCFormFieldControl.js';
|
|
4
5
|
import { UCFormFieldDesc } from './UCFormFieldDesc.js';
|
|
5
6
|
import { UCFormFieldErr } from './UCFormFieldErr.js';
|
|
6
|
-
import { UCFormFieldLabel
|
|
7
|
-
|
|
8
|
-
export function UCFormField({ disabled, execState, field, onChange: onChangeBase, only, }) {
|
|
7
|
+
import { UCFormFieldLabel } from './UCFormFieldLabel.js';
|
|
8
|
+
export function UCFormField({ disabled, execState, f, onChange: onChangeBase, only, }) {
|
|
9
9
|
const { i18nManager } = useDIContext();
|
|
10
|
-
const { type } = field.def;
|
|
11
10
|
const [errMsg, setErrMsg] = useState(null);
|
|
12
|
-
const elements = only ?? ELEMENTS;
|
|
13
11
|
const onChange = (f, op, v) => {
|
|
14
|
-
setErrMsg(
|
|
15
|
-
const vArr = Array.isArray(v) ? v : [v];
|
|
16
|
-
for (const vv of vArr) {
|
|
17
|
-
const validation = type.assign(vv).validate();
|
|
18
|
-
const violation = validation.get();
|
|
19
|
-
if (violation) {
|
|
20
|
-
const [key, expected] = violation;
|
|
21
|
-
setErrMsg(i18nManager.t(key, { vars: { expected } }));
|
|
22
|
-
break;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
12
|
+
setErrMsg(validateFormField(i18nManager, f, v));
|
|
25
13
|
onChangeBase(f, op, v);
|
|
26
14
|
};
|
|
15
|
+
const elements = only ?? UC_FORM_FIELD_ELEMENTS;
|
|
27
16
|
return (React.createElement(React.Fragment, null,
|
|
28
|
-
elements.includes('label') && React.createElement(UCFormFieldLabel, {
|
|
29
|
-
elements.includes('control') && (React.createElement(UCFormFieldControl, { disabled: disabled, execState: execState,
|
|
17
|
+
elements.includes('label') && React.createElement(UCFormFieldLabel, { f: f }),
|
|
18
|
+
elements.includes('control') && (React.createElement(UCFormFieldControl, { disabled: disabled, execState: execState, f: f, onChange: onChange })),
|
|
30
19
|
elements.includes('err') && errMsg && (React.createElement(UCFormFieldErr, { errMsg: errMsg })),
|
|
31
|
-
elements.includes('desc') && React.createElement(UCFormFieldDesc, {
|
|
20
|
+
elements.includes('desc') && React.createElement(UCFormFieldDesc, { f: f })));
|
|
32
21
|
}
|
|
@@ -1,11 +1,4 @@
|
|
|
1
1
|
import { type ReactElement } from 'react';
|
|
2
|
-
import type { DataType
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
import type { UCPanelState } from '../lib/react/panel.js';
|
|
6
|
-
export type Props<T extends DataType> = UCPanelState & {
|
|
7
|
-
errMsg?: ErrorMessage | null;
|
|
8
|
-
field: UCInputField<T>;
|
|
9
|
-
onChange: UCFormFieldControlOnChange<T>;
|
|
10
|
-
};
|
|
11
|
-
export declare function UCFormFieldControl<T extends DataType>({ errMsg, execState, field, onChange: onChangeBase, }: Props<T>): ReactElement;
|
|
2
|
+
import type { DataType } from '../../dt/index.js';
|
|
3
|
+
import type { UCFormFieldControlProps } from '../lib/react/form.js';
|
|
4
|
+
export declare function UCFormFieldControl<T extends DataType>({ errMsg, execState, f, onChange: onChangeBase, }: UCFormFieldControlProps<T>): ReactElement;
|
|
@@ -4,23 +4,23 @@ import { UCInputFieldChangeOperator, ucifRepeatability, } from '../../uc/index.j
|
|
|
4
4
|
import { isBlank } from '../../utils/index.js';
|
|
5
5
|
import { rnInputDef } from '../lib/rn/input.js';
|
|
6
6
|
const MULTIPLE_VALUES_SEPARATOR = ',';
|
|
7
|
-
export function UCFormFieldControl({ errMsg = null, execState,
|
|
8
|
-
const [internalValue, setInternalValue] = useState(
|
|
7
|
+
export function UCFormFieldControl({ errMsg = null, execState, f, onChange: onChangeBase, }) {
|
|
8
|
+
const [internalValue, setInternalValue] = useState(f.getValue());
|
|
9
9
|
// biome-ignore lint/correctness/useExhaustiveDependencies: false positive : It is actually necessary (only `field` does not trigger the effect)
|
|
10
10
|
useEffect(() => {
|
|
11
|
-
setInternalValue(
|
|
12
|
-
}, [
|
|
13
|
-
const attrs = rnInputDef(
|
|
11
|
+
setInternalValue(f.getValue());
|
|
12
|
+
}, [f.getValue()]);
|
|
13
|
+
const attrs = rnInputDef(f, execState, errMsg);
|
|
14
14
|
const onChangeText = (value) => {
|
|
15
|
-
const [isRepeatable] = ucifRepeatability(
|
|
15
|
+
const [isRepeatable] = ucifRepeatability(f.def);
|
|
16
16
|
if (isRepeatable && typeof value === 'string') {
|
|
17
17
|
const valueArr = value
|
|
18
18
|
.split(MULTIPLE_VALUES_SEPARATOR)
|
|
19
19
|
.map((v) => v.trim());
|
|
20
|
-
onChangeBase(
|
|
20
|
+
onChangeBase(f, UCInputFieldChangeOperator.SET, valueArr);
|
|
21
21
|
}
|
|
22
22
|
else {
|
|
23
|
-
onChangeBase(
|
|
23
|
+
onChangeBase(f, UCInputFieldChangeOperator.SET, value);
|
|
24
24
|
}
|
|
25
25
|
setInternalValue(value);
|
|
26
26
|
};
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
import { type ReactElement } from 'react';
|
|
2
2
|
import type { DataType } from '../../dt/index.js';
|
|
3
|
-
import type {
|
|
4
|
-
export
|
|
5
|
-
field: UCInputField<T>;
|
|
6
|
-
}
|
|
7
|
-
export declare function UCFormFieldDesc<T extends DataType>({ field, }: Props<T>): ReactElement | null;
|
|
3
|
+
import type { UCFormFieldDescProps } from '../lib/react/form.js';
|
|
4
|
+
export declare function UCFormFieldDesc<T extends DataType>({ f, }: UCFormFieldDescProps<T>): ReactElement | null;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React, {} from 'react';
|
|
2
2
|
import { Text } from 'react-native';
|
|
3
3
|
import { useDIContext } from '../lib/react/DIContextProvider.js';
|
|
4
|
-
export function UCFormFieldDesc({
|
|
4
|
+
export function UCFormFieldDesc({ f, }) {
|
|
5
5
|
const { wordingManager } = useDIContext();
|
|
6
|
-
const { desc } = wordingManager.ucif(
|
|
6
|
+
const { desc } = wordingManager.ucif(f);
|
|
7
7
|
if (!desc) {
|
|
8
8
|
return null;
|
|
9
9
|
}
|
|
@@ -1,7 +1,3 @@
|
|
|
1
1
|
import { type ReactElement } from 'react';
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
errMsg: ErrorMessage;
|
|
5
|
-
}
|
|
6
|
-
export declare function UCFormFieldErr({ errMsg }: Props): ReactElement;
|
|
7
|
-
export {};
|
|
2
|
+
import type { UCFormFieldErrProps } from '../lib/react/form.js';
|
|
3
|
+
export declare function UCFormFieldErr({ errMsg }: UCFormFieldErrProps): ReactElement;
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
import { type ReactElement } from 'react';
|
|
2
2
|
import type { DataType } from '../../dt/index.js';
|
|
3
|
-
import type {
|
|
4
|
-
export
|
|
5
|
-
field: UCInputField<T>;
|
|
6
|
-
}
|
|
7
|
-
export declare function UCFormFieldLabel<T extends DataType>({ field, }: Props<T>): ReactElement;
|
|
3
|
+
import type { UCFormFieldLabelProps } from '../lib/react/form.js';
|
|
4
|
+
export declare function UCFormFieldLabel<T extends DataType>({ f, }: UCFormFieldLabelProps<T>): ReactElement;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React, {} from 'react';
|
|
2
2
|
import { Text } from 'react-native';
|
|
3
3
|
import { useDIContext } from '../lib/react/DIContextProvider.js';
|
|
4
|
-
export function UCFormFieldLabel({
|
|
4
|
+
export function UCFormFieldLabel({ f, }) {
|
|
5
5
|
const { wordingManager } = useDIContext();
|
|
6
|
-
const { label } = wordingManager.ucif(
|
|
6
|
+
const { label } = wordingManager.ucif(f);
|
|
7
7
|
return React.createElement(Text, null, label);
|
|
8
8
|
}
|
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
import { type ReactElement } from 'react';
|
|
2
2
|
import type { UCInput, UCOPIBase } from '../../uc/index.js';
|
|
3
|
-
import type {
|
|
4
|
-
export
|
|
5
|
-
type Props<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = UCPanelCtx<I, OPI0, OPI1> & {
|
|
6
|
-
onPress?: UCFormSubmitOnPress;
|
|
7
|
-
};
|
|
8
|
-
export declare function UCFormSubmitControl<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ execState, disabled, onPress, uc }: Props<I, OPI0, OPI1>): ReactElement;
|
|
9
|
-
export {};
|
|
3
|
+
import type { UCFormSubmitControlProps } from '../lib/react/form.js';
|
|
4
|
+
export declare function UCFormSubmitControl<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ execState, disabled, onPress, uc, }: UCFormSubmitControlProps<I, OPI0, OPI1>): ReactElement;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, {} from 'react';
|
|
2
2
|
import { Pressable, Text } from 'react-native';
|
|
3
3
|
import { useDIContext } from '../lib/react/DIContextProvider.js';
|
|
4
|
-
export function UCFormSubmitControl({ execState, disabled, onPress, uc }) {
|
|
4
|
+
export function UCFormSubmitControl({ execState, disabled, onPress, uc, }) {
|
|
5
5
|
const { wordingManager } = useDIContext();
|
|
6
6
|
return (React.createElement(Pressable, { onPress: onPress, disabled: disabled },
|
|
7
7
|
React.createElement(Text, null, wordingManager.ucISubmit(uc.def, execState))));
|
|
@@ -12,6 +12,6 @@ export function UCForm({ clearAfterExec, disabled, execState, onChange, onSubmit
|
|
|
12
12
|
};
|
|
13
13
|
return (React.createElement("form", { onSubmit: onSubmit, ref: formRef },
|
|
14
14
|
uc.inputFieldsForForm().map((f) => (React.createElement("div", { key: f.key },
|
|
15
|
-
React.createElement(UCFormField, { disabled: disabled, execState: execState,
|
|
15
|
+
React.createElement(UCFormField, { disabled: disabled, execState: execState, f: f, onChange: onChange })))),
|
|
16
16
|
React.createElement(UCFormSubmitControl, { execState: execState, disabled: disabled, uc: uc })));
|
|
17
17
|
}
|
|
@@ -1,11 +1,4 @@
|
|
|
1
1
|
import { type ReactElement } from 'react';
|
|
2
2
|
import type { DataType } from '../../dt/index.js';
|
|
3
|
-
import { type
|
|
4
|
-
|
|
5
|
-
declare const ELEMENTS: readonly ["control", "desc", "err", "label"];
|
|
6
|
-
type Element = (typeof ELEMENTS)[number];
|
|
7
|
-
type Props<T extends DataType> = FormFieldControlProps<T> & FormFieldLabelProps<T> & {
|
|
8
|
-
only?: Element[];
|
|
9
|
-
};
|
|
10
|
-
export declare function UCFormField<T extends DataType>({ disabled, execState, field, onChange: onChangeBase, only, }: Props<T>): ReactElement;
|
|
11
|
-
export {};
|
|
3
|
+
import { type UCFormFieldProps } from '../lib/react/form.js';
|
|
4
|
+
export declare function UCFormField<T extends DataType>({ disabled, execState, f, onChange: onChangeBase, only, }: UCFormFieldProps<T>): ReactElement;
|
|
@@ -1,32 +1,21 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
2
|
import { useDIContext } from '../lib/react/DIContextProvider.js';
|
|
3
|
-
import {
|
|
3
|
+
import { UC_FORM_FIELD_ELEMENTS, validateFormField, } from '../lib/react/form.js';
|
|
4
|
+
import { UCFormFieldControl } from './UCFormFieldControl.js';
|
|
4
5
|
import { UCFormFieldDesc } from './UCFormFieldDesc.js';
|
|
5
6
|
import { UCFormFieldErr } from './UCFormFieldErr.js';
|
|
6
|
-
import { UCFormFieldLabel
|
|
7
|
-
|
|
8
|
-
export function UCFormField({ disabled, execState, field, onChange: onChangeBase, only, }) {
|
|
7
|
+
import { UCFormFieldLabel } from './UCFormFieldLabel.js';
|
|
8
|
+
export function UCFormField({ disabled, execState, f, onChange: onChangeBase, only, }) {
|
|
9
9
|
const { i18nManager } = useDIContext();
|
|
10
|
-
const { type } = field.def;
|
|
11
10
|
const [errMsg, setErrMsg] = useState(null);
|
|
12
|
-
const elements = only ?? ELEMENTS;
|
|
13
11
|
const onChange = (f, op, v) => {
|
|
14
|
-
setErrMsg(
|
|
15
|
-
const vArr = Array.isArray(v) ? v : [v];
|
|
16
|
-
for (const vv of vArr) {
|
|
17
|
-
const validation = type.assign(vv).validate();
|
|
18
|
-
const violation = validation.get();
|
|
19
|
-
if (violation) {
|
|
20
|
-
const [key, expected] = violation;
|
|
21
|
-
setErrMsg(i18nManager.t(key, { vars: { expected } }));
|
|
22
|
-
break;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
12
|
+
setErrMsg(validateFormField(i18nManager, f, v));
|
|
25
13
|
onChangeBase(f, op, v);
|
|
26
14
|
};
|
|
15
|
+
const elements = only ?? UC_FORM_FIELD_ELEMENTS;
|
|
27
16
|
return (React.createElement(React.Fragment, null,
|
|
28
|
-
elements.includes('label') && React.createElement(UCFormFieldLabel, {
|
|
29
|
-
elements.includes('control') && (React.createElement(UCFormFieldControl, { disabled: disabled, execState: execState,
|
|
17
|
+
elements.includes('label') && React.createElement(UCFormFieldLabel, { f: f }),
|
|
18
|
+
elements.includes('control') && (React.createElement(UCFormFieldControl, { disabled: disabled, execState: execState, f: f, onChange: onChange })),
|
|
30
19
|
elements.includes('err') && errMsg && (React.createElement(UCFormFieldErr, { errMsg: errMsg })),
|
|
31
|
-
elements.includes('desc') && React.createElement(UCFormFieldDesc, {
|
|
20
|
+
elements.includes('desc') && React.createElement(UCFormFieldDesc, { f: f })));
|
|
32
21
|
}
|
|
@@ -1,11 +1,4 @@
|
|
|
1
1
|
import { type ReactElement } from 'react';
|
|
2
|
-
import type { DataType
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
import type { UCPanelState } from '../lib/react/panel.js';
|
|
6
|
-
export type Props<T extends DataType> = UCPanelState & {
|
|
7
|
-
errMsg?: ErrorMessage | null;
|
|
8
|
-
field: UCInputField<T>;
|
|
9
|
-
onChange: UCFormFieldControlOnChange<T>;
|
|
10
|
-
};
|
|
11
|
-
export declare function UCFormFieldControl<T extends DataType>({ errMsg, execState, field, onChange: onChangeBase, }: Props<T>): ReactElement;
|
|
2
|
+
import type { DataType } from '../../dt/index.js';
|
|
3
|
+
import type { UCFormFieldControlProps } from '../lib/react/form.js';
|
|
4
|
+
export declare function UCFormFieldControl<T extends DataType>({ errMsg, execState, f, onChange: onChangeBase, }: UCFormFieldControlProps<T>): ReactElement;
|
|
@@ -4,31 +4,46 @@ import { htmlInputDef } from '../lib/web/input.js';
|
|
|
4
4
|
const CHECKED_FIELD_TYPES = ['checkbox', 'radio'];
|
|
5
5
|
const FILE_FIELD_TYPES = ['file'];
|
|
6
6
|
const MULTIPLE_VALUES_SEPARATOR = ',';
|
|
7
|
-
export function UCFormFieldControl({ errMsg = null, execState,
|
|
8
|
-
const attrs = htmlInputDef(
|
|
7
|
+
export function UCFormFieldControl({ errMsg = null, execState, f, onChange: onChangeBase, }) {
|
|
8
|
+
const attrs = htmlInputDef(f, execState, errMsg);
|
|
9
9
|
const onChange = (e) => {
|
|
10
10
|
const target = e.currentTarget;
|
|
11
11
|
const type = target.type;
|
|
12
12
|
let value = target.value;
|
|
13
|
+
if (target.localName === 'select' && !value) {
|
|
14
|
+
// Prevent the value from being '' when we set/unset the select
|
|
15
|
+
// Otherwise it sets '' as value and prevents the form for being valid
|
|
16
|
+
onChangeBase(f, UCInputFieldChangeOperator.RESET, value);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
13
19
|
if (CHECKED_FIELD_TYPES.includes(type) && 'checked' in target) {
|
|
14
20
|
value = target.checked;
|
|
15
21
|
}
|
|
16
22
|
else if (FILE_FIELD_TYPES.includes(type) && 'files' in target) {
|
|
17
23
|
value = target.files?.item(0);
|
|
18
24
|
}
|
|
19
|
-
const [isRepeatable] = ucifRepeatability(
|
|
25
|
+
const [isRepeatable] = ucifRepeatability(f.def);
|
|
20
26
|
if (isRepeatable && typeof value === 'string') {
|
|
21
27
|
const valueArr = value
|
|
22
28
|
.split(MULTIPLE_VALUES_SEPARATOR)
|
|
23
29
|
.map((v) => v.trim());
|
|
24
|
-
onChangeBase(
|
|
30
|
+
onChangeBase(f, UCInputFieldChangeOperator.SET, valueArr);
|
|
25
31
|
}
|
|
26
32
|
else {
|
|
27
|
-
onChangeBase(
|
|
33
|
+
onChangeBase(f, UCInputFieldChangeOperator.SET, value);
|
|
28
34
|
}
|
|
29
35
|
};
|
|
30
36
|
if (attrs.internal?.multiline) {
|
|
31
37
|
return React.createElement("textarea", { ...attrs.spec, onChange: onChange });
|
|
32
38
|
}
|
|
39
|
+
const { type } = f.def;
|
|
40
|
+
const options = type.getOptions();
|
|
41
|
+
if (options) {
|
|
42
|
+
// TODO : Handle type.hasStrictOptions() => display an input text alongside the select
|
|
43
|
+
// TODO : Consider using a radio and/or checkbox and/or selectable buttons when the options count < X
|
|
44
|
+
return (React.createElement("select", { ...attrs.spec, onChange: onChange },
|
|
45
|
+
React.createElement("option", null),
|
|
46
|
+
options.map((o) => (React.createElement("option", { key: o.value.toString(), value: o.value.toString() }, o.label)))));
|
|
47
|
+
}
|
|
33
48
|
return React.createElement("input", { ...attrs.spec, onChange: onChange });
|
|
34
49
|
}
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
import { type ReactElement } from 'react';
|
|
2
2
|
import type { DataType } from '../../dt/index.js';
|
|
3
|
-
import type {
|
|
4
|
-
export
|
|
5
|
-
field: UCInputField<T>;
|
|
6
|
-
}
|
|
7
|
-
export declare function UCFormFieldDesc<T extends DataType>({ field, }: Props<T>): ReactElement | null;
|
|
3
|
+
import type { UCFormFieldDescProps } from '../lib/react/form.js';
|
|
4
|
+
export declare function UCFormFieldDesc<T extends DataType>({ f, }: UCFormFieldDescProps<T>): ReactElement | null;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React, {} from 'react';
|
|
2
2
|
import { useDIContext } from '../lib/react/DIContextProvider.js';
|
|
3
|
-
export function UCFormFieldDesc({
|
|
3
|
+
export function UCFormFieldDesc({ f, }) {
|
|
4
4
|
const { wordingManager } = useDIContext();
|
|
5
|
-
const { desc } = wordingManager.ucif(
|
|
5
|
+
const { desc } = wordingManager.ucif(f);
|
|
6
6
|
if (!desc) {
|
|
7
7
|
return null;
|
|
8
8
|
}
|
|
@@ -1,7 +1,3 @@
|
|
|
1
1
|
import { type ReactElement } from 'react';
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
errMsg: ErrorMessage;
|
|
5
|
-
}
|
|
6
|
-
export declare function UCFormFieldErr({ errMsg }: Props): ReactElement;
|
|
7
|
-
export {};
|
|
2
|
+
import type { UCFormFieldErrProps } from '../lib/react/form.js';
|
|
3
|
+
export declare function UCFormFieldErr({ errMsg }: UCFormFieldErrProps): ReactElement;
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
import { type ReactElement } from 'react';
|
|
2
2
|
import type { DataType } from '../../dt/index.js';
|
|
3
|
-
import {
|
|
4
|
-
export
|
|
5
|
-
field: UCInputField<T>;
|
|
6
|
-
}
|
|
7
|
-
export declare function UCFormFieldLabel<T extends DataType>({ field, }: Props<T>): ReactElement;
|
|
3
|
+
import type { UCFormFieldLabelProps } from '../lib/react/form.js';
|
|
4
|
+
export declare function UCFormFieldLabel<T extends DataType>({ f, }: UCFormFieldLabelProps<T>): ReactElement;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React, {} from 'react';
|
|
2
2
|
import { ucifId } from '../../uc/index.js';
|
|
3
3
|
import { useDIContext } from '../lib/react/DIContextProvider.js';
|
|
4
|
-
export function UCFormFieldLabel({
|
|
4
|
+
export function UCFormFieldLabel({ f, }) {
|
|
5
5
|
const { wordingManager } = useDIContext();
|
|
6
|
-
const { label } = wordingManager.ucif(
|
|
7
|
-
return React.createElement("label", { htmlFor: ucifId(
|
|
6
|
+
const { label } = wordingManager.ucif(f);
|
|
7
|
+
return React.createElement("label", { htmlFor: ucifId(f.key) }, label);
|
|
8
8
|
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { type ReactElement } from 'react';
|
|
2
2
|
import type { UCInput, UCOPIBase } from '../../uc/index.js';
|
|
3
|
-
import type {
|
|
4
|
-
|
|
5
|
-
export declare function UCFormSubmitControl<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ execState, disabled, uc }: Props<I, OPI0, OPI1>): ReactElement;
|
|
6
|
-
export {};
|
|
3
|
+
import type { UCFormSubmitControlProps } from '../lib/react/form.js';
|
|
4
|
+
export declare function UCFormSubmitControl<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ execState, disabled, uc, }: UCFormSubmitControlProps<I, OPI0, OPI1>): ReactElement;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, {} from 'react';
|
|
2
2
|
import { useDIContext } from '../lib/react/DIContextProvider.js';
|
|
3
|
-
export function UCFormSubmitControl({ execState, disabled, uc }) {
|
|
3
|
+
export function UCFormSubmitControl({ execState, disabled, uc, }) {
|
|
4
4
|
const { wordingManager } = useDIContext();
|
|
5
5
|
return (React.createElement("input", { disabled: disabled, type: "submit", value: wordingManager.ucISubmit(uc.def, execState) }));
|
|
6
6
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "libmodulor",
|
|
3
3
|
"description": "An opinionated TypeScript library to create business oriented applications",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.6.0",
|
|
5
5
|
"license": "LGPL-3.0",
|
|
6
6
|
"author": "Chafik H'nini <chafik.hnini@gmail.com>",
|
|
7
7
|
"homepage": "https://github.com/c100k/libmodulor#readme",
|
|
@@ -13,9 +13,6 @@
|
|
|
13
13
|
".": {
|
|
14
14
|
"import": "./dist/esm/index.js"
|
|
15
15
|
},
|
|
16
|
-
"./helper": {
|
|
17
|
-
"import": "./dist/products/Helper/index.js"
|
|
18
|
-
},
|
|
19
16
|
"./locales/en": {
|
|
20
17
|
"import": "./dist/esm/i18n/locales/en.js"
|
|
21
18
|
},
|
|
@@ -56,9 +53,10 @@
|
|
|
56
53
|
"import": "./dist/esm/index.web.js"
|
|
57
54
|
}
|
|
58
55
|
},
|
|
56
|
+
"bin": "./dist/esm/products/Helper/index.js",
|
|
59
57
|
"peerDependencies": {
|
|
60
58
|
"@hono/node-server": "^1.13.8",
|
|
61
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
59
|
+
"@modelcontextprotocol/sdk": "^1.6.0",
|
|
62
60
|
"@stricli/core": "^1.1.1",
|
|
63
61
|
"buffer": "^6.0.3",
|
|
64
62
|
"cookie-parser": "^1.4.7",
|
|
@@ -68,16 +66,17 @@
|
|
|
68
66
|
"helmet": "^8.0.0",
|
|
69
67
|
"hono": "^4.7.2",
|
|
70
68
|
"inversify": "^6.2.2",
|
|
71
|
-
"jose": "^6.0.
|
|
69
|
+
"jose": "^6.0.8",
|
|
72
70
|
"knex": "^3.1.0",
|
|
73
71
|
"pg": "^8.13.3",
|
|
74
|
-
"react": "^
|
|
75
|
-
"react-dom": "^
|
|
72
|
+
"react": "^19.0.0",
|
|
73
|
+
"react-dom": "^19.0.0",
|
|
76
74
|
"react-native": "^0.78.0",
|
|
77
75
|
"reflect-metadata": "^0.2.2",
|
|
78
76
|
"sqlite3": "^5.1.7",
|
|
79
77
|
"typescript": "^5.7.3",
|
|
80
|
-
"vite": "^6.
|
|
78
|
+
"vite": "^6.2.0",
|
|
79
|
+
"vitest": "^3.0.7"
|
|
81
80
|
},
|
|
82
81
|
"peerDependenciesMeta": {
|
|
83
82
|
"@hono/node-server": {
|