5htp-core 0.1.2 → 0.2.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 (127) hide show
  1. package/changelog.md +5 -0
  2. package/doc/TODO.md +71 -0
  3. package/package.json +5 -4
  4. package/src/client/{App.tsx → app/component.tsx} +15 -8
  5. package/src/client/app/index.ts +128 -0
  6. package/src/client/app/service.ts +34 -0
  7. package/src/client/app.tsconfig.json +0 -4
  8. package/src/client/assets/css/medias.less +14 -0
  9. package/src/client/components/Card/index.tsx +2 -2
  10. package/src/client/components/Dialog/Manager.tsx +39 -12
  11. package/src/client/components/Form/index.tsx +1 -1
  12. package/src/client/components/button.tsx +2 -2
  13. package/src/client/components/containers/Popover/index.tsx +1 -1
  14. package/src/client/components/data/spintext/index.tsx +1 -1
  15. package/src/client/components/dropdown/index.tsx +1 -1
  16. package/src/client/components/index.ts +8 -0
  17. package/src/client/components/input/BaseV2/index.tsx +1 -1
  18. package/src/client/components/input/UploadImage/index.tsx +1 -1
  19. package/src/client/hooks/index.ts +5 -0
  20. package/src/client/hooks/useState/index.tsx +2 -2
  21. package/src/client/hooks.ts +22 -0
  22. package/src/client/index.ts +5 -0
  23. package/src/client/pages/_layout/landing/index.tsx +0 -2
  24. package/src/client/pages/_messages/400.tsx +2 -2
  25. package/src/client/pages/_messages/401.tsx +2 -2
  26. package/src/client/pages/_messages/403.tsx +2 -2
  27. package/src/client/pages/_messages/404.tsx +2 -2
  28. package/src/client/pages/_messages/500.tsx +2 -2
  29. package/src/client/pages/bug.tsx +1 -1
  30. package/src/client/pages/useHeader.tsx +1 -1
  31. package/src/client/{context/captcha.ts → services/captcha/index.ts} +0 -0
  32. package/src/client/services/metrics/index.ts +37 -0
  33. package/src/client/{router → services/router/components}/Link.tsx +1 -1
  34. package/src/client/services/router/components/Page.tsx +59 -0
  35. package/src/client/{router/component.tsx → services/router/components/router.tsx} +43 -74
  36. package/src/client/services/router/index.tsx +448 -0
  37. package/src/client/services/router/request/api.ts +229 -0
  38. package/src/client/{router → services/router}/request/history.ts +0 -0
  39. package/src/client/services/router/request/index.ts +52 -0
  40. package/src/client/services/router/response/index.tsx +107 -0
  41. package/src/client/services/router/response/page.ts +95 -0
  42. package/src/client/{context/socket.ts → services/socket/index.ts} +2 -2
  43. package/src/client/utils/dom.ts +1 -1
  44. package/src/common/app/index.ts +9 -0
  45. package/src/common/data/chaines/index.ts +9 -6
  46. package/src/common/data/input/validate.ts +3 -166
  47. package/src/common/data/objets.ts +25 -0
  48. package/src/common/data/tableaux.ts +8 -0
  49. package/src/common/errors/index.ts +3 -1
  50. package/src/common/router/index.ts +67 -88
  51. package/src/common/router/layouts.ts +50 -0
  52. package/src/common/router/register.ts +62 -0
  53. package/src/common/router/request/api.ts +72 -0
  54. package/src/common/router/request/index.ts +31 -0
  55. package/src/common/router/{response.ts → response/index.ts} +9 -13
  56. package/src/common/router/response/page.ts +40 -56
  57. package/src/common/validation/index.ts +3 -0
  58. package/src/common/validation/schema.ts +184 -0
  59. package/src/common/validation/validator.ts +88 -0
  60. package/src/common/validation/validators.ts +313 -0
  61. package/src/server/app/config.ts +9 -27
  62. package/src/server/app/index.ts +81 -124
  63. package/src/server/app/service.ts +98 -0
  64. package/src/server/app.tsconfig.json +0 -8
  65. package/src/server/error/index.ts +13 -0
  66. package/src/server/index.ts +5 -0
  67. package/src/server/patch.ts +0 -6
  68. package/src/server/{data/Cache.ts → services/cache/index.ts} +79 -47
  69. package/src/server/services/console/bugReporter.ts +26 -16
  70. package/src/server/services/console/index.ts +59 -51
  71. package/src/server/services/cron/index.ts +12 -26
  72. package/src/server/services/database/bucket.ts +40 -0
  73. package/src/server/services/database/connection.ts +206 -75
  74. package/src/server/services/database/datatypes.ts +63 -40
  75. package/src/server/services/database/index.ts +295 -272
  76. package/src/server/services/database/metas.ts +246 -135
  77. package/src/server/services/database/stats.ts +151 -126
  78. package/src/server/services/email/index.ts +28 -52
  79. package/src/server/services/{router/request/services → metrics}/detect.ts +8 -10
  80. package/src/server/services/{router/request/services/tracking.ts → metrics/index.ts} +68 -45
  81. package/src/server/services/{http → router/http}/index.ts +28 -70
  82. package/src/server/services/{http → router/http}/multipart.ts +0 -0
  83. package/src/server/services/{http → router/http}/session.ts.old +0 -0
  84. package/src/server/services/router/index.ts +273 -203
  85. package/src/server/services/router/request/api.ts +73 -0
  86. package/src/server/services/router/request/index.ts +16 -97
  87. package/src/server/services/router/request/service.ts +21 -0
  88. package/src/server/services/router/response/index.ts +125 -64
  89. package/src/server/services/router/response/{filter → mask}/Filter.ts +0 -0
  90. package/src/server/services/router/response/{filter → mask}/index.ts +0 -2
  91. package/src/server/services/router/response/{filter → mask}/selecteurs.ts +0 -0
  92. package/src/server/services/router/response/page/document.tsx +194 -0
  93. package/src/server/services/router/response/page/index.tsx +157 -0
  94. package/src/server/{libs/pages → services/router/response/page}/schemaGenerator.ts +0 -0
  95. package/src/server/services/router/service.ts +48 -0
  96. package/src/server/services/schema/index.ts +47 -0
  97. package/src/server/services/schema/request.ts +55 -0
  98. package/src/server/services/schema/router.ts +33 -0
  99. package/src/server/services/socket/index.ts +38 -43
  100. package/src/server/services/socket/scope.ts +6 -4
  101. package/src/server/services/users/index.ts +203 -0
  102. package/src/server/services/{auth/base.ts → users/old.ts} +28 -112
  103. package/src/server/services/users/router/index.ts +72 -0
  104. package/src/server/services/users/router/request.ts +49 -0
  105. package/src/types/aliases.d.ts +43 -2
  106. package/templates/composant.tsx +1 -1
  107. package/templates/modal.tsx +1 -1
  108. package/templates/page.tsx +1 -1
  109. package/tsconfig.common.json +0 -4
  110. package/src/client/context/api.ts +0 -92
  111. package/src/client/context/index.ts +0 -246
  112. package/src/client/index.tsx +0 -129
  113. package/src/client/router/index.ts +0 -286
  114. package/src/client/router/request/index.ts +0 -106
  115. package/src/client/router/response/index.ts +0 -38
  116. package/src/client/router/route.ts +0 -75
  117. package/src/common/data/input/validators/basic.ts +0 -299
  118. package/src/common/data/input/validators/build.ts +0 -63
  119. package/src/common/router/request.ts +0 -83
  120. package/src/server/data/ApiClient.ts +0 -119
  121. package/src/server/data/input.ts +0 -41
  122. package/src/server/libs/pages/document.static.tsx +0 -41
  123. package/src/server/libs/pages/document.tsx +0 -203
  124. package/src/server/libs/pages/render.tsx +0 -90
  125. package/src/server/routes/auth.ts +0 -151
  126. package/src/server/services/redis/index.ts +0 -71
  127. package/src/server/services/router/request/services/auth.ts +0 -177
