libmodulor 0.20.0 → 0.21.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 +19 -0
- package/README.md +1 -1
- package/dist/esm/apps/Helper/src/lib/project.js +4 -4
- package/dist/esm/dt/Validation.js +1 -1
- package/dist/esm/dt/final/TGitSSHURL.d.ts +4 -3
- package/dist/esm/dt/final/TGitSSHURL.js +1 -1
- package/dist/esm/dt/final/TSSHPrivateKey.js +1 -3
- package/dist/esm/std/impl/ConsoleLogger.js +2 -2
- package/dist/esm/std/impl/FetchHTTPAPICallExecutor.js +1 -1
- package/dist/esm/std/impl/NodeFormDataBuilder.js +3 -1
- package/dist/esm/std/impl/SimpleHTTPAPICaller.js +1 -1
- package/dist/esm/target/lib/cli/CommandExecutor.js +2 -2
- package/dist/esm/target/lib/react/UCPanel.js +0 -4
- package/dist/esm/target/lib/react/form.d.ts +5 -6
- package/dist/esm/target/lib/react/form.js +7 -10
- package/dist/esm/target/lib/react/useUC.d.ts +4 -4
- package/dist/esm/target/node-mcp-server/NodeLocalStdioMCPServerManager.js +1 -0
- package/dist/esm/target/react-native-pure/UCForm.d.ts +1 -1
- package/dist/esm/target/react-native-pure/UCForm.js +2 -2
- package/dist/esm/target/react-native-pure/UCFormField.d.ts +1 -1
- package/dist/esm/target/react-native-pure/UCFormField.js +3 -4
- package/dist/esm/target/react-native-pure/UCFormFieldControl.js +13 -7
- package/dist/esm/target/react-web-pure/UCForm.d.ts +1 -1
- package/dist/esm/target/react-web-pure/UCForm.js +2 -2
- package/dist/esm/target/react-web-pure/UCFormField.d.ts +1 -1
- package/dist/esm/target/react-web-pure/UCFormField.js +3 -4
- package/dist/esm/target/react-web-pure/UCFormFieldControl.js +7 -4
- package/dist/esm/testing/AppTester.d.ts +1 -1
- package/dist/esm/testing/AppTester.js +3 -2
- package/dist/esm/testing/impl/SimpleHTMLAppTestReportEmitter.js +1 -1
- package/dist/esm/testing/impl/TypeScriptLibUCDefASTParser.js +2 -2
- package/dist/esm/testing/impl/VitestAppTestSuiteEmitter.js +6 -3
- package/dist/esm/testing/uc-input.js +13 -12
- package/dist/esm/testing/workers/UCExecutor.js +2 -2
- package/dist/esm/uc/UC.d.ts +7 -7
- package/dist/esm/uc/UC.js +4 -3
- package/dist/esm/uc/UCInputField.d.ts +6 -3
- package/dist/esm/uc/UCInputField.js +39 -29
- package/dist/esm/uc/index.d.ts +0 -1
- package/dist/esm/uc/index.js +0 -1
- package/dist/esm/uc/input-field.d.ts +2 -19
- package/dist/esm/uc/input-field.js +0 -19
- package/dist/esm/uc/input.d.ts +13 -7
- package/dist/esm/uc/utils/rInput.js +4 -3
- package/dist/esm/uc/utils/rVal.d.ts +5 -5
- package/dist/esm/uc/utils/rVal.js +1 -12
- package/dist/esm/uc/value.d.ts +1 -2
- package/dist/esm/uc/workers/UCInputFilesProcessor.js +3 -3
- package/package.json +11 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## v0.21.0 (2025-08-19)
|
|
4
|
+
|
|
5
|
+
**BREAKING**
|
|
6
|
+
|
|
7
|
+
- Infer UC input field type without explicit generic when using `UC` methods like `inputField`, `reqVal0`, `rVal0`, `rValArr` : simply fix the TypeScript errors by removing the generic (e.g `uc.reqVal<DateISO8601>('from')` => `uc.reqVal('from')`)
|
|
8
|
+
- Change `UCInputField.setValue` to `UCInputField.setVal`, `UCInputField.addVal`, `UCInputField.rmVal` : simply fix the TypeScript errors by replacing `setValue` to the appropriate method. Also, `UCInputFieldChangeOperator` has been removed as it became useless. If you created custom `UCForm` field controls, you need to call the appropriate method to set the value in the field.
|
|
9
|
+
|
|
10
|
+
**Added**
|
|
11
|
+
|
|
12
|
+
- Add overrides to `rVal0` to avoid non null assertion
|
|
13
|
+
|
|
14
|
+
**Fixed**
|
|
15
|
+
|
|
16
|
+
- Display expected falsy values in violation
|
|
17
|
+
|
|
18
|
+
**Misc**
|
|
19
|
+
|
|
20
|
+
- Expose `TGitSSHURLConstraints`
|
|
21
|
+
|
|
3
22
|
## v0.20.0 (2025-07-26)
|
|
4
23
|
|
|
5
24
|
**Added**
|
package/README.md
CHANGED
|
@@ -81,13 +81,13 @@ export const PACKAGE_JSON = (name) => `{
|
|
|
81
81
|
"test": "tsc && vitest run --passWithNoTests"
|
|
82
82
|
},
|
|
83
83
|
"dependencies": {
|
|
84
|
-
"inversify": "^7.
|
|
84
|
+
"inversify": "^7.8.1",
|
|
85
85
|
"libmodulor": "latest",
|
|
86
86
|
"reflect-metadata": "^0.2.2"
|
|
87
87
|
},
|
|
88
88
|
"devDependencies": {
|
|
89
|
-
"@biomejs/biome": "^2.
|
|
90
|
-
"@types/node": "^22.
|
|
89
|
+
"@biomejs/biome": "^2.2.0",
|
|
90
|
+
"@types/node": "^22.17.2",
|
|
91
91
|
"@vitest/coverage-v8": "^3.2.4",
|
|
92
92
|
"buffer": "^6.0.3",
|
|
93
93
|
"cookie-parser": "^1.4.7",
|
|
@@ -96,7 +96,7 @@ export const PACKAGE_JSON = (name) => `{
|
|
|
96
96
|
"fast-check": "^4.2.0",
|
|
97
97
|
"helmet": "^8.1.0",
|
|
98
98
|
"jose": "^6.0.12",
|
|
99
|
-
"typescript": "^5.
|
|
99
|
+
"typescript": "^5.9.2",
|
|
100
100
|
"vite": "^6.3.5",
|
|
101
101
|
"vitest": "^3.2.4"
|
|
102
102
|
}
|
|
@@ -15,7 +15,7 @@ export class Validation {
|
|
|
15
15
|
return null;
|
|
16
16
|
}
|
|
17
17
|
const key = this.violationAsI18nable(violation);
|
|
18
|
-
const expected = (violation.expected
|
|
18
|
+
const expected = (violation.expected ?? '').toString();
|
|
19
19
|
return [key, expected];
|
|
20
20
|
}
|
|
21
21
|
getViolations() {
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { TName } from '../base/TBase.js';
|
|
2
2
|
import { TString, type TStringConstraints } from '../base/TString.js';
|
|
3
3
|
export type GitSSHURL = string;
|
|
4
|
+
export interface TGitSSHURLConstraints extends TStringConstraints<'GitSSHURL'> {
|
|
5
|
+
domainName?: string | undefined;
|
|
6
|
+
}
|
|
4
7
|
export declare class TGitSSHURL extends TString<GitSSHURL> {
|
|
5
8
|
private static DEFAULT_DOMAIN_NAME;
|
|
6
|
-
constructor(constraints?:
|
|
7
|
-
domainName: string;
|
|
8
|
-
});
|
|
9
|
+
constructor(constraints?: TGitSSHURLConstraints);
|
|
9
10
|
tName(): TName;
|
|
10
11
|
example(): GitSSHURL;
|
|
11
12
|
}
|
|
@@ -2,7 +2,7 @@ import { TString } from '../base/TString.js';
|
|
|
2
2
|
export class TGitSSHURL extends TString {
|
|
3
3
|
static DEFAULT_DOMAIN_NAME = 'github.com';
|
|
4
4
|
constructor(constraints) {
|
|
5
|
-
const format = new RegExp(`^git@${constraints?.domainName ?? TGitSSHURL.DEFAULT_DOMAIN_NAME}:([A-Za-z0-9-_]+)
|
|
5
|
+
const format = new RegExp(`^git@${constraints?.domainName ?? TGitSSHURL.DEFAULT_DOMAIN_NAME}:([A-Za-z0-9-_]+)/([A-Za-z0-9-_]+).git$`);
|
|
6
6
|
super({
|
|
7
7
|
...constraints,
|
|
8
8
|
format: { f: 'GitSSHURL', regexp: format },
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { TString } from '../base/TString.js';
|
|
2
2
|
export const SSHPrivatekKeyTypes = ['OPENSSH', 'RSA'];
|
|
3
3
|
export class TSSHPrivateKey extends TString {
|
|
4
|
-
static FORMAT =
|
|
5
|
-
// @ts-ignore
|
|
6
|
-
/^-----BEGIN (OPENSSH|RSA) PRIVATE KEY-----\n(.+)?\n-----END (OPENSSH|RSA) PRIVATE KEY-----$/is;
|
|
4
|
+
static FORMAT = /^-----BEGIN (OPENSSH|RSA) PRIVATE KEY-----\n(.+)?\n-----END (OPENSSH|RSA) PRIVATE KEY-----$/is;
|
|
7
5
|
constructor(constraints) {
|
|
8
6
|
super({
|
|
9
7
|
...constraints,
|
|
@@ -68,8 +68,8 @@ let ConsoleLogger = class ConsoleLogger {
|
|
|
68
68
|
console.warn(`${this.t()} [warn] ${message}`, ...meta);
|
|
69
69
|
}
|
|
70
70
|
shouldLog(level) {
|
|
71
|
-
const configLevelIndex = ConsoleLogger_1.LEVELS.
|
|
72
|
-
const levelIndex = ConsoleLogger_1.LEVELS.
|
|
71
|
+
const configLevelIndex = ConsoleLogger_1.LEVELS.indexOf(this.s().logger_level);
|
|
72
|
+
const levelIndex = ConsoleLogger_1.LEVELS.indexOf(level);
|
|
73
73
|
return levelIndex >= configLevelIndex;
|
|
74
74
|
}
|
|
75
75
|
t() {
|
|
@@ -17,7 +17,7 @@ import { injectable } from 'inversify';
|
|
|
17
17
|
let FetchHTTPAPICallExecutor = class FetchHTTPAPICallExecutor {
|
|
18
18
|
fn() {
|
|
19
19
|
// The generalization in HTTPAPICallExecutor is not exactly the same as the actual implementation
|
|
20
|
-
// @ts-
|
|
20
|
+
// @ts-expect-error
|
|
21
21
|
return fetch;
|
|
22
22
|
}
|
|
23
23
|
};
|
|
@@ -19,7 +19,9 @@ let NodeFormDataBuilder = class NodeFormDataBuilder {
|
|
|
19
19
|
chunks.push(chunk);
|
|
20
20
|
});
|
|
21
21
|
rs.on('end', () => {
|
|
22
|
-
fd.append(key,
|
|
22
|
+
fd.append(key,
|
|
23
|
+
// @ts-expect-error
|
|
24
|
+
new Blob(chunks, { type: val.type }), basename(val.uri));
|
|
23
25
|
resolve(null);
|
|
24
26
|
});
|
|
25
27
|
rs.on('error', (err) => {
|
|
@@ -177,7 +177,7 @@ let SimpleHTTPAPICaller = class SimpleHTTPAPICaller {
|
|
|
177
177
|
payload = {};
|
|
178
178
|
// TODO : Find a better way to do this (without adding any external dependency because the code must be portable)
|
|
179
179
|
new URL(`http://localhost?${asText}`).searchParams.forEach((v, k) => {
|
|
180
|
-
// @ts-
|
|
180
|
+
// @ts-expect-error
|
|
181
181
|
payload[k] = v;
|
|
182
182
|
});
|
|
183
183
|
}
|
|
@@ -14,7 +14,7 @@ var CommandExecutor_1;
|
|
|
14
14
|
import { inject, injectable } from 'inversify';
|
|
15
15
|
import { WordingManager } from '../../../i18n/index.js';
|
|
16
16
|
import { FSManagerItemInfoType, } from '../../../std/index.js';
|
|
17
|
-
import {
|
|
17
|
+
import { ucifMustBeFilledManually, } from '../../../uc/index.js';
|
|
18
18
|
import { print, printError } from './renderer.js';
|
|
19
19
|
let CommandExecutor = class CommandExecutor {
|
|
20
20
|
static { CommandExecutor_1 = this; }
|
|
@@ -89,7 +89,7 @@ let CommandExecutor = class CommandExecutor {
|
|
|
89
89
|
const invite = `${label}${help}`;
|
|
90
90
|
await this.promptManager.prompt(invite, {
|
|
91
91
|
validate: async (v) => {
|
|
92
|
-
f.
|
|
92
|
+
f.setVal(v);
|
|
93
93
|
const validation = f.validate();
|
|
94
94
|
const violation = validation.get();
|
|
95
95
|
if (!violation) {
|
|
@@ -27,9 +27,6 @@ export function UCPanel({ autoExec = false, clearAfterExec = true, onDone, onErr
|
|
|
27
27
|
},
|
|
28
28
|
sleepInMs,
|
|
29
29
|
});
|
|
30
|
-
const onChange = (f, op, v) => {
|
|
31
|
-
f.setValue(op, v);
|
|
32
|
-
};
|
|
33
30
|
const clear = () => {
|
|
34
31
|
if (!clearAfterExec) {
|
|
35
32
|
return;
|
|
@@ -46,7 +43,6 @@ export function UCPanel({ autoExec = false, clearAfterExec = true, onDone, onErr
|
|
|
46
43
|
return (_jsxs(UCContainer, { uc: uc, children: [autoExec && ctx.disabled && renderAutoExecLoader(), !autoExec && (_jsxs(_Fragment, { children: [needsInputFilling &&
|
|
47
44
|
renderForm({
|
|
48
45
|
...ctx,
|
|
49
|
-
onChange,
|
|
50
46
|
onSubmit: exec,
|
|
51
47
|
}), !needsInputFilling &&
|
|
52
48
|
renderExecTouchable({
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { ReactElement } from 'react';
|
|
2
2
|
import type { DataType, ErrorMessage } from '../../../dt/index.js';
|
|
3
3
|
import type { I18nManager } from '../../../std/index.js';
|
|
4
|
-
import type { UCInput, UCInputField,
|
|
4
|
+
import type { UCInput, UCInputField, UCOPIBase } from '../../../uc/index.js';
|
|
5
5
|
import type { UCPanelCtx, UCPanelOnSubmit, UCPanelState } from './panel.js';
|
|
6
|
-
export type UCFormFieldControlOnChange
|
|
6
|
+
export type UCFormFieldControlOnChange = () => void;
|
|
7
7
|
export type UCFormFieldControlProps<T extends DataType> = UCPanelState & {
|
|
8
8
|
errMsg?: ErrorMessage | null;
|
|
9
9
|
f: UCInputField<T>;
|
|
10
|
-
onChange: UCFormFieldControlOnChange
|
|
10
|
+
onChange: UCFormFieldControlOnChange;
|
|
11
11
|
};
|
|
12
12
|
export interface UCFormFieldDescProps<T extends DataType> {
|
|
13
13
|
f: UCInputField<T>;
|
|
@@ -20,15 +20,14 @@ export interface UCFormFieldLabelProps<T extends DataType> {
|
|
|
20
20
|
}
|
|
21
21
|
export declare const UC_FORM_FIELD_ELEMENTS: readonly ["control", "desc", "err", "label"];
|
|
22
22
|
export type UCFormFieldElement = (typeof UC_FORM_FIELD_ELEMENTS)[number];
|
|
23
|
-
export type UCFormFieldProps<T extends DataType> = UCFormFieldControlProps<T> & {
|
|
23
|
+
export type UCFormFieldProps<T extends DataType> = Omit<UCFormFieldControlProps<T>, 'onChange'> & {
|
|
24
24
|
only?: UCFormFieldElement[];
|
|
25
25
|
};
|
|
26
26
|
export type UCFormProps<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = UCPanelCtx<I, OPI0, OPI1> & {
|
|
27
|
-
onChange: UCFormFieldControlOnChange;
|
|
28
27
|
onSubmit: UCPanelOnSubmit;
|
|
29
28
|
};
|
|
30
29
|
export type UCFormSubmitControlProps<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = UCPanelCtx<I, OPI0, OPI1> & {
|
|
31
30
|
onPress?: () => Promise<void>;
|
|
32
31
|
};
|
|
33
32
|
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
|
|
33
|
+
export declare function validateFormField<T extends DataType = DataType>(i18nManager: I18nManager, f: UCInputField<T>): ErrorMessage | null;
|
|
@@ -5,18 +5,15 @@ export const UC_FORM_FIELD_ELEMENTS = [
|
|
|
5
5
|
'err',
|
|
6
6
|
'label',
|
|
7
7
|
];
|
|
8
|
-
export function validateFormField(i18nManager, f
|
|
9
|
-
if (isBlank(
|
|
8
|
+
export function validateFormField(i18nManager, f) {
|
|
9
|
+
if (isBlank(f.getValue())) {
|
|
10
10
|
return null;
|
|
11
11
|
}
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
const [key, expected] = violation;
|
|
18
|
-
return i18nManager.t(key, { vars: { expected } });
|
|
19
|
-
}
|
|
12
|
+
const validation = f.validate();
|
|
13
|
+
const violation = validation.get();
|
|
14
|
+
if (violation) {
|
|
15
|
+
const [key, expected] = violation;
|
|
16
|
+
return i18nManager.t(key, { vars: { expected } });
|
|
20
17
|
}
|
|
21
18
|
return null;
|
|
22
19
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { type ArgsRecord, UC, type UCDef, type UCInput, type UCOPIBase } from '../../../uc/index.js';
|
|
2
|
-
export type CloneFunc<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = (i:
|
|
1
|
+
import { type ArgsRecord, UC, type UCDef, type UCInput, type UCInputPartial, type UCOPIBase } from '../../../uc/index.js';
|
|
2
|
+
export type CloneFunc<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = (i: UCInputPartial<I>) => UC<I, OPI0, OPI1>;
|
|
3
3
|
export type DivertFunc<II extends UCInput | undefined = undefined, OOPI0 extends UCOPIBase | undefined = undefined, OOPI1 extends UCOPIBase | undefined = undefined> = (siblingUCD: UCDef) => UC<II, OOPI0, OOPI1>;
|
|
4
|
-
export type RefillFunc<I extends UCInput | undefined = undefined> = (i:
|
|
4
|
+
export type RefillFunc<I extends UCInput | undefined = undefined> = (i: UCInputPartial<I>) => void;
|
|
5
5
|
/**
|
|
6
6
|
* This hook provides utilities to init a use case and perform actions on it in a React way
|
|
7
7
|
* @param appManifest
|
|
@@ -11,7 +11,7 @@ export type RefillFunc<I extends UCInput | undefined = undefined> = (i: Partial<
|
|
|
11
11
|
* @returns
|
|
12
12
|
*/
|
|
13
13
|
export declare function useUC<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>(appManifest: ArgsRecord<I, OPI0, OPI1>['appManifest'], def: ArgsRecord<I, OPI0, OPI1>['def'], auth: ArgsRecord<I, OPI0, OPI1>['auth'], opts?: {
|
|
14
|
-
fillWith:
|
|
14
|
+
fillWith: UCInputPartial<I>;
|
|
15
15
|
}): [
|
|
16
16
|
UC<I, OPI0, OPI1>,
|
|
17
17
|
{
|
|
@@ -125,6 +125,7 @@ let NodeLocalStdioMCPServerManager = class NodeLocalStdioMCPServerManager {
|
|
|
125
125
|
def: ucd,
|
|
126
126
|
});
|
|
127
127
|
if (args) {
|
|
128
|
+
// biome-ignore lint/suspicious/noExplicitAny: can be anything
|
|
128
129
|
uc.fill(args);
|
|
129
130
|
}
|
|
130
131
|
const confirmed = await this.ucManager.confirmClient(uc);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { ReactElement } from 'react';
|
|
2
2
|
import type { UCInput, UCOPIBase } from '../../uc/index.js';
|
|
3
3
|
import type { UCFormProps } from '../lib/react/form.js';
|
|
4
|
-
export declare function UCForm<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ disabled, execState,
|
|
4
|
+
export declare function UCForm<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ disabled, execState, onSubmit, uc, }: UCFormProps<I, OPI0, OPI1>): ReactElement;
|
|
@@ -3,10 +3,10 @@ import { View } from 'react-native';
|
|
|
3
3
|
import { useStyleContext } from '../lib/react/StyleContextProvider.js';
|
|
4
4
|
import { UCFormField } from './UCFormField.js';
|
|
5
5
|
import { UCFormSubmitControl } from './UCFormSubmitControl.js';
|
|
6
|
-
export function UCForm({ disabled, execState,
|
|
6
|
+
export function UCForm({ disabled, execState, onSubmit, uc, }) {
|
|
7
7
|
const { form } = useStyleContext();
|
|
8
8
|
const onPress = async () => {
|
|
9
9
|
await onSubmit();
|
|
10
10
|
};
|
|
11
|
-
return (_jsxs(View, { style: form?.style, children: [uc.inputFieldsForForm().map((f) => (_jsx(UCFormField, { disabled: disabled, execState: execState, f: f
|
|
11
|
+
return (_jsxs(View, { style: form?.style, children: [uc.inputFieldsForForm().map((f) => (_jsx(UCFormField, { disabled: disabled, execState: execState, f: f }, f.key))), _jsx(UCFormSubmitControl, { disabled: disabled, execState: execState, onPress: onPress, uc: uc })] }));
|
|
12
12
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { type ReactElement } from 'react';
|
|
2
2
|
import type { DataType } from '../../dt/index.js';
|
|
3
3
|
import { type UCFormFieldProps } from '../lib/react/form.js';
|
|
4
|
-
export declare function UCFormField<T extends DataType>({ disabled, execState, f,
|
|
4
|
+
export declare function UCFormField<T extends DataType>({ disabled, execState, f, only, }: UCFormFieldProps<T>): ReactElement;
|
|
@@ -8,13 +8,12 @@ import { UCFormFieldControl } from './UCFormFieldControl.js';
|
|
|
8
8
|
import { UCFormFieldDesc } from './UCFormFieldDesc.js';
|
|
9
9
|
import { UCFormFieldErr } from './UCFormFieldErr.js';
|
|
10
10
|
import { UCFormFieldLabel } from './UCFormFieldLabel.js';
|
|
11
|
-
export function UCFormField({ disabled, execState, f,
|
|
11
|
+
export function UCFormField({ disabled, execState, f, only, }) {
|
|
12
12
|
const { i18nManager } = useDIContext();
|
|
13
13
|
const { formField } = useStyleContext();
|
|
14
14
|
const [errMsg, setErrMsg] = useState(null);
|
|
15
|
-
const onChange = (
|
|
16
|
-
setErrMsg(validateFormField(i18nManager, f
|
|
17
|
-
onChangeBase(f, op, v);
|
|
15
|
+
const onChange = () => {
|
|
16
|
+
setErrMsg(validateFormField(i18nManager, f));
|
|
18
17
|
};
|
|
19
18
|
const elements = only ?? UC_FORM_FIELD_ELEMENTS;
|
|
20
19
|
return (_jsxs(View, { style: formField?.style, children: [elements.includes('label') && _jsx(UCFormFieldLabel, { f: f }), elements.includes('control') && (_jsx(UCFormFieldControl, { disabled: disabled, execState: execState, f: f, onChange: onChange })), elements.includes('err') && errMsg && (_jsx(UCFormFieldErr, { errMsg: errMsg })), elements.includes('desc') && _jsx(UCFormFieldDesc, { f: f })] }));
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { useEffect, useState } from 'react';
|
|
3
3
|
import { FlatList, Pressable, StyleSheet, Switch, Text, TextInput, } from 'react-native';
|
|
4
4
|
import { TBoolean } from '../../dt/index.js';
|
|
5
|
-
import {
|
|
5
|
+
import { ucifRepeatability } from '../../uc/index.js';
|
|
6
6
|
import { isBlank } from '../../utils/index.js';
|
|
7
7
|
import { styleDef, useStyleContext, } from '../lib/react/StyleContextProvider.js';
|
|
8
8
|
import { rnInputDef } from '../lib/rn/input.js';
|
|
@@ -31,24 +31,30 @@ export function UCFormFieldControl({ disabled, errMsg = null, execState, f, onCh
|
|
|
31
31
|
const valueArr = value
|
|
32
32
|
.split(MULTIPLE_VALUES_SEPARATOR)
|
|
33
33
|
.map((v) => v.trim());
|
|
34
|
-
|
|
34
|
+
f.setVal(valueArr);
|
|
35
|
+
onChangeBase();
|
|
36
|
+
setInternalValue(valueArr);
|
|
35
37
|
}
|
|
36
38
|
else {
|
|
37
|
-
|
|
39
|
+
f.setVal(value);
|
|
40
|
+
onChangeBase();
|
|
41
|
+
setInternalValue(value);
|
|
38
42
|
}
|
|
39
|
-
setInternalValue(value);
|
|
40
43
|
};
|
|
41
44
|
const onSelect = (value) => {
|
|
42
45
|
if (internalValue === value) {
|
|
43
|
-
|
|
46
|
+
f.clear();
|
|
47
|
+
onChangeBase();
|
|
44
48
|
setInternalValue(null);
|
|
45
49
|
return;
|
|
46
50
|
}
|
|
47
|
-
|
|
51
|
+
f.setVal(value);
|
|
52
|
+
onChangeBase();
|
|
48
53
|
setInternalValue(value);
|
|
49
54
|
};
|
|
50
55
|
const onValueChange = (value) => {
|
|
51
|
-
|
|
56
|
+
f.setVal(value);
|
|
57
|
+
onChangeBase();
|
|
52
58
|
setInternalValue(value);
|
|
53
59
|
};
|
|
54
60
|
const attrs = rnInputDef(f, disabled, errMsg);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { type ReactElement } from 'react';
|
|
2
2
|
import type { UCInput, UCOPIBase } from '../../uc/index.js';
|
|
3
3
|
import type { UCFormProps } from '../lib/react/form.js';
|
|
4
|
-
export declare function UCForm<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ clearAfterExec, disabled, execState,
|
|
4
|
+
export declare function UCForm<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ clearAfterExec, disabled, execState, onSubmit: onSubmitBase, uc, }: UCFormProps<I, OPI0, OPI1>): ReactElement;
|
|
@@ -3,7 +3,7 @@ import { useRef } from 'react';
|
|
|
3
3
|
import { useStyleContext } from '../lib/react/StyleContextProvider.js';
|
|
4
4
|
import { UCFormField } from './UCFormField.js';
|
|
5
5
|
import { UCFormSubmitControl } from './UCFormSubmitControl.js';
|
|
6
|
-
export function UCForm({ clearAfterExec, disabled, execState,
|
|
6
|
+
export function UCForm({ clearAfterExec, disabled, execState, onSubmit: onSubmitBase, uc, }) {
|
|
7
7
|
const { form } = useStyleContext();
|
|
8
8
|
const formRef = useRef(null);
|
|
9
9
|
const onSubmit = async (e) => {
|
|
@@ -13,5 +13,5 @@ export function UCForm({ clearAfterExec, disabled, execState, onChange, onSubmit
|
|
|
13
13
|
formRef.current?.reset();
|
|
14
14
|
}
|
|
15
15
|
};
|
|
16
|
-
return (_jsxs("form", { className: form?.className, onSubmit: onSubmit, ref: formRef, style: form?.style, children: [uc.inputFieldsForForm().map((f) => (_jsx(UCFormField, { disabled: disabled, execState: execState, f: f
|
|
16
|
+
return (_jsxs("form", { className: form?.className, onSubmit: onSubmit, ref: formRef, style: form?.style, children: [uc.inputFieldsForForm().map((f) => (_jsx(UCFormField, { disabled: disabled, execState: execState, f: f }, f.key))), _jsx(UCFormSubmitControl, { disabled: disabled, execState: execState, uc: uc })] }));
|
|
17
17
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { type ReactElement } from 'react';
|
|
2
2
|
import type { DataType } from '../../dt/index.js';
|
|
3
3
|
import { type UCFormFieldProps } from '../lib/react/form.js';
|
|
4
|
-
export declare function UCFormField<T extends DataType>({ disabled, execState, f,
|
|
4
|
+
export declare function UCFormField<T extends DataType>({ disabled, execState, f, only, }: UCFormFieldProps<T>): ReactElement;
|
|
@@ -7,13 +7,12 @@ import { UCFormFieldControl } from './UCFormFieldControl.js';
|
|
|
7
7
|
import { UCFormFieldDesc } from './UCFormFieldDesc.js';
|
|
8
8
|
import { UCFormFieldErr } from './UCFormFieldErr.js';
|
|
9
9
|
import { UCFormFieldLabel } from './UCFormFieldLabel.js';
|
|
10
|
-
export function UCFormField({ disabled, execState, f,
|
|
10
|
+
export function UCFormField({ disabled, execState, f, only, }) {
|
|
11
11
|
const { i18nManager } = useDIContext();
|
|
12
12
|
const { formField } = useStyleContext();
|
|
13
13
|
const [errMsg, setErrMsg] = useState(null);
|
|
14
|
-
const onChange = (
|
|
15
|
-
setErrMsg(validateFormField(i18nManager, f
|
|
16
|
-
onChangeBase(f, op, v);
|
|
14
|
+
const onChange = () => {
|
|
15
|
+
setErrMsg(validateFormField(i18nManager, f));
|
|
17
16
|
};
|
|
18
17
|
const elements = only ?? UC_FORM_FIELD_ELEMENTS;
|
|
19
18
|
return (_jsxs("div", { className: formField?.className, style: formField?.style, children: [elements.includes('label') && _jsx(UCFormFieldLabel, { f: f }), elements.includes('control') && (_jsx(UCFormFieldControl, { disabled: disabled, execState: execState, f: f, onChange: onChange })), elements.includes('err') && errMsg && (_jsx(UCFormFieldErr, { errMsg: errMsg })), elements.includes('desc') && _jsx(UCFormFieldDesc, { f: f })] }));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { TBoolean } from '../../dt/index.js';
|
|
3
|
-
import {
|
|
3
|
+
import { ucifRepeatability } from '../../uc/index.js';
|
|
4
4
|
import { styleDef, useStyleContext, } from '../lib/react/StyleContextProvider.js';
|
|
5
5
|
import { htmlInputDef } from '../lib/web/input.js';
|
|
6
6
|
const CHECKED_FIELD_TYPES = ['checkbox', 'radio'];
|
|
@@ -27,7 +27,8 @@ export function UCFormFieldControl({ disabled, errMsg = null, execState, f, onCh
|
|
|
27
27
|
if (target.localName === 'select' && !value) {
|
|
28
28
|
// Prevent the value from being '' when we set/unset the select
|
|
29
29
|
// Otherwise it sets '' as value and prevents the form for being valid
|
|
30
|
-
|
|
30
|
+
f.clear();
|
|
31
|
+
onChangeBase();
|
|
31
32
|
return;
|
|
32
33
|
}
|
|
33
34
|
if (CHECKED_FIELD_TYPES.includes(type) && 'checked' in target) {
|
|
@@ -41,10 +42,12 @@ export function UCFormFieldControl({ disabled, errMsg = null, execState, f, onCh
|
|
|
41
42
|
const valueArr = value
|
|
42
43
|
.split(MULTIPLE_VALUES_SEPARATOR)
|
|
43
44
|
.map((v) => v.trim());
|
|
44
|
-
|
|
45
|
+
f.setVal(valueArr);
|
|
46
|
+
onChangeBase();
|
|
45
47
|
}
|
|
46
48
|
else {
|
|
47
|
-
|
|
49
|
+
f.setVal(value);
|
|
50
|
+
onChangeBase();
|
|
48
51
|
}
|
|
49
52
|
};
|
|
50
53
|
const defaultChecked = attrs.internal?.checked;
|
|
@@ -62,7 +62,7 @@ export declare class AppTester {
|
|
|
62
62
|
checkUCDSources(): Promise<void>;
|
|
63
63
|
checkUC(ucdRef: AppTesterUCDRef): Promise<void>;
|
|
64
64
|
execFlow(flow: AppTesterFlow): Promise<AppTesterFlowExecOutput>;
|
|
65
|
-
execMonkeyTest<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>(ucd: UCDef<I, OPI0, OPI1>, input: I): Promise<UCExecutorExecOutput<I, OPI0, OPI1>>;
|
|
65
|
+
execMonkeyTest<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>(ucd: UCDef<I, OPI0, OPI1>, input: NonNullable<I>): Promise<UCExecutorExecOutput<I, OPI0, OPI1>>;
|
|
66
66
|
execUC<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>(input: Omit<UCExecutorInput<I, OPI0, OPI1>, 'appManifest'>, flow?: AppTesterFlow): Promise<AppTestSuiteTestResult<I, OPI0, OPI1>>;
|
|
67
67
|
finalize(): Promise<void>;
|
|
68
68
|
getCtx(): AppTesterCtx;
|
|
@@ -13,7 +13,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
13
13
|
import { inject, injectable } from 'inversify';
|
|
14
14
|
import { I18nEN } from '../i18n/locales/en.js';
|
|
15
15
|
import { I18nFR } from '../i18n/locales/fr.js';
|
|
16
|
-
import { FAKE_USER_ADMIN, UCBuilder,
|
|
16
|
+
import { FAKE_USER_ADMIN, UCBuilder, ucHTTPContract, } from '../uc/index.js';
|
|
17
17
|
// We inject directly the implementation because we'll generate all the reports and not only the one that is bound to the interface.
|
|
18
18
|
// We can plan a setting à la Vitest where we specify the types of reports to generate though.
|
|
19
19
|
import { SimpleHTMLAppTestReportEmitter } from './impl/SimpleHTMLAppTestReportEmitter.js';
|
|
@@ -137,7 +137,8 @@ let AppTester = class AppTester {
|
|
|
137
137
|
if (inputOverride) {
|
|
138
138
|
const inputOverrides = inputOverride(output);
|
|
139
139
|
for (const [k, v] of Object.entries(inputOverrides)) {
|
|
140
|
-
|
|
140
|
+
// @ts-expect-error
|
|
141
|
+
uc.inputField(k).setVal(v);
|
|
141
142
|
}
|
|
142
143
|
}
|
|
143
144
|
};
|
|
@@ -140,7 +140,7 @@ const template = (appPath, testResults, testSummary) => `<!DOCTYPE html>
|
|
|
140
140
|
const search = new URLSearchParams(window.location.search);
|
|
141
141
|
const status = search.get('status');
|
|
142
142
|
if (status) {
|
|
143
|
-
document.querySelectorAll(\`table tbody tr:not(.\${status
|
|
143
|
+
document.querySelectorAll(\`table tbody tr:not(.\${status})\`).forEach((n) => n.remove());
|
|
144
144
|
}
|
|
145
145
|
</script>
|
|
146
146
|
</table>
|
|
@@ -92,9 +92,9 @@ let TypeScriptLibUCDefASTParser = class TypeScriptLibUCDefASTParser {
|
|
|
92
92
|
target)],
|
|
93
93
|
};
|
|
94
94
|
this.compilerOptions.incremental = false; // Otherwise it triggers the following error : Option '--incremental' can only be specified using tsconfig, emitting to single file or when option '--tsBuildInfoFile' is specified.
|
|
95
|
-
// @ts-
|
|
95
|
+
// @ts-expect-error
|
|
96
96
|
this.compilerOptions.jsx = undefined; // Otherwise it triggers the following error since TS 5.5 : jsx is a string value; tsconfig JSON must be parsed with parseJsonSourceFileConfigFileContent or getParsedCommandLineOfConfigFile before passing to createProgram
|
|
97
|
-
// @ts-
|
|
97
|
+
// @ts-expect-error
|
|
98
98
|
this.compilerOptions.lib = undefined; // Otherwise it triggers errors saying it does not find them
|
|
99
99
|
}
|
|
100
100
|
getTypeFields(node) {
|
|
@@ -186,7 +186,7 @@ describe('Run', async () => {
|
|
|
186
186
|
expect(out).toSatisfy(assertion);
|
|
187
187
|
} else {
|
|
188
188
|
expect({ out, sideEffects }).toMatchSnapshot(
|
|
189
|
-
\`hash = \${hash
|
|
189
|
+
\`hash = \${hash}\`,
|
|
190
190
|
);
|
|
191
191
|
}
|
|
192
192
|
},
|
|
@@ -209,7 +209,10 @@ describe('Run', async () => {
|
|
|
209
209
|
}
|
|
210
210
|
|
|
211
211
|
public async run(_m: Model, _r: RealSystem): Promise<void> {
|
|
212
|
-
const out = await runner.execMonkeyTest(
|
|
212
|
+
const out = await runner.execMonkeyTest(
|
|
213
|
+
ucd,
|
|
214
|
+
this.input,
|
|
215
|
+
);
|
|
213
216
|
|
|
214
217
|
if (out.err !== null) {
|
|
215
218
|
if (!(out.err instanceof CustomError)) {
|
|
@@ -220,7 +223,7 @@ describe('Run', async () => {
|
|
|
220
223
|
}
|
|
221
224
|
|
|
222
225
|
public toString(): string {
|
|
223
|
-
return \`\${ucd.metadata.name
|
|
226
|
+
return \`\${ucd.metadata.name}(\${JSON.stringify(this.input)})\`;
|
|
224
227
|
}
|
|
225
228
|
}
|
|
226
229
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TFile } from '../dt/index.js';
|
|
2
|
-
import {
|
|
2
|
+
import { ucifIsMandatory, ucifMustBeFilledManually, ucifRepeatability, } from '../uc/index.js';
|
|
3
3
|
export const DEFAULT_UC_INPUT_FILLERS = [
|
|
4
4
|
'ALL_WITH_EXAMPLES',
|
|
5
5
|
'ONLY_MANDATORY_WITH_EXAMPLES',
|
|
@@ -36,19 +36,20 @@ export function onlySetProgrammaticallyWithExamples(uc) {
|
|
|
36
36
|
// biome-ignore lint/suspicious/noExplicitAny: can be anything
|
|
37
37
|
function fillWithExample(f) {
|
|
38
38
|
const { type } = f.def;
|
|
39
|
-
let val = type.getExamples()?.[0] ?? type.example();
|
|
40
39
|
if (type instanceof TFile) {
|
|
41
|
-
const
|
|
40
|
+
const example = type.getExamples()?.[0] ?? type.example();
|
|
42
41
|
// TODO : Consider building a real file with real data (e.g. image, pdf, txt, etc.)
|
|
43
|
-
val = new File(['01010101010101010101010101010101'],
|
|
44
|
-
type:
|
|
42
|
+
const val = new File(['01010101010101010101010101010101'], example.path, {
|
|
43
|
+
type: example.type,
|
|
45
44
|
});
|
|
45
|
+
const [isRepeatable] = ucifRepeatability(f.def);
|
|
46
|
+
if (isRepeatable) {
|
|
47
|
+
f.addVal(val);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
f.setVal(val);
|
|
51
|
+
}
|
|
52
|
+
return;
|
|
46
53
|
}
|
|
47
|
-
|
|
48
|
-
if (isRepeatable) {
|
|
49
|
-
f.setValue(UCInputFieldChangeOperator.ADD, val);
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
f.setValue(UCInputFieldChangeOperator.SET, val);
|
|
53
|
-
}
|
|
54
|
+
f.fillWithExample();
|
|
54
55
|
}
|
|
@@ -92,13 +92,13 @@ let UCExecutor = class UCExecutor {
|
|
|
92
92
|
if (Array.isArray(v)) {
|
|
93
93
|
v.forEach((vv, idx) => {
|
|
94
94
|
if (vv instanceof File) {
|
|
95
|
-
// @ts-
|
|
95
|
+
// @ts-expect-error
|
|
96
96
|
input[k][idx] = this.derandomizeInputFile(vv);
|
|
97
97
|
}
|
|
98
98
|
});
|
|
99
99
|
}
|
|
100
100
|
else if (v instanceof File) {
|
|
101
|
-
// @ts-
|
|
101
|
+
// @ts-expect-error
|
|
102
102
|
input[k] = this.derandomizeInputFile(v);
|
|
103
103
|
}
|
|
104
104
|
}
|
package/dist/esm/uc/UC.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { AppManifest } from '../app/index.js';
|
|
|
2
2
|
import { type DataType, Validation } from '../dt/index.js';
|
|
3
3
|
import type { UCAuth } from './auth.js';
|
|
4
4
|
import type { UCDef, UCFieldKey } from './def.js';
|
|
5
|
-
import type { UCInput } from './input.js';
|
|
5
|
+
import type { UCInput, UCInputKey, UCInputKeyDataType, UCInputPartial } from './input.js';
|
|
6
6
|
import type { UCOPIBase } from './opi.js';
|
|
7
7
|
import { UCInputField } from './UCInputField.js';
|
|
8
8
|
import type { reqVal0, rVal0, rValArr } from './utils/rVal.js';
|
|
@@ -16,15 +16,15 @@ export declare class UC<I extends UCInput | undefined = undefined, OPI0 extends
|
|
|
16
16
|
appManifest: AppManifest;
|
|
17
17
|
def: UCDef<I, OPI0, OPI1>;
|
|
18
18
|
auth: UCAuth | null;
|
|
19
|
-
inputFields: UCInputField<
|
|
19
|
+
inputFields: UCInputField<DataType>[];
|
|
20
20
|
constructor(appManifest: AppManifest, def: UCDef<I, OPI0, OPI1>, auth: UCAuth | null);
|
|
21
21
|
clear(): void;
|
|
22
22
|
clearSensitiveInputFields(): void;
|
|
23
|
-
fill(input:
|
|
23
|
+
fill(input: UCInputPartial<I>): this;
|
|
24
24
|
hasInputField(key: UCFieldKey): boolean;
|
|
25
25
|
hasMediaInInput(): boolean;
|
|
26
26
|
hasOutputParts(): boolean;
|
|
27
|
-
inputField<
|
|
27
|
+
inputField<K extends UCInputKey<I>>(key: K): UCInputField<UCInputKeyDataType<I, K>>;
|
|
28
28
|
inputFieldsForForm(): UCInputField<any>[];
|
|
29
29
|
inputFieldsOrdered(): UCInputField<any>[];
|
|
30
30
|
inputFieldsInsensitive(): UCInputField<any>[];
|
|
@@ -32,8 +32,8 @@ export declare class UC<I extends UCInput | undefined = undefined, OPI0 extends
|
|
|
32
32
|
needsInputFilling(): boolean;
|
|
33
33
|
needsOutputDisplay(): boolean;
|
|
34
34
|
operatesOnAggregate(): boolean;
|
|
35
|
-
rVal0<
|
|
36
|
-
reqVal0<
|
|
37
|
-
rValArr<
|
|
35
|
+
rVal0<K extends UCInputKey<I>>(key: K): ReturnType<typeof rVal0<UCInputKeyDataType<I, K>>>;
|
|
36
|
+
reqVal0<K extends UCInputKey<I>>(key: K): ReturnType<typeof reqVal0<UCInputKeyDataType<I, K>>>;
|
|
37
|
+
rValArr<K extends UCInputKey<I>>(key: K): ReturnType<typeof rValArr<UCInputKeyDataType<I, K>>>;
|
|
38
38
|
validate(): [UCInputField<any> | null, Validation] | null;
|
|
39
39
|
}
|
package/dist/esm/uc/UC.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { TFile, Validation } from '../dt/index.js';
|
|
2
2
|
import { isBlank } from '../utils/index.js';
|
|
3
|
-
import {
|
|
3
|
+
import { ucifIsMandatory, ucifIsSensitive, ucifMustBeFilledManually, } from './input-field.js';
|
|
4
4
|
import { AggregateInputDef } from './io/input/AggregateInput.js';
|
|
5
5
|
import { ListInputDef } from './io/input/ListInput.js';
|
|
6
6
|
import { UCInputField } from './UCInputField.js';
|
|
@@ -8,7 +8,6 @@ export class UC {
|
|
|
8
8
|
appManifest;
|
|
9
9
|
def;
|
|
10
10
|
auth;
|
|
11
|
-
// biome-ignore lint/suspicious/noExplicitAny: can be anything
|
|
12
11
|
inputFields;
|
|
13
12
|
constructor(appManifest, def, auth) {
|
|
14
13
|
this.appManifest = appManifest;
|
|
@@ -40,7 +39,8 @@ export class UC {
|
|
|
40
39
|
}
|
|
41
40
|
fill(input) {
|
|
42
41
|
for (const f of this.inputFields) {
|
|
43
|
-
|
|
42
|
+
const val = input[f.key];
|
|
43
|
+
f.setVal(val);
|
|
44
44
|
}
|
|
45
45
|
return this;
|
|
46
46
|
}
|
|
@@ -58,6 +58,7 @@ export class UC {
|
|
|
58
58
|
if (!field) {
|
|
59
59
|
throw new Error(`Input field ${key.toString()} does not exist`);
|
|
60
60
|
}
|
|
61
|
+
// @ts-expect-error
|
|
61
62
|
return field;
|
|
62
63
|
}
|
|
63
64
|
// biome-ignore lint/suspicious/noExplicitAny: can be anything
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type DataType, Validation } from '../dt/index.js';
|
|
2
2
|
import type { UCFieldKey, UCWording } from './def.js';
|
|
3
|
-
import {
|
|
3
|
+
import { type UCInputFieldDef, type UCInputFieldValue } from './input-field.js';
|
|
4
4
|
import { type reqVal0, rVal0, rValArr } from './utils/rVal.js';
|
|
5
5
|
export declare class UCInputField<T extends DataType> {
|
|
6
6
|
key: UCFieldKey;
|
|
@@ -13,7 +13,9 @@ export declare class UCInputField<T extends DataType> {
|
|
|
13
13
|
private dynamicWording;
|
|
14
14
|
private value;
|
|
15
15
|
constructor(key: UCFieldKey, def: UCInputFieldDef<T>);
|
|
16
|
+
addVal(value: UCInputFieldValue<T>): void;
|
|
16
17
|
clear(): void;
|
|
18
|
+
fillWithExample(): void;
|
|
17
19
|
getDynamicWording(): Partial<UCWording> | undefined;
|
|
18
20
|
getValue(): UCInputFieldValue<T>;
|
|
19
21
|
/**
|
|
@@ -35,14 +37,15 @@ export declare class UCInputField<T extends DataType> {
|
|
|
35
37
|
*/
|
|
36
38
|
reqVal0(): ReturnType<typeof reqVal0<T>>;
|
|
37
39
|
/**
|
|
38
|
-
*
|
|
40
|
+
* Read the value as an array
|
|
39
41
|
*
|
|
40
42
|
* Unlink the standalone {@link rValArr}, it returns the default value in an array if present.
|
|
41
43
|
*
|
|
42
44
|
* @returns
|
|
43
45
|
*/
|
|
44
46
|
rValArr(): ReturnType<typeof rValArr<T>>;
|
|
45
|
-
|
|
47
|
+
rmVal(value: UCInputFieldValue<T>): void;
|
|
48
|
+
setVal(value: UCInputFieldValue<T>): void;
|
|
46
49
|
updateDef(def: UCInputFieldDef<T>): void;
|
|
47
50
|
updateDynamicWording(dynamicWording: Partial<UCWording> | undefined): void;
|
|
48
51
|
updateType(type: UCInputFieldDef<T>['type']): void;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Validation } from '../dt/index.js';
|
|
2
2
|
import { isBlank } from '../utils/index.js';
|
|
3
|
-
import {
|
|
3
|
+
import { ucifIsMandatory, ucifMustBeFilledManually, ucifRepeatability, } from './input-field.js';
|
|
4
4
|
import { rVal0, rValArr } from './utils/rVal.js';
|
|
5
|
-
import { ucifcoIsForArray } from './utils/ucifcoIsForArray.js';
|
|
6
5
|
export class UCInputField {
|
|
7
6
|
key;
|
|
8
7
|
def;
|
|
@@ -21,6 +20,18 @@ export class UCInputField {
|
|
|
21
20
|
this.value = initialValue;
|
|
22
21
|
}
|
|
23
22
|
}
|
|
23
|
+
addVal(value) {
|
|
24
|
+
const { type } = this.def;
|
|
25
|
+
type.assign(value);
|
|
26
|
+
const val = type.val();
|
|
27
|
+
if (val === undefined) {
|
|
28
|
+
// The value is invalid for T (we might want to throw an error here)
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const current = Array.isArray(this.value) ? this.value : [];
|
|
32
|
+
// We are not really forced to use immutability here, to be reconsidered
|
|
33
|
+
this.value = current.concat([val]);
|
|
34
|
+
}
|
|
24
35
|
clear() {
|
|
25
36
|
this.value = undefined;
|
|
26
37
|
const initialValue = this.def.type.getInitialValue();
|
|
@@ -28,6 +39,18 @@ export class UCInputField {
|
|
|
28
39
|
this.value = initialValue;
|
|
29
40
|
}
|
|
30
41
|
}
|
|
42
|
+
fillWithExample() {
|
|
43
|
+
this.clear();
|
|
44
|
+
const [isRepeatable] = ucifRepeatability(this.def);
|
|
45
|
+
const { type } = this.def;
|
|
46
|
+
const val = type.getExamples()?.[0] ?? type.example();
|
|
47
|
+
if (isRepeatable) {
|
|
48
|
+
this.addVal(val);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
this.setVal(val);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
31
54
|
getDynamicWording() {
|
|
32
55
|
return this.dynamicWording;
|
|
33
56
|
}
|
|
@@ -77,7 +100,7 @@ export class UCInputField {
|
|
|
77
100
|
throw new Error(`${this.key.toString()} is not set and has no default value. Do not require it.`);
|
|
78
101
|
}
|
|
79
102
|
/**
|
|
80
|
-
*
|
|
103
|
+
* Read the value as an array
|
|
81
104
|
*
|
|
82
105
|
* Unlink the standalone {@link rValArr}, it returns the default value in an array if present.
|
|
83
106
|
*
|
|
@@ -100,40 +123,27 @@ export class UCInputField {
|
|
|
100
123
|
// Otherwise, we could not get the value of an optional repeatable field (see remark above on the defaultValue).
|
|
101
124
|
return [];
|
|
102
125
|
}
|
|
103
|
-
|
|
104
|
-
if (op === UCInputFieldChangeOperator.RESET) {
|
|
105
|
-
this.clear();
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
126
|
+
rmVal(value) {
|
|
108
127
|
const { type } = this.def;
|
|
109
128
|
type.assign(value);
|
|
110
129
|
const val = type.val();
|
|
111
130
|
if (val === undefined) {
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
if (!ucifcoIsForArray(op)) {
|
|
115
|
-
// Using a switch, even for just one case, to have it trigger an error if we miss to handle an enum value
|
|
116
|
-
switch (op) {
|
|
117
|
-
case UCInputFieldChangeOperator.SET:
|
|
118
|
-
this.value = val;
|
|
119
|
-
break;
|
|
120
|
-
default:
|
|
121
|
-
((_) => { })(op);
|
|
122
|
-
}
|
|
131
|
+
// The value is invalid for T (we might want to throw an error here)
|
|
123
132
|
return;
|
|
124
133
|
}
|
|
125
134
|
const current = Array.isArray(this.value) ? this.value : [];
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
135
|
+
// We are not really forced to use immutability here, to be reconsidered
|
|
136
|
+
this.value = current.filter((v) => v !== val);
|
|
137
|
+
}
|
|
138
|
+
setVal(value) {
|
|
139
|
+
const { type } = this.def;
|
|
140
|
+
type.assign(value);
|
|
141
|
+
const val = type.val();
|
|
142
|
+
if (val === undefined) {
|
|
143
|
+
// The value is invalid for T (we might want to throw an error here)
|
|
144
|
+
return;
|
|
136
145
|
}
|
|
146
|
+
this.value = val;
|
|
137
147
|
}
|
|
138
148
|
updateDef(def) {
|
|
139
149
|
this.def = def;
|
package/dist/esm/uc/index.d.ts
CHANGED
|
@@ -50,7 +50,6 @@ export * from './utils/rInput.js';
|
|
|
50
50
|
export * from './utils/rVal.js';
|
|
51
51
|
export * from './utils/stripUCDLifecycleServer.js';
|
|
52
52
|
export * from './utils/ucHTTPContract.js';
|
|
53
|
-
export * from './utils/ucifcoIsForArray.js';
|
|
54
53
|
export * from './utils/ucMountingPoint.js';
|
|
55
54
|
export * from './value.js';
|
|
56
55
|
export * from './workers/SimpleAggregateFinder.js';
|
package/dist/esm/uc/index.js
CHANGED
|
@@ -50,7 +50,6 @@ export * from './utils/rInput.js';
|
|
|
50
50
|
export * from './utils/rVal.js';
|
|
51
51
|
export * from './utils/stripUCDLifecycleServer.js';
|
|
52
52
|
export * from './utils/ucHTTPContract.js';
|
|
53
|
-
export * from './utils/ucifcoIsForArray.js';
|
|
54
53
|
export * from './utils/ucMountingPoint.js';
|
|
55
54
|
export * from './value.js';
|
|
56
55
|
export * from './workers/SimpleAggregateFinder.js';
|
|
@@ -1,24 +1,6 @@
|
|
|
1
1
|
import type { DataType, TBase, UIntQuantity } from '../dt/index.js';
|
|
2
2
|
import type { UCFieldKey } from './def.js';
|
|
3
3
|
import type { Value } from './value.js';
|
|
4
|
-
export declare enum UCInputFieldChangeOperator {
|
|
5
|
-
/**
|
|
6
|
-
* Considering the cardinality of the field (min > 1), add a new value
|
|
7
|
-
*/
|
|
8
|
-
ADD = "ADD",
|
|
9
|
-
/**
|
|
10
|
-
* Considering the cardinality of the field (min > 1), remove a value
|
|
11
|
-
*/
|
|
12
|
-
REMOVE = "REMOVE",
|
|
13
|
-
/**
|
|
14
|
-
* Reset the value of the field
|
|
15
|
-
*/
|
|
16
|
-
RESET = "RESET",
|
|
17
|
-
/**
|
|
18
|
-
* Considering the cardinality of the field (max <= 1), set the value
|
|
19
|
-
*/
|
|
20
|
-
SET = "SET"
|
|
21
|
-
}
|
|
22
4
|
export declare enum UCInputFieldFillingMode {
|
|
23
5
|
/**
|
|
24
6
|
* Set programmatically on behalf of the user (e.g. a foreign key id for a given object)
|
|
@@ -72,7 +54,8 @@ export interface UCInputFieldDef<T extends DataType> {
|
|
|
72
54
|
transient?: boolean;
|
|
73
55
|
type: TBase<T>;
|
|
74
56
|
}
|
|
75
|
-
export type UCInputFieldValue<T
|
|
57
|
+
export type UCInputFieldValue<T> = Value<T>;
|
|
58
|
+
export type UCInputFieldValueUnwrapped<T> = T extends UCInputFieldValue<infer U> ? U : never;
|
|
76
59
|
export declare function ucifExamples<T extends DataType>(def: UCInputFieldDef<T>): T[] | undefined;
|
|
77
60
|
export declare function ucifHint<T extends DataType>(def: UCInputFieldDef<T>): string | undefined;
|
|
78
61
|
/**
|
|
@@ -1,22 +1,3 @@
|
|
|
1
|
-
export var UCInputFieldChangeOperator;
|
|
2
|
-
(function (UCInputFieldChangeOperator) {
|
|
3
|
-
/**
|
|
4
|
-
* Considering the cardinality of the field (min > 1), add a new value
|
|
5
|
-
*/
|
|
6
|
-
UCInputFieldChangeOperator["ADD"] = "ADD";
|
|
7
|
-
/**
|
|
8
|
-
* Considering the cardinality of the field (min > 1), remove a value
|
|
9
|
-
*/
|
|
10
|
-
UCInputFieldChangeOperator["REMOVE"] = "REMOVE";
|
|
11
|
-
/**
|
|
12
|
-
* Reset the value of the field
|
|
13
|
-
*/
|
|
14
|
-
UCInputFieldChangeOperator["RESET"] = "RESET";
|
|
15
|
-
/**
|
|
16
|
-
* Considering the cardinality of the field (max <= 1), set the value
|
|
17
|
-
*/
|
|
18
|
-
UCInputFieldChangeOperator["SET"] = "SET";
|
|
19
|
-
})(UCInputFieldChangeOperator || (UCInputFieldChangeOperator = {}));
|
|
20
1
|
export var UCInputFieldFillingMode;
|
|
21
2
|
(function (UCInputFieldFillingMode) {
|
|
22
3
|
/**
|
package/dist/esm/uc/input.d.ts
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
|
+
import type { DataType } from '../dt/index.js';
|
|
1
2
|
import type { StringKeys } from '../utils/index.js';
|
|
2
|
-
import type { UCInputFieldDef } from './input-field.js';
|
|
3
|
+
import type { UCInputFieldDef, UCInputFieldValue, UCInputFieldValueUnwrapped } from './input-field.js';
|
|
3
4
|
/**
|
|
4
5
|
* Base interface all the use case input interfaces must extend
|
|
5
6
|
*/
|
|
6
|
-
export
|
|
7
|
-
|
|
7
|
+
export type UCInput = {};
|
|
8
|
+
export type UCInputUnwrapped<I extends UCInput | undefined> = {
|
|
9
|
+
[K in keyof I]: UCInputFieldValueUnwrapped<I[K]>;
|
|
10
|
+
};
|
|
11
|
+
export type UCInputKey<I extends UCInput | undefined> = StringKeys<UCInputUnwrapped<I>>;
|
|
12
|
+
export type UCInputPartial<I extends UCInput | undefined> = Partial<Record<UCInputKey<I>, UCInputFieldValue<DataType>>>;
|
|
13
|
+
export type UCInputKeyDataType<I extends UCInput | undefined, K extends UCInputKey<I>> = NonNullable<UCInputUnwrapped<I>[K]>;
|
|
8
14
|
/**
|
|
9
15
|
* Definition of a use case input
|
|
10
16
|
*/
|
|
@@ -12,11 +18,11 @@ export interface UCInputDef<I extends UCInput> {
|
|
|
12
18
|
/**
|
|
13
19
|
* This is useful when you want to render a given field only after its dependent fields have been set.
|
|
14
20
|
*/
|
|
15
|
-
dependencies?: Partial<Record<
|
|
21
|
+
dependencies?: Partial<Record<UCInputKey<I>, UCInputKey<I>[]>>;
|
|
16
22
|
/**
|
|
17
23
|
* It must follow strictly the shape of the corresponding {@link UCInput} with fields sorted alphabetically.
|
|
18
24
|
*/
|
|
19
|
-
fields: Record<
|
|
25
|
+
fields: Record<UCInputKey<I>, UCInputFieldDef<any>>;
|
|
20
26
|
/**
|
|
21
27
|
* By default, the fields are displayed in the same order as in {@link fields} (i.e. alphabetically).
|
|
22
28
|
*
|
|
@@ -24,13 +30,13 @@ export interface UCInputDef<I extends UCInput> {
|
|
|
24
30
|
*
|
|
25
31
|
* For example, when rendering a form, this is used.
|
|
26
32
|
*/
|
|
27
|
-
order?:
|
|
33
|
+
order?: UCInputKey<I>[];
|
|
28
34
|
/**
|
|
29
35
|
* Cross-field validation rules
|
|
30
36
|
*
|
|
31
37
|
* For example, if you want the user to provide `a` OR `b` but not both.
|
|
32
38
|
*/
|
|
33
39
|
validation?: {
|
|
34
|
-
or?:
|
|
40
|
+
or?: UCInputKey<I>[];
|
|
35
41
|
};
|
|
36
42
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TBoolean } from '../../dt/index.js';
|
|
2
|
-
import {
|
|
2
|
+
import { ucifIsMandatory, ucifRepeatability } from '../input-field.js';
|
|
3
3
|
const DEFAULT_OPTS = {
|
|
4
4
|
forceArrayAsEmpty: false,
|
|
5
5
|
forceBooleanAsFalse: true,
|
|
@@ -24,18 +24,19 @@ export function rInput(uc, opts) {
|
|
|
24
24
|
ucifIsMandatory(f.def) &&
|
|
25
25
|
(value === null || value === undefined)) {
|
|
26
26
|
value = false;
|
|
27
|
-
f.
|
|
27
|
+
f.setVal(value);
|
|
28
28
|
}
|
|
29
29
|
const [isRepeatable] = ucifRepeatability(f.def);
|
|
30
30
|
if (forceArrayAsEmpty &&
|
|
31
31
|
isRepeatable &&
|
|
32
32
|
(value === null || value === undefined)) {
|
|
33
33
|
value = [];
|
|
34
|
-
f.
|
|
34
|
+
f.setVal(value);
|
|
35
35
|
}
|
|
36
36
|
if (!ignoreUndefined || (ignoreUndefined && value !== undefined)) {
|
|
37
37
|
// Useful when we get the input before persisting for example.
|
|
38
38
|
// Otherwise it will persist `undefined` as a string in the database, for nothing.
|
|
39
|
+
// @ts-expect-error
|
|
39
40
|
input[f.key] = value;
|
|
40
41
|
}
|
|
41
42
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { DataType } from '../../dt/index.js';
|
|
2
1
|
import type { Value } from '../value.js';
|
|
3
2
|
/**
|
|
4
3
|
* Read the value as a primitive
|
|
@@ -9,7 +8,8 @@ import type { Value } from '../value.js';
|
|
|
9
8
|
* @param or
|
|
10
9
|
* @returns
|
|
11
10
|
*/
|
|
12
|
-
export declare function rVal0<T
|
|
11
|
+
export declare function rVal0<T>(value: Value<T>, or: T): T;
|
|
12
|
+
export declare function rVal0<T>(value: Value<T>, or?: undefined): T | null;
|
|
13
13
|
/**
|
|
14
14
|
* Require the value as a primitive
|
|
15
15
|
*
|
|
@@ -18,13 +18,13 @@ export declare function rVal0<T extends DataType>(value: Value<T>, or?: T): T |
|
|
|
18
18
|
* @param value
|
|
19
19
|
* @returns
|
|
20
20
|
*/
|
|
21
|
-
export declare function reqVal0<T
|
|
21
|
+
export declare function reqVal0<T>(value: Value<T>): T;
|
|
22
22
|
/**
|
|
23
|
-
*
|
|
23
|
+
* Read the value as an array
|
|
24
24
|
*
|
|
25
25
|
* To be used when the field has a 0..* cardinality.
|
|
26
26
|
*
|
|
27
27
|
* @param value
|
|
28
28
|
* @returns
|
|
29
29
|
*/
|
|
30
|
-
export declare function rValArr<T
|
|
30
|
+
export declare function rValArr<T>(value: Value<T>): T[];
|
|
@@ -1,15 +1,4 @@
|
|
|
1
1
|
import { isBlank } from '../../utils/index.js';
|
|
2
|
-
// NOTE : the "r" prefix stands for "read" and the "req" prefix stands for "require"
|
|
3
|
-
/**
|
|
4
|
-
* Read the value as a primitive
|
|
5
|
-
*
|
|
6
|
-
* To be used when the field has a 0..1 cardinality.
|
|
7
|
-
*
|
|
8
|
-
* @param value
|
|
9
|
-
* @param or
|
|
10
|
-
* @returns
|
|
11
|
-
*/
|
|
12
|
-
// TODO : Find a way to return `T` when `or` is set (function override does not work)
|
|
13
2
|
export function rVal0(value, or) {
|
|
14
3
|
if (isBlank(value)) {
|
|
15
4
|
return or ?? null;
|
|
@@ -32,7 +21,7 @@ export function reqVal0(value) {
|
|
|
32
21
|
return val;
|
|
33
22
|
}
|
|
34
23
|
/**
|
|
35
|
-
*
|
|
24
|
+
* Read the value as an array
|
|
36
25
|
*
|
|
37
26
|
* To be used when the field has a 0..* cardinality.
|
|
38
27
|
*
|
package/dist/esm/uc/value.d.ts
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export type Value<T extends DataType> = T | T[] | null | undefined;
|
|
1
|
+
export type Value<T> = T | T[] | null | undefined;
|
|
@@ -12,7 +12,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
12
12
|
};
|
|
13
13
|
import { inject, injectable } from 'inversify';
|
|
14
14
|
import { TFile } from '../../dt/index.js';
|
|
15
|
-
import {
|
|
15
|
+
import { ucifRepeatability } from '../input-field.js';
|
|
16
16
|
import { rVal0, rValArr } from '../utils/rVal.js';
|
|
17
17
|
let UCInputFilesProcessor = class UCInputFilesProcessor {
|
|
18
18
|
clockManager;
|
|
@@ -45,13 +45,13 @@ let UCInputFilesProcessor = class UCInputFilesProcessor {
|
|
|
45
45
|
// Although the field is a file, here we fill it with the refs (for persistence)
|
|
46
46
|
// TODO : Improve the mgmt of FileNameRef vs actual File at the use case level
|
|
47
47
|
// I think we need to introduce another value, something like `setValueSerialized` or similar.
|
|
48
|
-
field.
|
|
48
|
+
field.setVal(fileNameRefs);
|
|
49
49
|
}
|
|
50
50
|
else {
|
|
51
51
|
const file = rVal0(field.getValue());
|
|
52
52
|
if (file) {
|
|
53
53
|
const fileNameRef = await this.processFile(file);
|
|
54
|
-
field.
|
|
54
|
+
field.setVal(fileNameRef);
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
}
|
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.21.0",
|
|
5
5
|
"license": "LGPL-3.0",
|
|
6
6
|
"author": "Chafik H'nini <chafik.hnini@gmail.com>",
|
|
7
7
|
"homepage": "https://libmodulor.c100k.eu",
|
|
@@ -81,11 +81,11 @@
|
|
|
81
81
|
"lint:ci": "biome check"
|
|
82
82
|
},
|
|
83
83
|
"devDependencies": {
|
|
84
|
-
"@biomejs/biome": "^2.
|
|
84
|
+
"@biomejs/biome": "^2.2.0"
|
|
85
85
|
},
|
|
86
86
|
"peerDependencies": {
|
|
87
|
-
"@hono/node-server": "^1.
|
|
88
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
87
|
+
"@hono/node-server": "^1.19.0",
|
|
88
|
+
"@modelcontextprotocol/sdk": "^1.17.3",
|
|
89
89
|
"@stricli/core": "^1.2.0",
|
|
90
90
|
"buffer": "^6.0.3",
|
|
91
91
|
"cookie-parser": "^1.4.7",
|
|
@@ -93,18 +93,18 @@
|
|
|
93
93
|
"express-fileupload": "^1.5.2",
|
|
94
94
|
"fast-check": "^4.2.0",
|
|
95
95
|
"helmet": "^8.1.0",
|
|
96
|
-
"hono": "^4.
|
|
97
|
-
"inversify": "^7.
|
|
96
|
+
"hono": "^4.9.2",
|
|
97
|
+
"inversify": "^7.8.1",
|
|
98
98
|
"jose": "^6.0.12",
|
|
99
99
|
"knex": "^3.1.0",
|
|
100
|
-
"next": "^15.4.
|
|
100
|
+
"next": "^15.4.7",
|
|
101
101
|
"pg": "^8.16.3",
|
|
102
|
-
"react": "^19.1.
|
|
103
|
-
"react-dom": "^19.1.
|
|
104
|
-
"react-native": "^0.79.
|
|
102
|
+
"react": "^19.1.1",
|
|
103
|
+
"react-dom": "^19.1.1",
|
|
104
|
+
"react-native": "^0.79.6",
|
|
105
105
|
"reflect-metadata": "^0.2.2",
|
|
106
106
|
"sqlite3": "^5.1.7",
|
|
107
|
-
"typescript": "^5.
|
|
107
|
+
"typescript": "^5.9.2",
|
|
108
108
|
"vite": "^6.3.5",
|
|
109
109
|
"vitest": "^3.2.4"
|
|
110
110
|
},
|