@modular-component/core 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/dist/index.d.ts +304 -91
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +107 -53
- package/dist/index.js.map +1 -1
- package/dist/types/arguments.d.ts +33 -0
- package/dist/types/arguments.d.ts.map +1 -0
- package/dist/types/arguments.js +6 -0
- package/dist/types/arguments.js.map +1 -0
- package/dist/types/methods/add.d.ts +23 -0
- package/dist/types/methods/add.d.ts.map +1 -0
- package/dist/types/methods/add.js +8 -0
- package/dist/types/methods/add.js.map +1 -0
- package/dist/types/methods/at.d.ts +22 -0
- package/dist/types/methods/at.d.ts.map +1 -0
- package/dist/types/methods/at.js +7 -0
- package/dist/types/methods/at.js.map +1 -0
- package/dist/types/methods/hook.d.ts +14 -0
- package/dist/types/methods/hook.d.ts.map +1 -0
- package/dist/types/methods/hook.js +7 -0
- package/dist/types/methods/hook.js.map +1 -0
- package/dist/types/methods/mock.d.ts +26 -0
- package/dist/types/methods/mock.d.ts.map +1 -0
- package/dist/types/methods/mock.js +6 -0
- package/dist/types/methods/mock.js.map +1 -0
- package/dist/types/methods/with.d.ts +44 -0
- package/dist/types/methods/with.d.ts.map +1 -0
- package/dist/types/methods/with.js +8 -0
- package/dist/types/methods/with.js.map +1 -0
- package/dist/types/methods.d.ts +10 -0
- package/dist/types/methods.d.ts.map +1 -0
- package/dist/types/methods.js +5 -0
- package/dist/types/methods.js.map +1 -0
- package/dist/types/modular-component.d.ts +15 -0
- package/dist/types/modular-component.d.ts.map +1 -0
- package/dist/types/modular-component.js +5 -0
- package/dist/types/modular-component.js.map +1 -0
- package/dist/types/stage.d.ts +41 -0
- package/dist/types/stage.d.ts.map +1 -0
- package/dist/types/stage.js +5 -0
- package/dist/types/stage.js.map +1 -0
- package/dist/types/utils.d.ts +24 -0
- package/dist/types/utils.d.ts.map +1 -0
- package/dist/types/utils.js +5 -0
- package/dist/types/utils.js.map +1 -0
- package/dist/types/validation.d.ts +4 -0
- package/dist/types/validation.d.ts.map +1 -0
- package/dist/types/validation.js +2 -0
- package/dist/types/validation.js.map +1 -0
- package/package.json +1 -1
- package/src/index.ts +185 -83
- package/src/types/arguments.ts +55 -0
- package/src/types/methods/add.ts +50 -0
- package/src/types/methods/at.ts +64 -0
- package/src/types/methods/hook.ts +27 -0
- package/src/types/methods/mock.ts +90 -0
- package/src/types/methods/with.ts +153 -0
- package/src/types/methods.ts +11 -0
- package/src/types/modular-component.ts +25 -0
- package/src/types/stage.ts +91 -0
- package/src/types/utils.ts +63 -0
- package/src/types/validation.ts +13 -0
- package/dist/types.d.ts +0 -76
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -2
- package/dist/types.js.map +0 -1
- package/src/types.ts +0 -279
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper for manipulating stages and stage tuples
|
|
3
|
+
*/
|
|
4
|
+
import { At, Before, Reduce, After, OneLess } from './utils';
|
|
5
|
+
export interface ModularStages<Args = any, Value = any> {
|
|
6
|
+
}
|
|
7
|
+
declare type StageRecord = {
|
|
8
|
+
stage: keyof ModularStages;
|
|
9
|
+
value: unknown;
|
|
10
|
+
};
|
|
11
|
+
export declare type StageTuple = StageRecord[];
|
|
12
|
+
export declare type AddStage<List extends StageTuple, Stage extends StageRecord> = [
|
|
13
|
+
...List,
|
|
14
|
+
Stage
|
|
15
|
+
];
|
|
16
|
+
export declare type ReplaceStageAt<List extends StageTuple, Stage extends StageRecord, At extends number | string> = {
|
|
17
|
+
[Index in keyof List]: Index extends At ? List[Index]['stage'] extends Stage['stage'] ? Stage : List[Index] : List[Index];
|
|
18
|
+
};
|
|
19
|
+
declare type ReplaceStage<List extends StageTuple, Stage extends StageRecord, At extends number | string = never> = [At] extends [never] ? {
|
|
20
|
+
[Index in keyof List]: List[Index]['stage'] extends Stage['stage'] ? Stage : List[Index];
|
|
21
|
+
} : ReplaceStageAt<List, Stage, At>;
|
|
22
|
+
export declare type ExtractStage<List extends StageTuple, Stage extends symbol, Union = List[number]> = Union extends {
|
|
23
|
+
stage: Stage;
|
|
24
|
+
value: infer U;
|
|
25
|
+
} ? {
|
|
26
|
+
stage: Stage;
|
|
27
|
+
value: U;
|
|
28
|
+
} : never;
|
|
29
|
+
export declare type UpsertStage<List extends StageTuple, Stage extends StageRecord, At extends number = never> = [ExtractStage<List, Stage['stage']>] extends [never] ? AddStage<List, Stage> : ReplaceStage<List, Stage, At>;
|
|
30
|
+
declare type IsolateStage<Tuple extends StageTuple, Stage extends symbol> = {
|
|
31
|
+
[key in keyof Tuple]: Tuple[key]['stage'] extends Stage ? key : never;
|
|
32
|
+
};
|
|
33
|
+
export declare type StageIndices<Tuple extends StageTuple, Stage extends symbol> = Reduce<IsolateStage<Tuple, Stage>>;
|
|
34
|
+
export declare type AtStage<Tuple extends StageTuple, Index extends number | string> = At<Tuple, Index> extends StageTuple ? At<Tuple, Index> : [];
|
|
35
|
+
export declare type BeforeStage<Tuple extends StageTuple, Index extends number | string> = Before<Tuple, Index> extends StageTuple ? Before<Tuple, Index> : [];
|
|
36
|
+
declare type AfterStage<Tuple extends StageTuple, Index extends number | string> = After<Tuple, Index> extends StageTuple ? After<Tuple, Index> : [];
|
|
37
|
+
export declare type CleanUpStages<Tuple extends StageTuple> = {
|
|
38
|
+
[key in keyof Tuple]: StageIndices<OneLess<AfterStage<Tuple, key>>, Tuple[key]['stage']>['length'] extends 0 ? Tuple[key] : never;
|
|
39
|
+
};
|
|
40
|
+
export {};
|
|
41
|
+
//# sourceMappingURL=stage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stage.d.ts","sourceRoot":"","sources":["../../src/types/stage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stage.js","sourceRoot":"","sources":["../../src/types/stage.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic type helpers (tuple, union, object...)
|
|
3
|
+
*/
|
|
4
|
+
export declare type OneLess<Tuple extends unknown[]> = Tuple extends [
|
|
5
|
+
unknown,
|
|
6
|
+
...infer Rest
|
|
7
|
+
] ? Rest : Tuple;
|
|
8
|
+
export declare type Before<Tuple extends unknown[], Index extends string | number> = `${Tuple['length']}` extends `${Index}` ? Tuple : Tuple extends [...infer Keep, infer Drop] ? Before<Keep, Index> : never;
|
|
9
|
+
export declare type After<Tuple extends unknown[], Index extends string | number, Rest extends unknown[] = []> = `${Rest['length']}` extends `${Index}` ? Tuple : Tuple extends [infer Drop, ...infer Keep] ? After<Keep, Index, [...Rest, Drop]> : never;
|
|
10
|
+
export declare type At<Tuple extends unknown[], Index extends string | number> = `${OneLess<Tuple>['length']}` extends `${Index}` ? Tuple : Tuple extends [...infer Keep, infer Drop] ? At<Keep, Index> : never;
|
|
11
|
+
export declare type Reduce<T extends unknown[]> = T extends [...infer R, infer L] ? [L] extends [never] ? [...Reduce<R>] : [...Reduce<R>, L] : T;
|
|
12
|
+
export declare type ToIndices<T extends unknown[]> = {
|
|
13
|
+
[key in keyof T]: key;
|
|
14
|
+
}[number];
|
|
15
|
+
export declare type Last<T extends unknown[]> = T extends [...infer R, infer L] ? L : never;
|
|
16
|
+
export declare type UnionToIntersection<U> = [U] extends [never] ? never : (U extends infer V ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
|
|
17
|
+
declare type NonNeverKeys<Obj extends {}> = {
|
|
18
|
+
[key in keyof Obj]: Obj[key] extends never ? never : key;
|
|
19
|
+
}[keyof Obj];
|
|
20
|
+
export declare type FilterNever<Obj extends {}> = {
|
|
21
|
+
[key in NonNeverKeys<Obj>]: Obj[key];
|
|
22
|
+
};
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/types/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,oBAAY,OAAO,CAAC,KAAK,SAAS,OAAO,EAAE,IAAI,KAAK,SAAS;IAC3D,OAAO;IACP,GAAG,MAAM,IAAI;CACd,GACG,IAAI,GACJ,KAAK,CAAA;AACT,oBAAY,MAAM,CAChB,KAAK,SAAS,OAAO,EAAE,EACvB,KAAK,SAAS,MAAM,GAAG,MAAM,IAC3B,GAAG,KAAK,CAAC,QAAQ,CAAC,EAAE,SAAS,GAAG,KAAK,EAAE,GACvC,KAAK,GACL,KAAK,SAAS,CAAC,GAAG,MAAM,IAAI,EAAE,MAAM,IAAI,CAAC,GACzC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,GACnB,KAAK,CAAA;AACT,oBAAY,KAAK,CACf,KAAK,SAAS,OAAO,EAAE,EACvB,KAAK,SAAS,MAAM,GAAG,MAAM,EAC7B,IAAI,SAAS,OAAO,EAAE,GAAG,EAAE,IACzB,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,SAAS,GAAG,KAAK,EAAE,GACtC,KAAK,GACL,KAAK,SAAS,CAAC,MAAM,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,GACzC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,CAAC,CAAC,GACnC,KAAK,CAAA;AACT,oBAAY,EAAE,CACZ,KAAK,SAAS,OAAO,EAAE,EACvB,KAAK,SAAS,MAAM,GAAG,MAAM,IAC3B,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,EAAE,SAAS,GAAG,KAAK,EAAE,GAChD,KAAK,GACL,KAAK,SAAS,CAAC,GAAG,MAAM,IAAI,EAAE,MAAM,IAAI,CAAC,GACzC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,GACf,KAAK,CAAA;AACT,oBAAY,MAAM,CAAC,CAAC,SAAS,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,GACrE,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GACjB,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,GACd,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GACnB,CAAC,CAAA;AACL,oBAAY,SAAS,CAAC,CAAC,SAAS,OAAO,EAAE,IAAI;KAAG,GAAG,IAAI,MAAM,CAAC,GAAG,GAAG;CAAE,CAAC,MAAM,CAAC,CAAA;AAC9E,oBAAY,IAAI,CAAC,CAAC,SAAS,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,GACnE,CAAC,GACD,KAAK,CAAA;AAKT,oBAAY,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GACpD,KAAK,GACL,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,IAAI,GACzE,CAAC,GACD,KAAK,CAAA;AAGT,aAAK,YAAY,CAAC,GAAG,SAAS,EAAE,IAAI;KACjC,GAAG,IAAI,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,SAAS,KAAK,GAAG,KAAK,GAAG,GAAG;CACzD,CAAC,MAAM,GAAG,CAAC,CAAA;AAEZ,oBAAY,WAAW,CAAC,GAAG,SAAS,EAAE,IAAI;KACvC,GAAG,IAAI,YAAY,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC;CACrC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/types/utils.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ModularStages } from './stage';
|
|
2
|
+
export declare type ValidateIndex<Index extends number | undefined, Candidates extends string | number> = `${Index}` extends Candidates ? true : false;
|
|
3
|
+
export declare type RestrictValue<Arguments extends {}, Stage extends keyof ModularStages> = ModularStages<Arguments>[Stage]['restrict'] extends never ? unknown : ModularStages<Arguments>[Stage]['restrict'];
|
|
4
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/types/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAEvC,oBAAY,aAAa,CACvB,KAAK,SAAS,MAAM,GAAG,SAAS,EAChC,UAAU,SAAS,MAAM,GAAG,MAAM,IAChC,GAAG,KAAK,EAAE,SAAS,UAAU,GAAG,IAAI,GAAG,KAAK,CAAA;AAEhD,oBAAY,aAAa,CACvB,SAAS,SAAS,EAAE,EACpB,KAAK,SAAS,MAAM,aAAa,IAC/B,aAAa,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,SAAS,KAAK,GACzD,OAAO,GACP,aAAa,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/types/validation.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,122 +1,208 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { FunctionComponent } from 'react'
|
|
1
|
+
import { ForwardedRef, FunctionComponent, forwardRef, memo } from 'react'
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
import { ModularComponent } from './types/modular-component'
|
|
4
|
+
import { MethodRecord } from './types/methods'
|
|
5
|
+
import { StageTuple } from './types/stage'
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
export type { ModularStages } from './types/stage'
|
|
8
|
+
|
|
9
|
+
function ModularFactory<Methods extends Record<string, MethodRecord>>(
|
|
10
|
+
methods: Methods,
|
|
11
|
+
) {
|
|
7
12
|
type CleanMethods = Methods extends infer U
|
|
8
13
|
? { [key in keyof U]: U[key] }
|
|
9
14
|
: never
|
|
10
15
|
|
|
11
16
|
return {
|
|
12
|
-
build: <Stages extends
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
17
|
+
build: <Stages extends StageTuple = []>(stages: StageTuple = []) => {
|
|
18
|
+
const factory = <Props extends {} = {}, Ref = FunctionComponent<Props>>(
|
|
19
|
+
displayName?: string,
|
|
20
|
+
options?: { memo: boolean },
|
|
21
|
+
) => {
|
|
22
|
+
const generateAsHook =
|
|
23
|
+
(ref?: ForwardedRef<Ref>, field?: string) =>
|
|
24
|
+
() =>
|
|
25
|
+
(props: Props = {} as Props) => {
|
|
26
|
+
// Prepare the shared arguments object, prefilling it with the props
|
|
27
|
+
// and an empty render result
|
|
28
|
+
let args = {
|
|
29
|
+
props,
|
|
30
|
+
children: (props as { children?: unknown })?.children,
|
|
31
|
+
render: null,
|
|
32
|
+
ref,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const methodsArray = Object.values(methods)
|
|
36
|
+
|
|
37
|
+
// Run each stage in order, replacing the arguments by the response
|
|
38
|
+
// from the last stage
|
|
39
|
+
for (const stage of stages) {
|
|
40
|
+
const method = methodsArray.find(
|
|
41
|
+
(method) => method.symbol === stage.stage,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
let useTransform =
|
|
45
|
+
// Never transform mocked stages
|
|
46
|
+
((stage as any).mocked ? undefined : method?.transform) ??
|
|
47
|
+
(() => stage.value)
|
|
48
|
+
|
|
49
|
+
args = {
|
|
50
|
+
...args,
|
|
51
|
+
[method?.field as keyof typeof args]: useTransform(
|
|
52
|
+
args,
|
|
53
|
+
stage.value,
|
|
54
|
+
),
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Finally, return the args
|
|
59
|
+
return field ? args[field as keyof typeof args] : args
|
|
60
|
+
}
|
|
61
|
+
|
|
16
62
|
// Create the actual Component. This is a simple React Functional Component
|
|
17
63
|
// that will call the hooks for each registered stages in order.
|
|
18
|
-
const Component = ((props) => {
|
|
64
|
+
const Component = forwardRef<Ref, Props>((props, ref) => {
|
|
19
65
|
// Prepare the shared arguments object, prefilling it with the props
|
|
20
66
|
// and an empty render result
|
|
21
|
-
const useComponent =
|
|
67
|
+
const useComponent = generateAsHook(ref)()
|
|
22
68
|
const args = useComponent(props)
|
|
23
69
|
|
|
24
70
|
return (args as unknown as { render: null }).render ?? null
|
|
25
|
-
}) as
|
|
71
|
+
}) as unknown as ModularComponent<Props, Ref, CleanMethods, Stages>
|
|
26
72
|
|
|
27
73
|
// Set the debug display name if provided
|
|
28
74
|
Component.displayName = displayName
|
|
29
75
|
|
|
30
76
|
// Add an asHook system to get the components args as a reusable hook
|
|
31
|
-
Component.asHook = (
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
method.transform ??
|
|
43
|
-
(() =>
|
|
44
|
-
typeof useStage === 'function'
|
|
45
|
-
? useStage({ ...args })
|
|
46
|
-
: useStage)
|
|
47
|
-
|
|
48
|
-
args = {
|
|
49
|
-
...args,
|
|
50
|
-
[method.field as keyof typeof args]: useTransform(args, useStage),
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Finally, return the args
|
|
55
|
-
return field ? args[field as keyof typeof args] : args
|
|
56
|
-
}) as unknown as Modular<Props, CleanMethods, Stages>['asHook']
|
|
57
|
-
|
|
58
|
-
// Add a function for rewinding the component up to a certain stage
|
|
59
|
-
Component.atStage = ((stage: MethodName) => {
|
|
60
|
-
// Find the needed stage
|
|
61
|
-
const stageIndex = (stages
|
|
77
|
+
Component.asHook = generateAsHook() as ModularComponent<
|
|
78
|
+
Props,
|
|
79
|
+
Ref,
|
|
80
|
+
CleanMethods,
|
|
81
|
+
Stages
|
|
82
|
+
>['asHook']
|
|
83
|
+
|
|
84
|
+
// Add each configured stage methods to the component
|
|
85
|
+
Object.keys(methods).forEach((method) => {
|
|
86
|
+
// Check if a stage of the same key already exists
|
|
87
|
+
const stageIndices = stages
|
|
62
88
|
// Map all stages to an [index, stage] tuple
|
|
63
89
|
.map((record, index) => [index, record] as const)
|
|
64
90
|
// Remove all tuples not matching our stage
|
|
65
|
-
.filter(([, record]) => record.
|
|
66
|
-
// Get the index
|
|
67
|
-
.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
return ModularFactory<Methods>(methods).build(
|
|
76
|
-
stages.slice(0, stageIndex + 1),
|
|
77
|
-
)<Props>(displayName)
|
|
78
|
-
}) as unknown as Modular<Props, CleanMethods, Stages>['atStage']
|
|
79
|
-
|
|
80
|
-
// Add each configured stage method to the component
|
|
81
|
-
Object.keys(methods).forEach((method) => {
|
|
82
|
-
Component[method as keyof CleanMethods] = ((value: unknown) => {
|
|
91
|
+
.filter(([, record]) => record.stage === methods[method].symbol)
|
|
92
|
+
// Get the index
|
|
93
|
+
.map(([index]) => index)
|
|
94
|
+
const lastIndex = [...stageIndices].pop() as number
|
|
95
|
+
|
|
96
|
+
// @ts-ignore
|
|
97
|
+
Component[`with${method}`] = (
|
|
98
|
+
value: unknown,
|
|
99
|
+
forceIndex?: number,
|
|
100
|
+
) => {
|
|
83
101
|
// Prepare the new stage
|
|
84
|
-
const stage = {
|
|
85
|
-
|
|
86
|
-
// For stages in "multiple" mode, simply append the stage
|
|
87
|
-
if (methods[method as MethodName].multiple) {
|
|
88
|
-
return ModularFactory(methods).build([...stages, stage])<Props>(
|
|
89
|
-
displayName,
|
|
90
|
-
)
|
|
91
|
-
}
|
|
102
|
+
const stage = { stage: methods[method].symbol, value } as const
|
|
92
103
|
|
|
93
|
-
//
|
|
94
|
-
const
|
|
104
|
+
// Check if a stage of the same key already exists
|
|
105
|
+
const stageIndex =
|
|
106
|
+
(forceIndex !== undefined
|
|
107
|
+
? stageIndices[forceIndex]
|
|
108
|
+
: lastIndex) ?? -1
|
|
95
109
|
|
|
96
110
|
// If so, copy the stages and replace the previous record
|
|
97
|
-
if (
|
|
111
|
+
if (stageIndex > -1) {
|
|
98
112
|
const nextStages = [...stages]
|
|
99
|
-
nextStages[
|
|
113
|
+
nextStages[stageIndex] = stage
|
|
100
114
|
return ModularFactory(methods).build(nextStages)<Props>(
|
|
101
115
|
displayName,
|
|
102
116
|
)
|
|
103
117
|
}
|
|
104
118
|
|
|
105
|
-
// Otherwise, append the stage
|
|
119
|
+
// Otherwise, append the stage
|
|
106
120
|
return ModularFactory(methods).build([...stages, stage])<Props>(
|
|
107
121
|
displayName,
|
|
108
122
|
)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// @ts-ignore
|
|
126
|
+
Component[`add${method}`] =
|
|
127
|
+
stageIndices.length < 1
|
|
128
|
+
? undefined
|
|
129
|
+
: (value: unknown) => {
|
|
130
|
+
// Prepare the new stage
|
|
131
|
+
const stage = {
|
|
132
|
+
stage: methods[method].symbol,
|
|
133
|
+
value,
|
|
134
|
+
} as const
|
|
135
|
+
|
|
136
|
+
// Append the stage as in multiple mode
|
|
137
|
+
return ModularFactory(methods).build([
|
|
138
|
+
...stages,
|
|
139
|
+
stage,
|
|
140
|
+
])<Props>(displayName)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// @ts-ignore
|
|
144
|
+
Component[`at${method}`] =
|
|
145
|
+
stageIndices.length < 1
|
|
146
|
+
? undefined
|
|
147
|
+
: (forceIndex?: number) => {
|
|
148
|
+
// Find the needed stage
|
|
149
|
+
const stageIndex =
|
|
150
|
+
(forceIndex !== undefined
|
|
151
|
+
? stageIndices[forceIndex]
|
|
152
|
+
: lastIndex) ?? lastIndex
|
|
153
|
+
|
|
154
|
+
// Otherwise, keep all stages up to and including the found stage
|
|
155
|
+
return ModularFactory<Methods>(methods).build(
|
|
156
|
+
stages.slice(0, stageIndex + 1),
|
|
157
|
+
)<Props>(displayName)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// @ts-ignore
|
|
161
|
+
Component[`mock${method}`] =
|
|
162
|
+
stageIndices.length < 1
|
|
163
|
+
? undefined
|
|
164
|
+
: (value: unknown, forceIndex?: number) => {
|
|
165
|
+
// Prepare the mocked stage
|
|
166
|
+
const stage = {
|
|
167
|
+
stage: methods[method].symbol,
|
|
168
|
+
value,
|
|
169
|
+
mocked: true,
|
|
170
|
+
} as const
|
|
171
|
+
|
|
172
|
+
// Find the needed stage
|
|
173
|
+
const stageIndex =
|
|
174
|
+
(forceIndex !== undefined
|
|
175
|
+
? stageIndices[forceIndex]
|
|
176
|
+
: lastIndex) ?? lastIndex
|
|
177
|
+
|
|
178
|
+
// Replace the stage with its mock
|
|
179
|
+
const nextStages = [...stages]
|
|
180
|
+
nextStages[stageIndex] = stage
|
|
181
|
+
return ModularFactory(methods).build(nextStages)<Props>(
|
|
182
|
+
displayName,
|
|
183
|
+
)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const capitalize = (str: string) =>
|
|
187
|
+
str[0].toUpperCase() + str.slice(1)
|
|
188
|
+
|
|
189
|
+
// @ts-ignore
|
|
190
|
+
Component[`asUse${capitalize(methods[method].field)}`] =
|
|
191
|
+
generateAsHook(undefined, methods[method].field)
|
|
114
192
|
})
|
|
115
193
|
|
|
116
|
-
return Component
|
|
194
|
+
return (options?.memo ? memo(Component) : Component) as typeof Component
|
|
117
195
|
}
|
|
196
|
+
|
|
197
|
+
factory.memo = <Props extends {} = {}, Ref = FunctionComponent<Props>>(
|
|
198
|
+
displayName?: string,
|
|
199
|
+
) => factory<Props, Ref>(displayName, { memo: true })
|
|
200
|
+
|
|
201
|
+
return factory
|
|
118
202
|
},
|
|
119
|
-
extend: <_Methods extends MethodRecord
|
|
203
|
+
extend: <_Methods extends Record<string, MethodRecord>>(
|
|
204
|
+
_methods: _Methods,
|
|
205
|
+
) => {
|
|
120
206
|
return ModularFactory<Methods & _Methods>({
|
|
121
207
|
...methods,
|
|
122
208
|
..._methods,
|
|
@@ -125,13 +211,29 @@ function ModularFactory<Methods extends MethodRecord>(methods: Methods) {
|
|
|
125
211
|
}
|
|
126
212
|
}
|
|
127
213
|
|
|
214
|
+
const withRender = Symbol()
|
|
215
|
+
|
|
216
|
+
declare module './types/stage' {
|
|
217
|
+
export interface ModularStages<Args, Value> {
|
|
218
|
+
[withRender]: {
|
|
219
|
+
restrict: FunctionComponent<Args>
|
|
220
|
+
transform: ReturnType<
|
|
221
|
+
Value extends FunctionComponent<Args> ? Value : never
|
|
222
|
+
>
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
128
227
|
export const modularFactory = ModularFactory({
|
|
129
|
-
|
|
228
|
+
Render: {
|
|
229
|
+
symbol: withRender,
|
|
130
230
|
field: 'render',
|
|
131
|
-
|
|
231
|
+
transform: (args, useStage) => useStage(args),
|
|
132
232
|
},
|
|
133
233
|
} as const)
|
|
134
234
|
|
|
135
|
-
export function createMethodRecord<R extends MethodRecord
|
|
235
|
+
export function createMethodRecord<R extends Record<string, MethodRecord>>(
|
|
236
|
+
record: R,
|
|
237
|
+
): R {
|
|
136
238
|
return record
|
|
137
239
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers for computing the arguments map generated by a given
|
|
3
|
+
* set of stages
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { PropsWithChildren } from 'react'
|
|
7
|
+
import { StageTuple, ModularStages, BeforeStage, CleanUpStages } from './stage'
|
|
8
|
+
import { UnionToIntersection } from './utils'
|
|
9
|
+
|
|
10
|
+
export type ComputeArguments<
|
|
11
|
+
Props extends {},
|
|
12
|
+
Ref,
|
|
13
|
+
Methods extends Record<
|
|
14
|
+
string,
|
|
15
|
+
{ symbol: keyof ModularStages; field: string }
|
|
16
|
+
>,
|
|
17
|
+
Stages extends StageTuple,
|
|
18
|
+
CleanedStages extends StageTuple = CleanUpStages<Stages>,
|
|
19
|
+
MethodList = Methods[keyof Methods],
|
|
20
|
+
> = {
|
|
21
|
+
props: Props extends { children: unknown } ? Props : PropsWithChildren<Props>
|
|
22
|
+
ref: Ref
|
|
23
|
+
children: Props extends { children: infer C } ? C : PropsWithChildren['children']
|
|
24
|
+
} & (Stages['length'] extends 0
|
|
25
|
+
? {}
|
|
26
|
+
: UnionToIntersection<
|
|
27
|
+
{
|
|
28
|
+
[key in keyof CleanedStages]: MethodList extends {
|
|
29
|
+
symbol: CleanedStages[key]['stage']
|
|
30
|
+
field: infer F
|
|
31
|
+
}
|
|
32
|
+
? {
|
|
33
|
+
[k in F extends string ? F : never]: ModularStages<
|
|
34
|
+
ComputeArguments<
|
|
35
|
+
Props,
|
|
36
|
+
Ref,
|
|
37
|
+
Methods,
|
|
38
|
+
BeforeStage<CleanedStages, key>
|
|
39
|
+
>,
|
|
40
|
+
CleanedStages[key]['value']
|
|
41
|
+
>[CleanedStages[key]['stage']] extends { transform: infer T }
|
|
42
|
+
? T
|
|
43
|
+
: CleanedStages[key]['value']
|
|
44
|
+
}
|
|
45
|
+
: never
|
|
46
|
+
}[number]
|
|
47
|
+
>) extends infer U
|
|
48
|
+
? {
|
|
49
|
+
[key in keyof U]: U[key] extends Record<string, unknown>
|
|
50
|
+
? U[key] extends infer V
|
|
51
|
+
? { [key in keyof V]: V[key] }
|
|
52
|
+
: never
|
|
53
|
+
: U[key]
|
|
54
|
+
}
|
|
55
|
+
: never
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Methods for adding a new entry for a previous stage, rather
|
|
3
|
+
* than reusing the previous one.
|
|
4
|
+
* One two entries for the same stage have been added, `with`, `at` and
|
|
5
|
+
* `mock` methods can take an optional index to select the entry to target
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { ModularComponent } from '../modular-component'
|
|
9
|
+
import { AddStage, ModularStages, StageIndices, StageTuple } from '../stage'
|
|
10
|
+
import { ComputeArguments } from '../arguments'
|
|
11
|
+
import { RestrictValue } from '../validation'
|
|
12
|
+
import { MethodRecord } from '../methods'
|
|
13
|
+
import { FilterNever } from '../utils'
|
|
14
|
+
|
|
15
|
+
interface ModularAddMethod<
|
|
16
|
+
Props extends {},
|
|
17
|
+
Ref,
|
|
18
|
+
Methods extends Record<string, MethodRecord>,
|
|
19
|
+
Stages extends StageTuple,
|
|
20
|
+
Method extends keyof Methods,
|
|
21
|
+
Symbol extends keyof ModularStages = Methods[Method]['symbol'],
|
|
22
|
+
> {
|
|
23
|
+
<
|
|
24
|
+
Value extends RestrictValue<Arguments, Symbol>,
|
|
25
|
+
Arguments extends ComputeArguments<Props, Ref, Methods, Stages>,
|
|
26
|
+
>(
|
|
27
|
+
value: Value,
|
|
28
|
+
): ModularComponent<
|
|
29
|
+
Props,
|
|
30
|
+
Ref,
|
|
31
|
+
Methods,
|
|
32
|
+
AddStage<Stages, { stage: Symbol; value: Value }>
|
|
33
|
+
>
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type ModularAddMethods<
|
|
37
|
+
Props extends {},
|
|
38
|
+
Ref,
|
|
39
|
+
Methods extends Record<string, MethodRecord>,
|
|
40
|
+
Stages extends StageTuple,
|
|
41
|
+
> = FilterNever<{
|
|
42
|
+
[Method in keyof Methods as `add${Method extends string
|
|
43
|
+
? Method
|
|
44
|
+
: never}`]: StageIndices<
|
|
45
|
+
Stages,
|
|
46
|
+
Methods[Method]['symbol']
|
|
47
|
+
>['length'] extends 0
|
|
48
|
+
? never
|
|
49
|
+
: ModularAddMethod<Props, Ref, Methods, Stages, Method>
|
|
50
|
+
}>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Methods for rewinding a modular component up to a given stage.
|
|
3
|
+
* If multiple entries of the same stage were previously added,
|
|
4
|
+
* it's possible to pass the index for the entry to rewind to.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { ModularComponent } from '../modular-component'
|
|
8
|
+
import { AtStage, StageIndices, StageTuple } from '../stage'
|
|
9
|
+
import { FilterNever, Last, ToIndices } from '../utils'
|
|
10
|
+
import { ValidateIndex } from '../validation'
|
|
11
|
+
import { MethodRecord } from '../methods'
|
|
12
|
+
|
|
13
|
+
interface ModularAtMethodIndices<
|
|
14
|
+
Props extends {},
|
|
15
|
+
Ref,
|
|
16
|
+
Methods extends Record<string, MethodRecord>,
|
|
17
|
+
Stages extends StageTuple,
|
|
18
|
+
Method extends keyof Methods,
|
|
19
|
+
Indices extends number[],
|
|
20
|
+
> {
|
|
21
|
+
<
|
|
22
|
+
// Validate index
|
|
23
|
+
StageIndex extends Index extends number ? Indices[Index] : Last<Indices>,
|
|
24
|
+
ValidIndex extends ValidateIndex<Index, ToIndices<Indices>>,
|
|
25
|
+
Index extends number,
|
|
26
|
+
>(
|
|
27
|
+
index: ValidIndex extends true ? Index : ToIndices<Indices>,
|
|
28
|
+
): ModularComponent<Props, Ref, Methods, AtStage<Stages, StageIndex>>
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface ModularAtMethodLast<
|
|
32
|
+
Props extends {},
|
|
33
|
+
Ref,
|
|
34
|
+
Methods extends Record<string, MethodRecord>,
|
|
35
|
+
Stages extends StageTuple,
|
|
36
|
+
Method extends keyof Methods,
|
|
37
|
+
Index extends number,
|
|
38
|
+
> {
|
|
39
|
+
(): ModularComponent<Props, Ref, Methods, AtStage<Stages, Index>>
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
type ModularAtMethod<
|
|
43
|
+
Props extends {},
|
|
44
|
+
Ref,
|
|
45
|
+
Methods extends Record<string, MethodRecord>,
|
|
46
|
+
Stages extends StageTuple,
|
|
47
|
+
Method extends keyof Methods,
|
|
48
|
+
Symbol extends symbol = Methods[Method]['symbol'],
|
|
49
|
+
Indices extends StageIndices<Stages, Symbol> = StageIndices<Stages, Symbol>,
|
|
50
|
+
> = Indices['length'] extends 0
|
|
51
|
+
? never
|
|
52
|
+
: ModularAtMethodIndices<Props, Ref, Methods, Stages, Method, Indices> &
|
|
53
|
+
ModularAtMethodLast<Props, Ref, Methods, Stages, Method, Last<Indices>>
|
|
54
|
+
|
|
55
|
+
export type ModularAtMethods<
|
|
56
|
+
Props extends {},
|
|
57
|
+
Ref,
|
|
58
|
+
Methods extends Record<string, MethodRecord>,
|
|
59
|
+
Stages extends StageTuple,
|
|
60
|
+
> = FilterNever<{
|
|
61
|
+
[Method in keyof Methods as `at${Method extends string
|
|
62
|
+
? Method
|
|
63
|
+
: never}`]: ModularAtMethod<Props, Ref, Methods, Stages, Method>
|
|
64
|
+
}>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Methods for converting a modular component to hooks, either
|
|
3
|
+
* a generic hook returning all the arguments, or a specific hook
|
|
4
|
+
* returning one given argument.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { StageTuple } from '../stage'
|
|
8
|
+
import { MethodRecord } from '../methods'
|
|
9
|
+
import { ComputeArguments } from '../arguments'
|
|
10
|
+
|
|
11
|
+
export type ModularHookMethods<
|
|
12
|
+
Props extends {},
|
|
13
|
+
Ref,
|
|
14
|
+
Methods extends Record<string, MethodRecord>,
|
|
15
|
+
Stages extends StageTuple,
|
|
16
|
+
Arguments extends {} = ComputeArguments<Props, Ref, Methods, Stages>,
|
|
17
|
+
> = {
|
|
18
|
+
asHook(): keyof Props extends never
|
|
19
|
+
? () => Arguments
|
|
20
|
+
: (props: Props) => Arguments
|
|
21
|
+
} & {
|
|
22
|
+
[Arg in keyof Arguments as `asUse${Capitalize<
|
|
23
|
+
Arg extends string ? Arg : never
|
|
24
|
+
>}`]: keyof Props extends never
|
|
25
|
+
? () => () => Arguments[Arg]
|
|
26
|
+
: () => (props: Props) => Arguments[Arg]
|
|
27
|
+
}
|