@@ -0,0 +1,52 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Npm
6
+ import { Location } from 'history';
7
+ import type Bowser from 'bowser';
8
+
9
+ // Core
10
+ import BaseRequest from '@common/router/request';
11
+
12
+ // Specific
13
+ import type ClientRouter from '..';
14
+ import ApiClient from './api';
15
+ import type ClientResponse from '../response';
16
+
17
+ /*----------------------------------
18
+ - TYPES
19
+ ----------------------------------*/
20
+
21
+
22
+ /*----------------------------------
23
+ - ROUTER
24
+ ----------------------------------*/
25
+ // Since we do SSR, the server router can also be passed here
26
+ export default class ClientRequest<TRouter extends ClientRouter = ClientRouter> extends BaseRequest {
27
+
28
+ public api: ApiClient;
29
+ public response?: ClientResponse<TRouter>;
30
+ public hash?: string;
31
+
32
+ public constructor(
33
+ location: Location,
34
+ public router: TRouter,
35
+ public app = router.app
36
+ ) {
37
+
38
+ super(location.pathname);
39
+
40
+ this.host = window.location.host;
41
+ this.hash = location.hash;
42
+
43
+ this.api = new ApiClient(this.app, this);
44
+ }
45
+
46
+ // To move to a service
47
+ public device(): Bowser.Parser.ParsedResult | undefined {
48
+ // We load bowser only when required
49
+ const Bowser = require("bowser");
50
+ return Bowser.parse(window.navigator.userAgent);
51
+ }
52
+ }
@@ -0,0 +1,107 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Libs
6
+ import type ServerRouter from '@server/services/router';
7
+ import type ServerResponse from '@server/services/router/response';
8
+
9
+ import type { TRoute, TErrorRoute } from '@common/router';
10
+ import BaseResponse from '@common/router/response';
11
+
12
+ import type ClientApplication from '@client/app';
13
+ import type { default as ClientRouter } from '@client/services/router'
14
+ import type ClientResponse from '@client/services/router/response'
15
+ import ClientRequest from '@client/services/router/request'
16
+ import ClientPage from '@client/services/router/response/page'
17
+ import { history } from '@client/services/router/request/history';
18
+ import CommonPage from '@common/router/response/page';
19
+
20
+ /*----------------------------------
21
+ - TYPES
22
+ ----------------------------------*/
23
+
24
+ export type TPageResponse<TRouter extends ClientRouter> = (
25
+ ClientResponse<TRouter, ClientPage>
26
+ |
27
+ ServerResponse<ServerRouter, ClientPage>
28
+ );
29
+
30
+ export type TRouterContext<TRouter extends ClientRouter = ClientRouter, TApplication extends ClientApplication = ClientApplication> = (
31
+ // ClientPage context
32
+ {
33
+ app: TApplication,
34
+ context: TRouterContext<TRouter, TApplication>,
35
+ request: ClientRequest<TRouter>,
36
+ route: TRoute<TRouter>,
37
+ api: ClientRequest<TRouter>["api"],
38
+ page: ClientPage<TRouter>,
39
+ user: User
40
+ }
41
+ &
42
+ // Expose client application services (api, socket, ...)
43
+ //TRouter["app"]
44
+ TApplication
45
+ )
46
+
47
+ /*----------------------------------
48
+ - ROUTER
49
+ ----------------------------------*/
50
+ export default class ClientPageResponse<
51
+ TRouter extends ClientRouter,
52
+ TData extends TResponseData = TResponseData
53
+ > extends BaseResponse<TData> {
54
+
55
+ public context: TRouterContext<TRouter, TRouter["app"]>;
56
+
57
+ public constructor(
58
+ public request: ClientRequest<TRouter>,
59
+ public route: TRoute | TErrorRoute,
60
+
61
+ public app = request.app,
62
+ ) {
63
+
64
+ super(request);
65
+
66
+ request.response = this;
67
+
68
+ // Create response context for controllers
69
+ this.context = this.createContext();
70
+ }
71
+
72
+ private createContext(): TRouterContext<TRouter, TRouter["app"]> {
73
+
74
+ const context: TRouterContext<TRouter, TRouter["app"]> = {
75
+ // App services (TODO: expose only services)
76
+ ...this.request.app,
77
+ // Router context
78
+ app: this.app,
79
+ context: undefined as unknown as TRouterContext<TRouter, TRouter["app"]>,
80
+ request: this.request,
81
+ route: this.route,
82
+ api: this.request.api,
83
+ }
84
+
85
+ context.context = context;
86
+
87
+ return context;
88
+ }
89
+
90
+ public async runController( additionnalData: {} = {} ): Promise<ClientPage> {
91
+
92
+ // Run contoller
93
+ const result = this.route.controller(this.context);
94
+
95
+ // Default data type for `return <raw data>`
96
+ if (result instanceof ClientPage)
97
+ await result.render();
98
+ else
99
+ throw new Error(`Unsupported response format: ${result.constructor?.name}`);
100
+
101
+ return result;
102
+ }
103
+
104
+ public redirect(url: string) {
105
+ history?.replace(url);
106
+ }
107
+ }
@@ -0,0 +1,95 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Core
6
+ import type { TClientOrServerContext } from '@common/router';
7
+ import PageResponse, { TDataProvider, TFrontRenderer } from "@common/router/response/page";
8
+
9
+ // Specific
10
+ import type ClientRouter from '..';
11
+
12
+ /*----------------------------------
13
+ - TYPES
14
+ ----------------------------------*/
15
+
16
+
17
+
18
+ /*----------------------------------
19
+ - CLASS
20
+ ----------------------------------*/
21
+
22
+ export default class ClientPage<TRouter = ClientRouter> extends PageResponse<TRouter> {
23
+
24
+ public isLoading: boolean = false;
25
+ public scrollToId: string;
26
+
27
+ public constructor(
28
+ public dataProvider: TDataProvider | null,
29
+ public component: TFrontRenderer,
30
+ public context: TClientOrServerContext,
31
+
32
+ public route = context.route
33
+ ) {
34
+
35
+ super(dataProvider, component, context);
36
+
37
+ this.bodyId = context.route.options.bodyId;
38
+ this.scrollToId = context.request.hash;
39
+ }
40
+
41
+ public async render( data?: TObjetDonnees ) {
42
+
43
+ // Add the page to the context
44
+ this.context.page = this;
45
+
46
+ // Load the fetchers list to load data if needed
47
+ if (this.dataProvider)
48
+ this.fetchers = this.dataProvider( this.context );
49
+
50
+ // Data succesfully loaded
51
+ if (data !== undefined) {
52
+ this.isLoading = false;
53
+ this.data = data;
54
+ }
55
+
56
+ // Fetch data
57
+ this.data = await this.fetchData();
58
+
59
+ return this;
60
+ }
61
+
62
+ /*----------------------------------
63
+ - ACTIONS
64
+ ----------------------------------*/
65
+ // Should be called AFTER rendering the page
66
+ public updateClient() {
67
+
68
+ document.body.id = this.bodyId || this.id;
69
+ document.title = this.title || APP_NAME;
70
+ document.body.className = [...this.bodyClass].join(' ');
71
+
72
+ }
73
+
74
+ public setAllData( callback: (data: {[k: string]: any}) => void) {
75
+ console.warn(`page.setAllData not yet attached to the page Reatc component.`);
76
+ }
77
+ public setData( key: string, value: ((value: any) => void) | any ) {
78
+ this.setAllData(old => ({
79
+ ...old,
80
+ [key]: typeof value === 'function' ? value(old[key]) : value
81
+ }));
82
+ }
83
+
84
+ public loadIndicator;
85
+ public loading(state: boolean) {
86
+
87
+ if (state === true) {
88
+ if (!document.body.classList.contains("loading"))
89
+ document.body.classList.add("loading");
90
+ } else {
91
+ document.body.classList.remove("loading");
92
+ }
93
+
94
+ }
95
+ }
@@ -2,7 +2,7 @@
2
2
  - DEPENDANCES
