libmodulor 0.24.0 → 0.25.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 (73) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +1 -1
  3. package/dist/esm/apps/Helper/src/lib/project.js +6 -6
  4. package/dist/esm/dt/Validation.d.ts +2 -2
  5. package/dist/esm/dt/base/TBase.d.ts +2 -0
  6. package/dist/esm/dt/base/TBase.js +3 -0
  7. package/dist/esm/dt/base/TObject.d.ts +6 -4
  8. package/dist/esm/dt/base/TObject.js +4 -5
  9. package/dist/esm/dt/base/TString.d.ts +2 -1
  10. package/dist/esm/dt/base/TString.js +22 -0
  11. package/dist/esm/dt/final/TFile.d.ts +13 -4
  12. package/dist/esm/dt/final/TFile.js +70 -8
  13. package/dist/esm/dt/final/TFileExtension.d.ts +1 -1
  14. package/dist/esm/dt/final/TFileMimeType.d.ts +2 -6
  15. package/dist/esm/dt/final/TFileMimeType.js +0 -6
  16. package/dist/esm/dt/final/TFilePath.d.ts +7 -0
  17. package/dist/esm/dt/final/TFilePath.js +5 -1
  18. package/dist/esm/dt/index.d.ts +1 -1
  19. package/dist/esm/i18n/WordingManager.d.ts +2 -1
  20. package/dist/esm/i18n/WordingManager.js +23 -2
  21. package/dist/esm/i18n/locales/de.js +8 -0
  22. package/dist/esm/i18n/locales/en.js +8 -0
  23. package/dist/esm/i18n/locales/es.js +8 -0
  24. package/dist/esm/i18n/locales/fr.js +8 -0
  25. package/dist/esm/i18n/types.d.ts +2 -2
  26. package/dist/esm/std/FSManager.d.ts +7 -5
  27. package/dist/esm/std/FSManager.js +5 -6
  28. package/dist/esm/std/FormDataBuilder.d.ts +2 -1
  29. package/dist/esm/std/impl/NodeFSManager.js +3 -2
  30. package/dist/esm/target/lib/react/StyleContextProvider.d.ts +1 -0
  31. package/dist/esm/target/lib/react/form.d.ts +1 -1
  32. package/dist/esm/target/lib/react/form.js +1 -0
  33. package/dist/esm/target/lib/react/useAction.d.ts +1 -1
  34. package/dist/esm/target/lib/react/useAction.js +13 -12
  35. package/dist/esm/target/lib/server-express/funcs.js +2 -1
  36. package/dist/esm/target/lib/web/input.d.ts +1 -0
  37. package/dist/esm/target/lib/web/input.js +5 -1
  38. package/dist/esm/target/react-native-pure/UCFormField.js +2 -1
  39. package/dist/esm/target/react-native-pure/UCFormFieldControl.js +6 -4
  40. package/dist/esm/target/react-native-pure/UCFormFieldErr.d.ts +1 -1
  41. package/dist/esm/target/react-native-pure/UCFormFieldErr.js +4 -1
  42. package/dist/esm/target/react-native-pure/UCFormFieldHelp.d.ts +4 -0
  43. package/dist/esm/target/react-native-pure/UCFormFieldHelp.js +15 -0
  44. package/dist/esm/target/react-web-pure/UCFormField.js +2 -1
  45. package/dist/esm/target/react-web-pure/UCFormFieldErr.d.ts +1 -1
  46. package/dist/esm/target/react-web-pure/UCFormFieldErr.js +4 -1
  47. package/dist/esm/target/react-web-pure/UCFormFieldHelp.d.ts +4 -0
  48. package/dist/esm/target/react-web-pure/UCFormFieldHelp.js +14 -0
  49. package/dist/esm/testing/impl/SimpleAppDocsEmitter/SimpleAppDocsEmitter.d.ts +7 -0
  50. package/dist/esm/testing/impl/SimpleAppDocsEmitter/SimpleAppDocsEmitter.js +59 -0
  51. package/dist/esm/testing/impl/SimpleAppDocsEmitter/markdown.d.ts +2 -0
  52. package/dist/esm/testing/impl/SimpleAppDocsEmitter/markdown.js +10 -0
  53. package/dist/esm/testing/impl/SimpleAppDocsEmitter/sequence-diagram.d.ts +2 -0
  54. package/dist/esm/testing/impl/SimpleAppDocsEmitter/sequence-diagram.js +92 -0
  55. package/dist/esm/testing/impl/SimpleAppDocsEmitter/tech-summary.d.ts +2 -0
  56. package/dist/esm/testing/impl/SimpleAppDocsEmitter/tech-summary.js +27 -0
  57. package/dist/esm/testing/impl/SimpleAppDocsEmitter/uc-summary.d.ts +2 -0
  58. package/dist/esm/testing/impl/SimpleAppDocsEmitter/uc-summary.js +63 -0
  59. package/dist/esm/testing/impl/newNodeAppTester.js +1 -1
  60. package/dist/esm/testing/uc-input.js +5 -2
  61. package/dist/esm/uc/exec.d.ts +42 -21
  62. package/dist/esm/uc/exec.js +48 -13
  63. package/dist/esm/uc/input-field.d.ts +6 -4
  64. package/dist/esm/uc/input-field.js +4 -5
  65. package/dist/esm/uc/side-effect.d.ts +10 -8
  66. package/dist/esm/uc/side-effect.js +5 -6
  67. package/dist/esm/uc/workers/UCInputFilesProcessor.js +3 -3
  68. package/dist/esm/uc/workers/UCInputValidator.js +2 -1
  69. package/dist/esm/uc/workers/UCOutputFilesProcessor.js +1 -1
  70. package/dist/esm/utils/bundling/webpack/loader.js +1 -1
  71. package/dist/esm/utils/index.d.ts +1 -1
  72. package/dist/esm/utils/types/utility-types.d.ts +4 -0
  73. package/package.json +16 -14
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## v0.25.0 (2025-12-21)
4
+
5
+ **Highlights**
6
+
7
+ - Added use case summary in the auto-generated app docs : In addition to the existing mermaid diagram, there is now a summary of the lifecyle, input and output in a dedicated table
8
+ - Example : https://github.com/c100k/libmodulor/tree/42fd11307cdd9f8cdec19b4de75d4959bc9f9a9e/examples/apps/Spotify#createalbum
9
+ - Improved the `File` data type
10
+ - Changed the property `path` to `uri` to conform to the `FormData` spec (this is a breaking change)
11
+ - Simplified the declaration by inlining the accepted types via `accept` instead of `type.allowed` (this is also a breaking change)
12
+ - Added `maxSizeInBytes` and `minSizeInBytes` for size validation
13
+ - Added `getConstraintsForHuman` to format constraints for the end user in the targets. For instance :
14
+ - For `FreeTextShort`, it displays `Max length: 150` 🇬🇧 when present
15
+ - For `File`, it displays `Max size: 8MB - Accepted types: application/png, application/jpg` 🇬🇧 when present
16
+ - Applied to the `react-native-pure` and `react-native-web` targets (see `UCFormFieldHelp.tsx`)
17
+
18
+ See all the changes here : https://github.com/c100k/libmodulor/compare/v0.24.0...master
19
+
3
20
  ## v0.24.0 (2025-12-07)
