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.
Files changed (49) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +1 -1
  3. package/dist/esm/apps/Helper/src/lib/project.js +4 -4
  4. package/dist/esm/dt/Validation.js +1 -1
  5. package/dist/esm/dt/final/TGitSSHURL.d.ts +4 -3
  6. package/dist/esm/dt/final/TGitSSHURL.js +1 -1
  7. package/dist/esm/dt/final/TSSHPrivateKey.js +1 -3
  8. package/dist/esm/std/impl/ConsoleLogger.js +2 -2
  9. package/dist/esm/std/impl/FetchHTTPAPICallExecutor.js +1 -1
  10. package/dist/esm/std/impl/NodeFormDataBuilder.js +3 -1
  11. package/dist/esm/std/impl/SimpleHTTPAPICaller.js +1 -1
  12. package/dist/esm/target/lib/cli/CommandExecutor.js +2 -2
  13. package/dist/esm/target/lib/react/UCPanel.js +0 -4
  14. package/dist/esm/target/lib/react/form.d.ts +5 -6
  15. package/dist/esm/target/lib/react/form.js +7 -10
  16. package/dist/esm/target/lib/react/useUC.d.ts +4 -4
  17. package/dist/esm/target/node-mcp-server/NodeLocalStdioMCPServerManager.js +1 -0
  18. package/dist/esm/target/react-native-pure/UCForm.d.ts +1 -1
  19. package/dist/esm/target/react-native-pure/UCForm.js +2 -2
  20. package/dist/esm/target/react-native-pure/UCFormField.d.ts +1 -1
  21. package/dist/esm/target/react-native-pure/UCFormField.js +3 -4
  22. package/dist/esm/target/react-native-pure/UCFormFieldControl.js +13 -7
  23. package/dist/esm/target/react-web-pure/UCForm.d.ts +1 -1
  24. package/dist/esm/target/react-web-pure/UCForm.js +2 -2
  25. package/dist/esm/target/react-web-pure/UCFormField.d.ts +1 -1
  26. package/dist/esm/target/react-web-pure/UCFormField.js +3 -4
  27. package/dist/esm/target/react-web-pure/UCFormFieldControl.js +7 -4
  28. package/dist/esm/testing/AppTester.d.ts +1 -1
  29. package/dist/esm/testing/AppTester.js +3 -2
  30. package/dist/esm/testing/impl/SimpleHTMLAppTestReportEmitter.js +1 -1
  31. package/dist/esm/testing/impl/TypeScriptLibUCDefASTParser.js +2 -2
  32. package/dist/esm/testing/impl/VitestAppTestSuiteEmitter.js +6 -3
  33. package/dist/esm/testing/uc-input.js +13 -12
  34. package/dist/esm/testing/workers/UCExecutor.js +2 -2
  35. package/dist/esm/uc/UC.d.ts +7 -7
  36. package/dist/esm/uc/UC.js +4 -3
  37. package/dist/esm/uc/UCInputField.d.ts +6 -3
  38. package/dist/esm/uc/UCInputField.js +39 -29
  39. package/dist/esm/uc/index.d.ts +0 -1
  40. package/dist/esm/uc/index.js +0 -1
  41. package/dist/esm/uc/input-field.d.ts +2 -19
  42. package/dist/esm/uc/input-field.js +0 -19
  43. package/dist/esm/uc/input.d.ts +13 -7
  44. package/dist/esm/uc/utils/rInput.js +4 -3
  45. package/dist/esm/uc/utils/rVal.d.ts +5 -5
  46. package/dist/esm/uc/utils/rVal.js +1 -12
  47. package/dist/esm/uc/value.d.ts +1 -2
  48. package/dist/esm/uc/workers/UCInputFilesProcessor.js +3 -3
  49. 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