3
3
  ----------------------------------*/
4
4
 
5
- import type { ClientContext } from '.';
5
+ import type { ClientContext } from '../../context';
6
6
 
7
7
  import type { TDialogControls } from '@client/components/Dialog/Manager';
8
8
 
@@ -131,7 +131,7 @@ export default class SocketClient {
131
131
 
132
132
  public scopes: { [name: string]: SocketScope } = {}
133
133
 
134
- public constructor(public context: ClientContext ) {
134
+ public constructor( public context: ClientContext ) {
135
135
 
136
136
 
137
137
  }
@@ -1,5 +1,5 @@
1
1
  import type { RefObject } from 'preact';
2
- import { history } from '@client/router/request/history';
2
+ import { history } from '@client/services/router/request/history';
3
3
 
4
4
  type ElementOrSelector = HTMLElement | string;
5
5
  export const deepContains = (
@@ -0,0 +1,9 @@
1
+ import type ClientApplication from '@client/app';
2
+ import type ServerApplication from '@server/app';
3
+
4
+ export type ClientOrServerApplication = ClientApplication | ServerApplication;
5
+
6
+ export type TAppArrowFunction<
7
+ TRegisteredData = void,
8
+ TApplication extends ClientOrServerApplication = ClientOrServerApplication
9
+ > = (app: TApplication) => TRegisteredData
@@ -11,6 +11,11 @@ export const nameToID = (name: string) => name.toLowerCase().replace(/[^a-z1-9]/
11
11
 
12
12
  export const ucfirst = (chaine: string): string => {
13
13
  return chaine.charAt(0).toUpperCase() + chaine.slice(1);
14
+ }
15
+
16
+ export const linkify = (texte: string): string => {
17
+ const regex = /((http|https)\:\/\/([a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?))/gi;
18
+ return texte.replace(regex, '<a href="$1" target="_blank">$3</a>');
14
19
  }
15
20
 
16
21
  export const trim = (s: string, c: string) => {
@@ -19,12 +24,7 @@ export const trim = (s: string, c: string) => {
19
24
  return s.replace(new RegExp(
20
25
  "^[" + c + "]+|[" + c + "]+$", "g"
21
26
  ), "");
22
- }
23
-
24
- export const linkify = (texte: string): string => {
25
- const regex = /((http|https)\:\/\/([a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?))/gi;
26
- return texte.replace(regex, '<a href="$1" target="_blank">$3</a>');
27
- }
27
+ }
28
28
 
29
29
  export const trimLeft = (chaine: string, toTrim: string) => chaine.startsWith(toTrim)
30
30
  ? chaine.substring(toTrim.length) : chaine;
@@ -32,6 +32,9 @@ export const trimLeft = (chaine: string, toTrim: string) => chaine.startsWith(to
32
32
  export const trimRight = (chaine: string, toTrim: string) => chaine.endsWith(toTrim)
33
33
  ? chaine.substring(0, -toTrim.length) : chaine;
34
34
 
35
+ export const escapeRegExp = (string: string) =>
36
+ string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
37
+
35
38
  /*----------------------------------
36
39
  - EXTRACT
37
40
  ----------------------------------*/
@@ -24,53 +24,6 @@ const debug = false;
24
24
 
25
25
  //import type { Choix } from '@client/components/Champs/Base/Choix';
26
26
 
27
- export type TSchema = { [champ: string]: TSchema | TSchemaChampComplet }
28
-
29
- export type TSchemaChamp<TValeur> = {
30
-
31
- rendu?: TBaseComposantChamp,
32
- activer?: (donnees: TObjetDonnees) => boolean,
33
- onglet?: string, // Sert juste d'identifiant secondaire. Ex: nom onglet correspondant
34
-
35
- // Executé après le validateur propre au type
36
- valider?: (val: TValeur, donneesSaisie: TObjetDonnees, donneesRetour: TObjetDonnees, corriger?: boolean) => Promise<TValeur>,
37
- dependances?: string[],
38
- opt?: true,
39
- defaut?: TValeur,
40
- as?: string[], // Mapping personnalisé
41
-
42
- }
43
-
44
- export type TBaseComposantChamp = (props: any) => ComponentChild;
45
-
46
- export type TSchemaChampComplet<TValeur = unknown> = TSchemaChamp<TValeur> & {
47
- type: string,
48
- valider: (val: any, formData?: unknown) => Promise<TValeur | undefined>
49
- }
50
-
51
- /*----------------------------------
52
- - TYPES: VALIDATION SCHEMA
53
- ----------------------------------*/
54
- type TOptsValider = {
55
- critique?: boolean,
56
- validationComplete?: boolean,
57
- avecDependances?: boolean,
58
- corriger?: boolean,
59
- }
60
-
61
- export type TDonneesValidees<TSchemaA extends TSchema> = {
62
- [cle in keyof TSchemaA]: TSchemaA[cle]["type"] extends string
63
- // Champ
64
- ? ThenArg<ReturnType<TSchemaA[cle]["valider"]>>
65
- // Schema
66
- : TDonneesValidees<TSchemaA[cle]>
67
- }
68
-
69
- export type TRetourValidation<TSchemaA extends TSchema> = {
70
- valeurs: TDonneesValidees<TSchemaA>,
71
- nbErreurs: number,
72
- erreurs: TListeErreursSaisie
73
- }
74
27
 
75
28
  /*----------------------------------
76
29
  - FONCTIONS
@@ -81,10 +34,10 @@ export const initDonnees = <TSchemaA extends TSchema>(
81
34
  schema: TSchemaA,
82
35
  donnees: TObjetDonnees,
83
36
  toutConserver: boolean = false
84
- ): Partial<TDonneesValidees<TSchemaA>> => {
37
+ ): Partial<TValidatedData<TSchemaA>> => {
85
38
 
86
39
  // toutConserver = true: on conserve toutes les données, y compris celles n'étant pas été définies dans le schéma
87
- let retour: Partial<TDonneesValidees<TSchemaA>> = toutConserver ? { ...donnees } : {}
40
+ let retour: Partial<TValidatedData<TSchemaA>> = toutConserver ? { ...donnees } : {}
88
41
 
89
42
  for (const nomChamp in schema) {
90
43
  const elem = schema[nomChamp];
@@ -107,120 +60,4 @@ export const initDonnees = <TSchemaA extends TSchema>(
107
60
 
108
61
  }
109
62
 
110
- export const validate = async <TSchemaA extends TSchema, TDonnees extends TObjetDonnees>(
111
-
112
- schema: TSchemaA,
113
-
114
- inputAvalider: Partial<TDonnees>,
115
- inputComplet?: TDonnees,
116
- output: TObjetDonnees = {},
117
-
118
- opts: TOptsValider = {},
119
- chemin: string[] = []
120
-
121
- ): Promise<TRetourValidation<TSchemaA>> => {
122
-
123
- opts = {
124
- critique: false,
125
- validationComplete: false,
126
- avecDependances: true,
127
- corriger: false,
128
- ...opts,
129
- }
130
-
131
- const clesAvalider = Object.keys(opts.validationComplete === true ? schema : inputAvalider);
132
-
133
- let outputSchema = output;
134
- for (const branche of chemin)
135
- outputSchema = outputSchema[branche];
136
-
137
- // Validation de chacune d'entre elles
138
- let erreurs: TListeErreursSaisie = {};
139
- let nbErreurs = 0;
140
- for (const champ of clesAvalider) {
141
-
142
- // La donnée est répertoriée dans le schema
143
- const metas = schema[champ];
144
- if (metas === undefined) {
145
- debug && console.warn('[schema][valider][' + champ + ']', 'Exclusion (pas présent dans le schéma)');
146
- continue;
147
- }
148
-
149
- const cheminA = [...chemin, champ].join('.')
150
-
151
- // Sous-schema
152
- if (isSchema(metas)) {
153
-
154
- // Initialise la structure pour permettre l'assignement d'outputSchema
155
- if (outputSchema[champ] === undefined)
156
- outputSchema[champ] = {}
157
-
158
- const validationSchema = await validate(
159
- metas,
160
- inputAvalider[champ],
161
- inputComplet,
162
- output,
163
- opts,
164
- cheminA
165
- );
166
- erreurs = { ...erreurs, ...validationSchema.erreurs };
167
- nbErreurs += validationSchema.nbErreurs;
168
-
169
- // Pas besoin d'assigner, car output est passé en référence
170
- //output[champ] = validationSchema.valeurs;
171
-
172
-
173
-
174
- } else if (metas.activer !== undefined && metas.activer(inputComplet) === false) {
175
-
176
- delete outputSchema[champ];
177
-
178
- } else {
179
-
180
- // Champ composé de plusieurs valeurs
181
- const valOrigine = metas.as === undefined
182
- ? inputAvalider[champ]
183
- // Le champ regroupe plusieurs valeurs (ex: Periode)
184
- : metas.as.map((nomVal: string) => inputAvalider[nomVal])
185
-
186
- // Validation
187
- try {
188
-
189
- const val = await metas.valider(valOrigine, inputComplet, output, opts.corriger);
190
-
191
- // Exclusion seulement si explicitement demandé
192
- // IMPORTANT: Conserver les valeurs undefined
193
- // La présence d'un valeur undefined peut être utile, par exemple, pour indiquer qu'on souhaite supprimer une donnée
194
- // Exemple: undefinec = suppression fichier | Absende donnée = conservation fihcier actuel
195
- if (val === EXCLURE_VALEUR)
196
- debug && console.log('[schema][valider][' + cheminA + '] Exclusion demandée');
197
- else
198
- outputSchema[champ] = val;
199
-
200
- debug && console.log('[schema][valider][' + cheminA + ']', valOrigine, '=>', val);
201
-
202
- } catch (error) {
203
-
204
- debug && console.warn('[schema][valider][' + cheminA + ']', valOrigine, '|| Erreur:', error);
205
-
206
- if (error instanceof Erreur) {
207
-
208
- // Référencement erreur
209
- erreurs[cheminA] = [error.message]
210
- nbErreurs++;
211
-
212
- } else
213
- throw error;
214
- }
215
- }
216
- }
217
-
218
- if (nbErreurs !== 0 && opts.critique === true) {
219
- throw new InputErrorSchema(erreurs);
220
- }
221
-
222
- debug && console.log('[schema][valider]', inputAvalider, '=>', output);
223
-
224
- return { erreurs, nbErreurs, valeurs: output, };
225
-
226
- }
63
+ export const validate =
@@ -118,3 +118,28 @@ export const chemin = {
118
118
 
119
119
  }
120
120
  }
121
+
122
+ export const callableInstance = <TInstance extends object, TCallableName extends keyof TInstance>(
123
+ instance: TInstance,
124
+ funcName: TCallableName
125
+ ): TInstance[TCallableName] & TInstance => {
126
+
127
+ const callableFunc = instance[funcName];
128
+ if (typeof callableFunc !== 'function')
129
+ throw new Error(`instance[funcName] isn't callable.`);
130
+
131
+ const callable = callableFunc.bind(instance);
132
+
133
+ const methods = [
134
+ ...Object.getOwnPropertyNames( Object.getPrototypeOf( instance )),
135
+ ...Object.getOwnPropertyNames( instance )
136
+ ];
137
+
138
+ for (const method of methods)
139
+ if (method !== 'constructor')
140
+ callable[ method ] = typeof instance[ method ] === 'function'
141
+ ? instance[ method ].bind( instance )
142
+ : instance[ method ];
143
+
144
+ return callable as TInstance[TCallableName] & TInstance;
145
+ }
@@ -40,6 +40,14 @@ export function arrayToObj<Ttbl extends {[cle: string]: any}, Tcle extends strin
40
40
 
41
41
  export const somme = (tbl: number[]) => tbl.reduce((a: number, b: number) => a + b);
42
42
 
43
+ export const arrayChunks = <TArray extends any[]>(array: TArray, size: number) => {
44
+
45
+ const arrays: TArray[] = [];
46
+ while (array.length > 0)
47
+ arrays.push( array.splice(0, size) as TArray );
48
+
49
+ return arrays;
50
+ }
43
51
 
44
52
  export function array_sum( tbl: number[] ): number {
45
53
  return tbl.reduce((a: number, b: number) => a + b);
@@ -161,4 +161,6 @@ export const instancierViaCode = (
161
161
  case 404: return new NotFound( message, details);
162
162
  default: return new Anomaly( message, details);
163
163
  }
164
- }
164
+ }
165
+
166
+ export default Erreur;