4
21
 
5
22
  **Highlights**
package/README.md CHANGED
@@ -169,4 +169,4 @@ If you think you can help in any way, feel free to contact me (cf. `author` in `
169
169
 
170
170
  ## ⚖️ License
171
171
 
172
- [LGPL-3.0](https://github.com/c100k/libmodulor/blob/v0.24.0/LICENSE)
172
+ [LGPL-3.0](https://github.com/c100k/libmodulor/blob/v0.25.0/LICENSE)
@@ -81,21 +81,21 @@ export const PACKAGE_JSON = (name) => `{
81
81
  "test": "tsc && vitest run --passWithNoTests"
82
82
  },
83
83
  "dependencies": {
84
- "inversify": "^7.10.4",
84
+ "inversify": "^7.10.7",
85
85
  "libmodulor": "latest",
86
86
  "reflect-metadata": "^0.2.2"
87
87
  },
88
88
  "devDependencies": {
89
- "@biomejs/biome": "^2.3.8",
90
- "@types/node": "^24.10.1",
89
+ "@biomejs/biome": "^2.3.10",
90
+ "@types/node": "^25.0.3",
91
91
  "@vitest/coverage-v8": "^3.2.4",
92
92
  "buffer": "^6.0.3",
93
93
  "cookie-parser": "^1.4.7",
94
- "express": "^5.1.0",
94
+ "express": "^5.2.1",
95
95
  "express-fileupload": "^1.5.2",
96
- "fast-check": "^4.3.0",
96
+ "fast-check": "^4.4.0",
97
97
  "helmet": "^8.1.0",
98
- "jose": "^6.1.2",
98
+ "jose": "^6.1.3",
99
99
  "typescript": "^5.9.3",
100
100
  "vite": "^6.4.1",
101
101
  "vitest": "^3.2.4"
@@ -1,13 +1,13 @@
1
1
  import type { I18nTranslation } from '../i18n/index.js';
2
2
  import type { NumIndex } from './final/TNumIndex.js';
3
- type ViolationConstraint = 'fieldsOr' | 'format' | 'mandatory' | 'max' | 'maxCount' | 'maxLength' | 'min' | 'minCount' | 'minLength' | 'oneOf' | 'shape' | 'type';
3
+ type ViolationConstraint = 'fieldsOr' | 'format' | 'mandatory' | 'max' | 'maxCount' | 'maxLength' | 'maxSize' | 'min' | 'minCount' | 'minLength' | 'minSize' | 'oneOf' | 'shape' | 'type';
4
4
  type ViolationBase<C extends ViolationConstraint, EV> = {
5
5
  constraint: C;
6
6
  expected: EV;
7
7
  };
8
8
  export type ViolationFormat = 'ColorRGBA' | 'DateISO8601' | 'DirPath' | 'DomainName' | 'Email' | 'FilePath' | 'GitSSHURL' | 'IPv4' | 'IPv6' | 'JSON' | 'JWT' | 'PersonFirstname' | 'PersonFullname' | 'PersonInitials' | 'PersonLastname' | 'QRCode' | 'SemVerVersion' | 'Slug' | 'SSHPrivateKey' | 'SSHPublicKey' | 'Time' | 'URL' | 'UUID';
9
9
  export type ViolationType = 'array' | 'boolean' | 'int' | 'number' | 'object' | 'scalar' | 'string';
10
- export type Violation<T = unknown> = ViolationBase<'fieldsOr', string> | ViolationBase<'format', ViolationFormat> | ViolationBase<'format', string> | ViolationBase<'mandatory', undefined> | ViolationBase<'max', number> | ViolationBase<'maxCount', number> | ViolationBase<'maxLength', number> | ViolationBase<'min', number> | ViolationBase<'minCount', number> | ViolationBase<'minLength', number> | ViolationBase<'oneOf', T[]> | ViolationBase<'shape', object> | ViolationBase<'type', ViolationType>;
10
+ export type Violation<T = unknown> = ViolationBase<'fieldsOr', string> | ViolationBase<'format', ViolationFormat> | ViolationBase<'format', string> | ViolationBase<'mandatory', undefined> | ViolationBase<'max', number> | ViolationBase<'maxCount', number> | ViolationBase<'maxLength', number> | ViolationBase<'maxSize', string> | ViolationBase<'min', number> | ViolationBase<'minCount', number> | ViolationBase<'minLength', number> | ViolationBase<'minSize', string> | ViolationBase<'oneOf', T[]> | ViolationBase<'shape', object> | ViolationBase<'type', ViolationType>;
11
11
  type ViolationI18nableSimple = Exclude<ViolationConstraint, 'format' | 'type'>;
12
12
  export type ViolationI18nable = `validation_${ViolationI18nableSimple}` | `validation_format_${ViolationFormat}` | `validation_type_${ViolationType}`;
13
13
  export type ViolationI18n = Record<ViolationI18nable, I18nTranslation>;
@@ -26,6 +26,7 @@ export interface OptionsOpts {
26
26
  shouldTranslateLabels?: boolean;
27
27
  strict?: boolean;
28
28
  }
29
+ export type ConstraintsForHuman = Record<string, string>;
29
30
  export declare abstract class TBase<T extends DataType> {
30
31
  static DEFAULT_OPTIONS: Required<OptionsOpts>;
31
32
  protected defaultValue: T | undefined;
@@ -44,6 +45,7 @@ export declare abstract class TBase<T extends DataType> {
44
45
  fmt(ifNullOrUndefined?: string): string;
45
46
  getDefaultValue(): T | undefined;
46
47
  getExamples(): T[] | undefined;
48
+ getConstraintsForHuman(): ConstraintsForHuman | null;
47
49
  getInitialValue(): T | undefined;
48
50
  getOptions(): Option<T>[] | undefined;
49
51
  getSemanticsMapping(): SemanticsMapping | undefined;
@@ -39,6 +39,9 @@ export class TBase {
39
39
  getExamples() {
40
40
  return this.examples;
41
41
  }
42
+ getConstraintsForHuman() {
43
+ return null;
44
+ }
42
45
  getInitialValue() {
43
46
  return this.initialValue;
44
47
  }
@@ -1,6 +1,7 @@
1
+ import type { EnumOf } from '../../utils/index.js';
1
2
  import type { Validation } from '../Validation.js';
2
3
  import { TBase, type TName } from './TBase.js';
3
- export declare enum TObjectShapeValidationStrategy {
4
+ export declare const TObjectShapeValidationStrategy: {
4
5
  /**
5
6
  * No shape validation is performed
6
7
  *
@@ -8,14 +9,15 @@ export declare enum TObjectShapeValidationStrategy {
8
9
  *
9
10
  * Otherwise, you can still override {@link validate} in the `T*` class and do your own validation.
10
11
  */
11
- NONE = "NONE",
12
+ readonly NONE: "NONE";
12
13
  /**
13
14
  * Validate against the {@link TObject.example()}
14
15
  *
15
16
  * It checks that the keys of the value, sorted alphabetically, are the same as the example's keys.
16
17
  */
17
- SAME_AS_EXAMPLE = "SAME_AS_EXAMPLE"
18
- }
18
+ readonly SAME_AS_EXAMPLE: "SAME_AS_EXAMPLE";
19
+ };
20
+ export type TObjectShapeValidationStrategy = EnumOf<typeof TObjectShapeValidationStrategy>;
19
21
  export interface TObjectConstraints {
20
22
  /**
21
23
  * @defaultValue {@link TObjectShapeValidationStrategy.SAME_AS_EXAMPLE}
@@ -1,6 +1,5 @@
1
1
  import { TBase } from './TBase.js';
2
- export var TObjectShapeValidationStrategy;
3
- (function (TObjectShapeValidationStrategy) {
2
+ export const TObjectShapeValidationStrategy = {
4
3
  /**
5
4
  * No shape validation is performed
6
5
  *
@@ -8,14 +7,14 @@ export var TObjectShapeValidationStrategy;
8
7
  *
9
8
  * Otherwise, you can still override {@link validate} in the `T*` class and do your own validation.
10
9
  */
11
- TObjectShapeValidationStrategy["NONE"] = "NONE";
10
+ NONE: 'NONE',
12
11
  /**
13
12
  * Validate against the {@link TObject.example()}
14
13
  *
15
14
  * It checks that the keys of the value, sorted alphabetically, are the same as the example's keys.
16
15
  */
17
- TObjectShapeValidationStrategy["SAME_AS_EXAMPLE"] = "SAME_AS_EXAMPLE";
18
- })(TObjectShapeValidationStrategy || (TObjectShapeValidationStrategy = {}));
16
+ SAME_AS_EXAMPLE: 'SAME_AS_EXAMPLE',
17
+ };
19
18
  export class TObject extends TBase {
20
19
  constraints;
21
20
  constructor(constraints = {
@@ -1,5 +1,5 @@
1
1
  import type { Validation, ViolationFormat } from '../Validation.js';
2
- import { TBase, type TName } from './TBase.js';
2
+ import { type ConstraintsForHuman, TBase, type TName } from './TBase.js';
3
3
  export interface TStringConstraints<VF extends ViolationFormat | (string & {}) = ViolationFormat> {
4
4
  format?: {
5
5
  f: VF;
@@ -15,6 +15,7 @@ export declare class TString<T extends string = string, VF extends ViolationForm
15
15
  constructor(constraints?: TStringConstraints<VF> | undefined);
16
16
  tName(): TName;
17
17
  example(): T;
18
+ getConstraintsForHuman(): ConstraintsForHuman | null;
18
19
  getConstraints(): TStringConstraints<VF> | undefined;
19
20
  isPotentiallyLong(): boolean;
20
21
  protected removeFormatConstraint(): void;
@@ -13,6 +13,28 @@ export class TString extends TBase {
13
13
  example() {
14
14
  return 'Miami';
15
15
  }
16
+ getConstraintsForHuman() {
17
+ if (!this.constraints) {
18
+ return null;
19
+ }
20
+ const c = {};
21
+ const { format, maxLength, minLength } = this.constraints;
22
+ if (minLength) {
23
+ // biome-ignore lint/complexity/useLiteralKeys: typescript disagrees
24
+ c['minLength'] = minLength.toString();
25
+ }
26
+ if (maxLength) {
27
+ // biome-ignore lint/complexity/useLiteralKeys: typescript disagrees
28
+ c['maxLength'] = maxLength.toString();
29
+ }
30
+ if (format) {
31
+ // Are regexes really "human" ?
32
+ // TODO : Find a more human way of displaying regexes
33
+ // biome-ignore lint/complexity/useLiteralKeys: typescript disagrees
34
+ c['format'] = format.regexp.toString();
35
+ }
36
+ return c;
37
+ }
16
38
  getConstraints() {
17
39
  return this.constraints;
18
40
  }
@@ -1,23 +1,32 @@
1
- import type { TName } from '../base/TBase.js';
1
+ import type { ConstraintsForHuman, TName } from '../base/TBase.js';
2
2
  import { TObject } from '../base/TObject.js';
3
3
  import type { HTMLInputType } from '../targets/web.js';
4
4
  import type { Validation } from '../Validation.js';
5
- import { type FileMimeType, type TFileMimeTypeConstraints } from './TFileMimeType.js';
5
+ import { type FileMimeType } from './TFileMimeType.js';
6
6
  import { type FileName } from './TFileName.js';
7
7
  import { type FilePath } from './TFilePath.js';
8
+ import type { UIntQuantity } from './TUIntQuantity.js';
8
9
  export type File = {
9
10
  name: FileName;
10
- path: FilePath;
11
+ size: UIntQuantity;
11
12
  type: FileMimeType;
13
+ uri: FilePath;
12
14
  };
13
15
  export interface TFileConstraints {
14
- type: TFileMimeTypeConstraints;
16
+ accept: FileMimeType[];
17
+ maxSizeInBytes?: UIntQuantity;
18
+ minSizeInBytes?: UIntQuantity;
15
19
  }
16
20
  export declare class TFile extends TObject<File> {
17
21
  protected fileConstraints: TFileConstraints;
22
+ static readonly UNITS: string[];
18
23
  constructor(fileConstraints: TFileConstraints);
19
24
  tName(): TName;
20
25
  example(): File;
26
+ getConstraintsForHuman(): ConstraintsForHuman | null;
21
27
  htmlInputType(): HTMLInputType;
22
28
  validate(): Validation;
29
+ getFileConstraints(): TFileConstraints;
30
+ fmtBytes(bytes: number, decimals?: number): string;
31
+ withOneExample(name: File['name']): this;
23
32
  }
@@ -1,9 +1,21 @@
1
1
  import { TObject, TObjectShapeValidationStrategy } from '../base/TObject.js';
2
- import { TFileMimeType, } from './TFileMimeType.js';
2
+ import { TFileMimeType } from './TFileMimeType.js';
3
3
  import { TFileName } from './TFileName.js';
4
4
  import { TFilePath } from './TFilePath.js';
5
5
  export class TFile extends TObject {
6
6
  fileConstraints;
7
+ // We consider them generic enough to not having to be translated
8
+ static UNITS = [
9
+ 'B',
10
+ 'KB',
11
+ 'MB',
12
+ 'GB',
13
+ 'TB',
14
+ 'PB',
15
+ 'EB',
16
+ 'ZB',
17
+ 'YB',
18
+ ];
7
19
  constructor(fileConstraints) {
8
20
  super({
9
21
  // We usually process instances of https://developer.mozilla.org/fr/docs/Web/API/File
@@ -17,11 +29,27 @@ export class TFile extends TObject {
17
29
  }
18
30
  example() {
19
31
  return {
20
- name: 'picture.png',
21
- path: '/Users/dexter/Desktop/picture.png',
22
- type: 'image/png',
32
+ name: TFilePath.FILE_NAME,
33
+ size: TFilePath.FILE_SIZE,
34
+ type: TFilePath.MIME_TYPE,
35
+ uri: `${TFilePath.ABS_PATH}/${TFilePath.FILE_NAME}`,
23
36
  };
24
37
  }
38
+ getConstraintsForHuman() {
39
+ const c = {};
40
+ const { accept, maxSizeInBytes, minSizeInBytes } = this.fileConstraints;
41
+ if (minSizeInBytes) {
42
+ // biome-ignore lint/complexity/useLiteralKeys: typescript disagrees
43
+ c['minSizeInBytes'] = this.fmtBytes(minSizeInBytes);
44
+ }
45
+ if (maxSizeInBytes) {
46
+ // biome-ignore lint/complexity/useLiteralKeys: typescript disagrees
47
+ c['maxSizeInBytes'] = this.fmtBytes(maxSizeInBytes);
48
+ }
49
+ // biome-ignore lint/complexity/useLiteralKeys: typescript disagrees
50
+ c['accept'] = accept.join(', ');
51
+ return c;
52
+ }
25
53
  htmlInputType() {
26
54
  return 'file';
27
55
  }
@@ -32,13 +60,47 @@ export class TFile extends TObject {
32
60
  }
33
61
  const val = this.raw;
34
62
  validation.concat(new TFileName().assign(val.name).validate());
63
+ const { accept, maxSizeInBytes, minSizeInBytes } = this.fileConstraints;
64
+ const { size, type, uri } = val;
35
65
  if (!(val instanceof File)) {
36
- validation.concat(new TFilePath().assign(val.path).validate());
66
+ validation.concat(new TFilePath().assign(uri).validate());
37
67
  }
38
- validation.concat(new TFileMimeType(this.fileConstraints.type)
39
- .assign(val.type)
68
+ validation.concat(new TFileMimeType()
69
+ .setOptions(accept.map((a) => ({ label: a, value: a })))
70
+ .assign(type)
40
71
  .validate());
41
- // TODO : Add validation on file size
72
+ if (minSizeInBytes && size < minSizeInBytes) {
73
+ validation.add({
74
+ constraint: 'minSize',
75
+ expected: this.fmtBytes(minSizeInBytes),
76
+ });
77
+ }
78
+ if (maxSizeInBytes && size > maxSizeInBytes) {
79
+ validation.add({
80
+ constraint: 'maxSize',
81
+ expected: this.fmtBytes(maxSizeInBytes),
82
+ });
83
+ }
42
84
  return validation;
43
85
  }
86
+ getFileConstraints() {
87
+ return this.fileConstraints;
88
+ }
89
+ fmtBytes(bytes, decimals = 2) {
90
+ const k = 1024;
91
+ const dm = decimals < 0 ? 0 : decimals;
92
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
93
+ return `${Number.parseFloat((bytes / k ** i).toFixed(dm))} ${TFile.UNITS[i]}`;
94
+ }
95
+ withOneExample(name) {
96
+ this.setExamples([
97
+ {
98
+ name,
99
+ size: TFilePath.FILE_SIZE,
100
+ type: this.fileConstraints.accept[0] ?? TFilePath.MIME_TYPE,
101
+ uri: `${TFilePath.ABS_PATH}/${name}`,
102
+ },
103
+ ]);
104
+ return this;
105
+ }
44
106
  }
@@ -3,7 +3,7 @@ import { TString, type TStringConstraints } from '../base/TString.js';
3
3
  type ImageExtension = 'gif' | 'heic' | 'jpg' | 'png';
4
4
  type VideoExtension = 'mov' | 'mp4';
5
5
  type XMLExtension = 'gpx' | 'xml';
6
- export type FileExtension = ImageExtension | VideoExtension | XMLExtension;
6
+ export type FileExtension = ImageExtension | VideoExtension | XMLExtension | (string & {});
7
7
  export interface TFileExtensionConstraints extends TStringConstraints {
8
8
  allowed: FileExtension[];
9
9
  }
@@ -1,11 +1,7 @@
1
1
  import type { TName } from '../base/TBase.js';
2
- import { TString, type TStringConstraints } from '../base/TString.js';
3
- export type FileMimeType = 'text/plain' | 'audio/aac' | 'application/x-abiword' | 'application/octet-stream' | 'video/x-msvideo' | 'application/vnd.amazon.ebook' | 'image/bmp' | 'application/x-bzip' | 'application/x-bzip2' | 'application/x-csh' | 'text/css' | 'text/csv' | 'application/msword' | 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' | 'application/vnd.ms-fontobject' | 'application/epub+zip' | 'image/gif' | 'text/html' | 'image/x-icon' | 'text/calendar' | 'application/java-archive' | 'image/jpeg' | 'image/jpg' | 'application/javascript' | 'application/json' | 'audio/midi' | 'video/mpeg' | 'application/vnd.apple.installer+xml' | 'application/vnd.oasis.opendocument.presentation' | 'application/vnd.oasis.opendocument.spreadsheet' | 'application/vnd.oasis.opendocument.text' | 'audio/ogg' | 'video/ogg' | 'application/ogg' | 'font/otf' | 'image/png' | 'application/pdf' | 'application/vnd.ms-powerpoint' | 'application/vnd.openxmlformats-officedocument.presentationml.presentation' | 'application/x-rar-compressed' | 'application/rtf' | 'application/x-sh' | 'image/svg+xml' | 'application/x-shockwave-flash' | 'application/x-tar' | 'image/tiff' | 'application/typescript' | 'font/ttf' | 'application/vnd.visio' | 'audio/x-wav' | 'audio/webm' | 'video/webm' | 'image/webp' | 'font/woff' | 'font/woff2' | 'application/xhtml+xml' | 'application/vnd.ms-excel' | 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' | 'application/xml' | 'application/vnd.mozilla.xul+xml' | 'application/zip' | 'video/3gpp audio/3gpp' | 'video/3gpp2 audio/3gpp2' | 'application/x-7z-compressed';
4
- export interface TFileMimeTypeConstraints extends TStringConstraints {
5
- allowed: FileMimeType[];
6
- }
2
+ import { TString } from '../base/TString.js';
3
+ export type FileMimeType = 'text/plain' | 'audio/aac' | 'application/x-abiword' | 'application/octet-stream' | 'video/x-msvideo' | 'application/vnd.amazon.ebook' | 'image/bmp' | 'application/x-bzip' | 'application/x-bzip2' | 'application/x-csh' | 'text/css' | 'text/csv' | 'application/msword' | 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' | 'application/vnd.ms-fontobject' | 'application/epub+zip' | 'image/gif' | 'text/html' | 'image/x-icon' | 'text/calendar' | 'application/java-archive' | 'image/jpeg' | 'image/jpg' | 'application/javascript' | 'application/json' | 'audio/midi' | 'video/mpeg' | 'application/vnd.apple.installer+xml' | 'application/vnd.oasis.opendocument.presentation' | 'application/vnd.oasis.opendocument.spreadsheet' | 'application/vnd.oasis.opendocument.text' | 'audio/ogg' | 'video/ogg' | 'application/ogg' | 'font/otf' | 'image/png' | 'application/pdf' | 'application/vnd.ms-powerpoint' | 'application/vnd.openxmlformats-officedocument.presentationml.presentation' | 'application/x-rar-compressed' | 'application/rtf' | 'application/x-sh' | 'image/svg+xml' | 'application/x-shockwave-flash' | 'application/x-tar' | 'image/tiff' | 'application/typescript' | 'font/ttf' | 'application/vnd.visio' | 'audio/x-wav' | 'audio/webm' | 'video/webm' | 'image/webp' | 'font/woff' | 'font/woff2' | 'application/xhtml+xml' | 'application/vnd.ms-excel' | 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' | 'application/xml' | 'application/vnd.mozilla.xul+xml' | 'application/zip' | 'video/3gpp audio/3gpp' | 'video/3gpp2 audio/3gpp2' | 'application/x-7z-compressed' | (string & {});
7
4
  export declare class TFileMimeType extends TString<FileMimeType> {
8
- constructor(constraints?: TFileMimeTypeConstraints);
9
5
  tName(): TName;
10
6
  example(): FileMimeType;
11
7
  }
@@ -1,11 +1,5 @@
1
1
  import { TString } from '../base/TString.js';
2
2
  export class TFileMimeType extends TString {
3
- constructor(constraints) {
4
- super(constraints);
5
- if (constraints?.allowed) {
6
- this.setOptions(constraints?.allowed.map((v) => ({ label: v, value: v })));
7
- }
8
- }
9
3
  tName() {
10
4
  return 'FileMimeType';
11
5
  }
@@ -1,7 +1,14 @@
1
1
  import type { TName } from '../base/TBase.js';
2
2
  import { TString, type TStringConstraints } from '../base/TString.js';
3
+ import type { FileMimeType } from './TFileMimeType.js';
4
+ import type { FileName } from './TFileName.js';
5
+ import type { UIntQuantity } from './TUIntQuantity.js';
3
6
  export type FilePath = string;
4
7
  export declare class TFilePath extends TString<FilePath> {
8
+ static readonly ABS_PATH: FilePath;
9
+ static readonly FILE_NAME: FileName;
10
+ static readonly FILE_SIZE: UIntQuantity;
11
+ static readonly MIME_TYPE: FileMimeType;
5
12
  static readonly FORMAT: RegExp;
6
13
  constructor(constraints?: TStringConstraints);
7
14
  tName(): TName;
@@ -1,5 +1,9 @@
1
1
  import { TString } from '../base/TString.js';
2
2
  export class TFilePath extends TString {
3
+ static ABS_PATH = '/Users/dexter/Desktop';
4
+ static FILE_NAME = 'picture.png';
5
+ static FILE_SIZE = 32;
6
+ static MIME_TYPE = 'image/png';
3
7
  static FORMAT = /^[a-z0-9_/.][a-z0-9-_/.]+/i;
4
8
  constructor(constraints) {
5
9
  super({
@@ -11,6 +15,6 @@ export class TFilePath extends TString {
11
15
  return 'FilePath';
12
16
  }
13
17
  example() {
14
- return '/Users/dexter/Desktop/picture.png';
18
+ return `${TFilePath.ABS_PATH}/${TFilePath.FILE_NAME}`;
15
19
  }
16
20
  }
@@ -27,7 +27,7 @@ export { type Emoji, TEmoji } from './final/TEmoji.js';
27
27
  export { type EncryptionKey, TEncryptionKey } from './final/TEncryptionKey.js';
28
28
  export { type ErrorMessage, TErrorMessage } from './final/TErrorMessage.js';
29
29
  export { type ExternalServiceId, TExternalServiceId, } from './final/TExternalServiceId.js';
30
- export { type File, TFile } from './final/TFile.js';
30
+ export { type File, TFile, type TFileConstraints } from './final/TFile.js';
31
31
  export { type FileExtension, TFileExtension } from './final/TFileExtension.js';
32
32
  export { type FileMimeType, TFileMimeType } from './final/TFileMimeType.js';
33
33
  export { type FileName, TFileName } from './final/TFileName.js';
@@ -18,11 +18,12 @@ import type { UCClientConfirmConfig, UCDef, UCExecState, UCFieldKey, UCInput, UC
18
18
  * One might argue that a label can be different for "name" in "CreateX" and "CreateY".
19
19
  * In this case, we consider that the input field shouldn't be named "name" in both places.
20
20
  */
21
- export type WordingManagerKey = `dt_${TName}_${string}_${keyof UCWording}` | `p_${keyof ProductWording}` | `uc_${UCName}_${keyof UCWording}` | `uc_${UCName}_client_confirm_${keyof UCClientConfirmConfig}` | `uc_${UCName}_i_submit_${UCExecState}` | `uc_${UCName}_op_${UCOutputPartIdx}_${keyof UCOutputPartWording}` | `ucif_${UCFieldKey}_${keyof UCWording}` | `ucof_${UCFieldKey}_${keyof UCWording}`;
21
+ export type WordingManagerKey = `dt_${TName}_constr_${string}` | `dt_${TName}_${string}_${keyof UCWording}` | `p_${keyof ProductWording}` | `uc_${UCName}_${keyof UCWording}` | `uc_${UCName}_client_confirm_${keyof UCClientConfirmConfig}` | `uc_${UCName}_i_submit_${UCExecState}` | `uc_${UCName}_op_${UCOutputPartIdx}_${keyof UCOutputPartWording}` | `ucif_${UCFieldKey}_${keyof UCWording}` | `ucof_${UCFieldKey}_${keyof UCWording}`;
22
22
  export declare class WordingManager {
23
23
  private i18nManager;
24
24
  constructor(i18nManager: I18nManager);
25
25
  dt<DT extends DataType>(type: TBase<DT>): UCWording;
26
+ dtConstr<DT extends DataType>(type: TBase<DT>): string[] | null;
26
27
  p(): ProductWording;
27
28
  uc<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>(def: UCDef<I, OPI0, OPI1>): UCWording;
28
29
  ucClientConfirm<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>(def: UCDef<I, OPI0, OPI1>): UCClientConfirmConfig;
@@ -39,6 +39,24 @@ let WordingManager = class WordingManager {
39
39
  }
40
40
  return { desc, label };
41
41
  }
42
+ dtConstr(type) {
43
+ const constraints = type.getConstraintsForHuman();
44
+ if (!constraints) {
45
+ return null;
46
+ }
47
+ const entries = Object.entries(constraints);
48
+ if (entries.length === 0) {
49
+ return null;
50
+ }
51
+ const parts = [];
52
+ for (const [k, v] of Object.entries(constraints)) {
53
+ parts.push(
54
+ // TODO : Consider moving up the type hierarchy to fetch the constr of the parent when missing
55
+ // e.g. TFreeTextShort > TString
56
+ this.t(`dt_${type.tName()}_constr_${k}`, undefined, v));
57
+ }
58
+ return parts;
59
+ }
42
60
  p() {
43
61
  return {
44
62
  desc: this.tOrNull('p_desc'),
@@ -87,8 +105,11 @@ let WordingManager = class WordingManager {
87
105
  label: this.tOrNull(`uc_${name}_op_${idx}_label`),
88
106
  };
89
107
  }
90
- t(key, fallback = undefined) {
91
- return this.i18nManager.t(key, { fallback });
108
+ t(key, fallback = undefined, expected = undefined) {
109
+ return this.i18nManager.t(key, {
110
+ fallback,
111
+ vars: expected ? { expected } : {},
112
+ });
92
113
  }
93
114
  tOr(key, fallbackKey) {
94
115
  let val = this.tOrNull(key);
@@ -1,4 +1,10 @@
1
1
  export const I18nDE = {
2
+ dt_File_constr_accept: 'Akzeptierte Typen: {{expected}}',
3
+ dt_File_constr_maxSizeInBytes: 'Maximale Größe: {{expected}}',
4
+ dt_File_constr_minSizeInBytes: 'Minimale Größe: {{expected}}',
5
+ dt_FreeTextShort_constr_format: 'Format: {{expected}}',
6
+ dt_FreeTextShort_constr_maxLength: 'Maximale Länge: {{expected}}',
7
+ dt_FreeTextShort_constr_minLength: 'Minimale Länge: {{expected}}',
2
8
  dt_YesNo_N_desc: '',
3
9
  dt_YesNo_N_label: 'Nein',
4
10
  dt_YesNo_Y_desc: '',
@@ -39,9 +45,11 @@ export const I18nDE = {
39
45
  validation_max: 'Muss kleiner oder gleich {{expected}} sein',
40
46
  validation_maxCount: 'Darf höchstens {{expected}} Element(e) enthalten',
41
47
  validation_maxLength: 'Darf höchstens {{expected}} Zeichen enthalten',
48
+ validation_maxSize: 'Muss eine maximale Größe von {{expected}} haben',
42
49
  validation_min: 'Muss größer oder gleich {{expected}} sein',
43
50
  validation_minCount: 'Muss mindestens {{expected}} Element(e) enthalten',
44
51
  validation_minLength: 'Muss mindestens {{expected}} Zeichen enthalten',
52
+ validation_minSize: 'Muss eine minimale Größe von {{expected}} haben',
45
53
  validation_oneOf: 'Muss eines der Elemente der Liste sein',
46
54
  validation_shape: 'Muss der erwarteten Objektstruktur entsprechen',
47
55
  validation_type_array: 'Muss ein Array sein',
@@ -1,4 +1,10 @@
1
1
  export const I18nEN = {
2
+ dt_File_constr_accept: 'Accepted types: {{expected}}',
3
+ dt_File_constr_maxSizeInBytes: 'Max size: {{expected}}',
4
+ dt_File_constr_minSizeInBytes: 'Min size: {{expected}}',
5
+ dt_FreeTextShort_constr_format: 'Format : {{expected}}',
6
+ dt_FreeTextShort_constr_maxLength: 'Max length : {{expected}}',
7
+ dt_FreeTextShort_constr_minLength: 'Min length : {{expected}}',
2
8
  dt_YesNo_N_desc: '',
3
9
  dt_YesNo_N_label: 'No',
4
10
  dt_YesNo_Y_desc: '',
@@ -39,9 +45,11 @@ export const I18nEN = {
39
45
  validation_max: 'Must be lower than or equal to {{expected}}',
40
46
  validation_maxCount: 'Must contain at most {{expected}} item(s)',
41
47
  validation_maxLength: 'Must contain at most {{expected}} character(s)',
48
+ validation_maxSize: 'Must have a max size of {{expected}}',
42
49
  validation_min: 'Must be greater than or equal to {{expected}}',
43
50
  validation_minCount: 'Must contain at least {{expected}} item(s)',
44
51
  validation_minLength: 'Must contain at least {{expected}} character(s)',
52
+ validation_minSize: 'Must have a min size of {{expected}}',
45
53
  validation_oneOf: 'Must be one of the elements of the list',
46
54
  validation_shape: 'Must respect the expected object shape',
47
55
  validation_type_array: 'Must be an array',
@@ -1,4 +1,10 @@
1
1
  export const I18nES = {
2
+ dt_File_constr_accept: 'Tipos aceptados: {{expected}}',
3
+ dt_File_constr_maxSizeInBytes: 'Tamaño máximo: {{expected}}',
4
+ dt_File_constr_minSizeInBytes: 'Tamaño mínimo: {{expected}}',
5
+ dt_FreeTextShort_constr_format: 'Formato: {{expected}}',
6
+ dt_FreeTextShort_constr_maxLength: 'Longitud máxima: {{expected}}',
7
+ dt_FreeTextShort_constr_minLength: 'Longitud mínima: {{expected}}',
2
8
  dt_YesNo_N_desc: '',
3
9
  dt_YesNo_N_label: 'No',
4
10
  dt_YesNo_Y_desc: '',
@@ -39,9 +45,11 @@ export const I18nES = {
39
45
  validation_max: 'Debe ser menor o igual que {{expected}}',
40
46
  validation_maxCount: 'Debe contener como máximo {{expected}} elemento(s)',
41
47
  validation_maxLength: 'Debe contener como máximo {{expected}} carácter(es)',
48
+ validation_maxSize: 'Debe tener un tamaño máximo de {{expected}}',
42
49
  validation_min: 'Debe ser mayor o igual que {{expected}}',
43
50
  validation_minCount: 'Debe contener al menos {{expected}} elemento(s)',
44
51
  validation_minLength: 'Debe contener al menos {{expected}} carácter(es)',
52
+ validation_minSize: 'Debe tener un tamaño mínimo de {{expected}}',
45
53
  validation_oneOf: 'Debe ser uno de los elementos de la lista',
46
54
  validation_shape: 'Debe respetar la estructura esperada del objeto',
47
55
  validation_type_array: 'Debe ser un array',
@@ -1,4 +1,10 @@
1
1
  export const I18nFR = {
2
+ dt_File_constr_accept: 'Types acceptés : {{expected}}',
3
+ dt_File_constr_maxSizeInBytes: 'Taille max : {{expected}}',
4
+ dt_File_constr_minSizeInBytes: 'Taille min : {{expected}}',
5
+ dt_FreeTextShort_constr_format: 'Format : {{expected}}',
6
+ dt_FreeTextShort_constr_maxLength: 'Longueur max : {{expected}}',
7
+ dt_FreeTextShort_constr_minLength: 'Longueur min : {{expected}}',
2
8
  dt_YesNo_N_desc: '',
3
9
  dt_YesNo_N_label: 'Non',
4
10
  dt_YesNo_Y_desc: '',
@@ -39,9 +45,11 @@ export const I18nFR = {
39
45
  validation_max: 'Doit être inférieur ou égal à {{expected}}',
40
46
  validation_maxCount: 'Doit contenir au maximim {{expected}} élément(s)',
41
47
  validation_maxLength: 'Doit contenir au maximum {{expected}} caractère(s)',
48
+ validation_maxSize: 'Doit avoir une taille maximum de {{expected}}',
42
49
  validation_min: 'Doit être supérieur ou égal à {{expected}}',
43
50
  validation_minCount: 'Doit contenir au minimum {{expected}} élément(s)',
44
51
  validation_minLength: 'Doit contenir au minimum {{expected}} caractère(s)',
52
+ validation_minSize: 'Doit avoir une taille minimum de {{expected}}',
45
53
  validation_oneOf: 'Doit être un des éléments de la liste',
46
54
  validation_shape: "Doit respecter la forme de l'objet attendue",
47
55
  validation_type_array: 'Doît être un tableau',
@@ -1,4 +1,4 @@
1
- import type { ViolationI18nable, YesNo } from '../dt/index.js';
1
+ import type { TFileConstraints, TStringConstraints, ViolationI18nable, YesNo } from '../dt/index.js';
2
2
  import type { UCClientConfirmConfig, UCExecState, UCWording } from '../uc/index.js';
3
3
  export type I18nLanguageCode = 'de' | 'en' | 'es' | 'fr';
4
4
  /**
@@ -8,7 +8,7 @@ export type I18nLanguageCode = 'de' | 'en' | 'es' | 'fr';
8
8
  */
9
9
  export type I18nTranslation = string;
10
10
  export type I18nTranslationKey = string;
11
- export type I18nCoreKey = ViolationI18nable | `dt_YesNo_${YesNo}_${keyof UCWording}` | `uc_client_confirm_${keyof UCClientConfirmConfig}` | `uc_i_submit_${UCExecState}`;
11
+ export type I18nCoreKey = ViolationI18nable | `dt_FreeTextShort_constr_${keyof TStringConstraints}` | `dt_File_constr_${keyof TFileConstraints}` | `dt_YesNo_${YesNo}_${keyof UCWording}` | `uc_client_confirm_${keyof UCClientConfirmConfig}` | `uc_i_submit_${UCExecState}`;
12
12
  export type I18nCoreTranslations = Record<I18nCoreKey, I18nTranslation>;
13
13
  export type I18nSource = any;
14
14
  export type I18nSourceSafe = {
@@ -1,4 +1,5 @@
1
1
  import type { DateISO8601, DirPath, File, FileExtension, FileMimeType, FileName, FilePath, UIntQuantity } from '../dt/index.js';
2
+ import type { EnumOf } from '../utils/index.js';
2
3
  export type FSManagerChmodMode = number | string;
3
4
  export interface FSManagerCatOpts {
4
5
  encoding?: FSManagerEncoding;
@@ -9,11 +10,12 @@ export interface FSManagerFilePickerOpts {
9
10
  path?: FilePath;
10
11
  }
11
12
  export type FSManagerFilePickerSource = 'camera' | 'library' | 'path';
12
- export declare enum FSManagerItemInfoType {
13
- DIR = "DIR",
14
- FILE = "FILE",
15
- OTHER = "OTHER"
16
- }
13
+ export declare const FSManagerItemInfoType: {
14
+ readonly DIR: "DIR";
15
+ readonly FILE: "FILE";
16
+ readonly OTHER: "OTHER";
17
+ };
18
+ export type FSManagerItemInfoType = EnumOf<typeof FSManagerItemInfoType>;
17
19
  export interface FSManagerItemInfo {
18
20
  base: string;
19
21
  birthtime: DateISO8601;