@@ -17,4 +17,4 @@ If you think you can help in any way, feel free to contact me (cf. `author` in `
17
17
 
18
18
  ## ⚖️ License
19
19
 
20
- [LGPL-3.0](https://github.com/c100k/libmodulor/blob/v0.20.0/LICENSE)
20
+ [LGPL-3.0](https://github.com/c100k/libmodulor/blob/v0.21.0/LICENSE)
@@ -81,13 +81,13 @@ export const PACKAGE_JSON = (name) => `{
81
81
  "test": "tsc && vitest run --passWithNoTests"
82
82
  },
83
83
  "dependencies": {
84
- "inversify": "^7.6.1",
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.1.2",
90
- "@types/node": "^22.16.5",
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.8.3",
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 || '').toString();
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?: TStringConstraints & {
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-_]+)\/([A-Za-z0-9-_]+)\.git$`);
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.findIndex((l) => l === this.s().logger_level);
72
- const levelIndex = ConsoleLogger_1.LEVELS.findIndex((l) => l === level);
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-ignore
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, new Blob(chunks, { type: val.type }), basename(val.uri));
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-ignore
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 { UCInputFieldChangeOperator, ucifMustBeFilledManually, } from '../../../uc/index.js';
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.setValue(UCInputFieldChangeOperator.SET, v);
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, UCInputFieldChangeOperator, UCInputFieldValue, UCOPIBase } from '../../../uc/index.js';
4
+ import type { UCInput, UCInputField, UCOPIBase } from '../../../uc/index.js';
5
5
  import type { UCPanelCtx, UCPanelOnSubmit, UCPanelState } from './panel.js';
6
- export type UCFormFieldControlOnChange<T extends DataType = DataType> = (f: UCInputField<T>, op: UCInputFieldChangeOperator, v: UCInputFieldValue<T>) => void;
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<T>;
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>, v: UCInputFieldValue<T>): ErrorMessage | null;
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, v) {
9
- if (isBlank(v)) {
8
+ export function validateFormField(i18nManager, f) {
9
+ if (isBlank(f.getValue())) {
10
10
  return null;
11
11
  }
12
- const vArr = Array.isArray(v) ? v : [v];
13
- for (const vv of vArr) {
14
- const validation = f.def.type.assign(vv).validate();
15
- const violation = validation.get();
16
- if (violation) {
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: Partial<I>) => UC<I, OPI0, OPI1>;
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: Partial<I>) => void;
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: Partial<I>;
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, onChange, onSubmit, uc, }: UCFormProps<I, OPI0, OPI1>): ReactElement;
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, onChange, onSubmit, uc, }) {
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, onChange: onChange }, f.key))), _jsx(UCFormSubmitControl, { disabled: disabled, execState: execState, onPress: onPress, uc: uc })] }));
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, onChange: onChangeBase, only, }: UCFormFieldProps<T>): ReactElement;
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, onChange: onChangeBase, only, }) {
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 = (f, op, v) => {
16
- setErrMsg(validateFormField(i18nManager, f, v));
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 { UCInputFieldChangeOperator, ucifRepeatability, } from '../../uc/index.js';
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
- onChangeBase(f, UCInputFieldChangeOperator.SET, valueArr);
34
+ f.setVal(valueArr);
35
+ onChangeBase();
36
+ setInternalValue(valueArr);
35
37
  }
36
38
  else {
37
- onChangeBase(f, UCInputFieldChangeOperator.SET, value);
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
- onChangeBase(f, UCInputFieldChangeOperator.RESET, null);
46
+ f.clear();
47
+ onChangeBase();
44
48
  setInternalValue(null);
45
49
  return;
46
50
  }
47
- onChangeBase(f, UCInputFieldChangeOperator.SET, value);
51
+ f.setVal(value);
52
+ onChangeBase();
48
53
  setInternalValue(value);
49
54
  };
50
55
  const onValueChange = (value) => {
51
- onChangeBase(f, UCInputFieldChangeOperator.SET, value);
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, onChange, onSubmit: onSubmitBase, uc, }: UCFormProps<I, OPI0, OPI1>): ReactElement;
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, onChange, onSubmit: onSubmitBase, uc, }) {
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, onChange: onChange }, f.key))), _jsx(UCFormSubmitControl, { disabled: disabled, execState: execState, uc: uc })] }));
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, onChange: onChangeBase, only, }: UCFormFieldProps<T>): ReactElement;
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, onChange: onChangeBase, only, }) {
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 = (f, op, v) => {
15
- setErrMsg(validateFormField(i18nManager, f, v));
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 { UCInputFieldChangeOperator, ucifRepeatability, } from '../../uc/index.js';
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
- onChangeBase(f, UCInputFieldChangeOperator.RESET, value);
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
- onChangeBase(f, UCInputFieldChangeOperator.SET, valueArr);
45
+ f.setVal(valueArr);
46
+ onChangeBase();
45
47
  }
46
48
  else {
47
- onChangeBase(f, UCInputFieldChangeOperator.SET, value);
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, UCInputFieldChangeOperator, ucHTTPContract, } from '../uc/index.js';
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
- uc.inputField(k).setValue(UCInputFieldChangeOperator.SET, v);
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\})\`).forEach((n) => n.remove());
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-ignore
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-ignore
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(ucd, this.input);
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\}(\${JSON.stringify(this.input)\})\`;
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 { UCInputFieldChangeOperator, ucifIsMandatory, ucifMustBeFilledManually, ucifRepeatability, } from '../uc/index.js';
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 file = val;
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'], file.path, {
44
- type: file.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
- const [isRepeatable] = ucifRepeatability(f.def);
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-ignore
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-ignore
101
+ // @ts-expect-error
102
102
  input[k] = this.derandomizeInputFile(v);
103
103
  }
104
104
  }
@@ -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<any>[];
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: Partial<I>): this;
23
+ fill(input: UCInputPartial<I>): this;
24
24
  hasInputField(key: UCFieldKey): boolean;
25
25
  hasMediaInInput(): boolean;
26
26
  hasOutputParts(): boolean;
27
- inputField<T extends DataType>(key: keyof NonNullable<I>): UCInputField<T>;
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<T extends DataType>(key: keyof I): ReturnType<typeof rVal0<T>>;
36
- reqVal0<T extends DataType>(key: keyof I): ReturnType<typeof reqVal0<T>>;
37
- rValArr<T extends DataType>(key: keyof I): ReturnType<typeof rValArr<T>>;
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 { UCInputFieldChangeOperator, ucifIsMandatory, ucifIsSensitive, ucifMustBeFilledManually, } from './input-field.js';
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
- f.setValue(UCInputFieldChangeOperator.SET, input[f.key]);
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 { UCInputFieldChangeOperator, type UCInputFieldDef, type UCInputFieldValue } from './input-field.js';
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
- * Require the value as an array
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
- setValue(op: UCInputFieldChangeOperator, value: UCInputFieldValue<T>): void;
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 { UCInputFieldChangeOperator, ucifIsMandatory, ucifMustBeFilledManually, ucifRepeatability, } from './input-field.js';
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
- * Require the value as an array
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
- setValue(op, value) {
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
- return;
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
- switch (op) {
127
- // We are not really forced to use immutability here, but it's better for consistency
128
- case UCInputFieldChangeOperator.ADD:
129
- this.value = current.concat([val]);
130
- break;
131
- case UCInputFieldChangeOperator.REMOVE:
132
- this.value = current.filter((v) => v !== val);
133
- break;
134
- default:
135
- ((_) => { })(op);
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;
@@ -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';
@@ -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 extends DataType> = Value<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
  /**
@@ -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 interface UCInput {
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<StringKeys<I>, StringKeys<I>[]>>;
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<StringKeys<I>, UCInputFieldDef<any>>;
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?: StringKeys<I>[];
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?: StringKeys<I>[];
40
+ or?: UCInputKey<I>[];
35
41
  };
36
42
  }
@@ -1,5 +1,5 @@
1
1
  import { TBoolean } from '../../dt/index.js';
2
- import { UCInputFieldChangeOperator, ucifIsMandatory, ucifRepeatability, } from '../input-field.js';
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.setValue(UCInputFieldChangeOperator.SET, value);
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.setValue(UCInputFieldChangeOperator.SET, value);
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 extends DataType>(value: Value<T>, or?: T): T | null;
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 extends DataType>(value: Value<T>): T;
21
+ export declare function reqVal0<T>(value: Value<T>): T;
22
22
  /**
23
- * Get the value as an array
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 extends DataType>(value: Value<T>): 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
- * Get the value as an array
24
+ * Read the value as an array
36
25
  *
37
26
  * To be used when the field has a 0..* cardinality.
38
27
  *
@@ -1,2 +1 @@
1
- import type { DataType } from '../dt/index.js';
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 { UCInputFieldChangeOperator, ucifRepeatability, } from '../input-field.js';
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.setValue(UCInputFieldChangeOperator.SET, fileNameRefs);
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.setValue(UCInputFieldChangeOperator.SET, fileNameRef);
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.20.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.1.2"
84
+ "@biomejs/biome": "^2.2.0"
85
85
  },
86
86
  "peerDependencies": {
87
- "@hono/node-server": "^1.17.1",
88
- "@modelcontextprotocol/sdk": "^1.16.0",
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.8.5",
97
- "inversify": "^7.6.1",
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.2",
100
+ "next": "^15.4.7",
101
101
  "pg": "^8.16.3",
102
- "react": "^19.1.0",
103
- "react-dom": "^19.1.0",
104
- "react-native": "^0.79.5",
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.8.3",
107
+ "typescript": "^5.9.2",
108
108
  "vite": "^6.3.5",
109
109
  "vitest": "^3.2.4"
110
110
  },