@servicetitan/react-ioc 36.2.0 → 36.3.1
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/dist/dedupe-entries.d.ts +9 -0
- package/dist/dedupe-entries.d.ts.map +1 -0
- package/dist/dedupe-entries.js +35 -0
- package/dist/dedupe-entries.js.map +1 -0
- package/dist/entry-helpers.d.ts +33 -0
- package/dist/entry-helpers.d.ts.map +1 -0
- package/dist/entry-helpers.js +52 -0
- package/dist/entry-helpers.js.map +1 -0
- package/dist/provide.d.ts +2 -5
- package/dist/provide.d.ts.map +1 -1
- package/dist/provide.js.map +1 -1
- package/dist/provider.d.ts +2 -25
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +23 -49
- package/dist/provider.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/dedupe-entries.test.ts +143 -0
- package/src/__tests__/entry-helpers.test.ts +247 -0
- package/src/__tests__/provider.test.tsx +73 -0
- package/src/dedupe-entries.ts +50 -0
- package/src/entry-helpers.ts +113 -0
- package/src/provide.tsx +3 -5
- package/src/provider.tsx +46 -105
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Token } from './common';
|
|
2
|
+
import { ProviderConfigEntries, ProviderConfigEntryInstances, ProviderConfigEntrySingletons } from './entry-helpers';
|
|
3
|
+
export interface DedupeEntriesResult {
|
|
4
|
+
duplicates: Token<any>[];
|
|
5
|
+
singletons: ProviderConfigEntrySingletons<any>[];
|
|
6
|
+
instances: ProviderConfigEntryInstances<any>[];
|
|
7
|
+
}
|
|
8
|
+
export declare function dedupeEntries({ singletons, instances, }: ProviderConfigEntries): DedupeEntriesResult;
|
|
9
|
+
//# sourceMappingURL=dedupe-entries.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dedupe-entries.d.ts","sourceRoot":"","sources":["../src/dedupe-entries.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACjC,OAAO,EAEH,qBAAqB,EAErB,4BAA4B,EAC5B,6BAA6B,EAChC,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,mBAAmB;IAChC,UAAU,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;IACzB,UAAU,EAAE,6BAA6B,CAAC,GAAG,CAAC,EAAE,CAAC;IACjD,SAAS,EAAE,4BAA4B,CAAC,GAAG,CAAC,EAAE,CAAC;CAClD;AAED,wBAAgB,aAAa,CAAC,EAC1B,UAAe,EACf,SAAc,GACjB,EAAE,qBAAqB,GAAG,mBAAmB,CA+B7C"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { getProvideToken } from './entry-helpers';
|
|
2
|
+
export function dedupeEntries({ singletons = [], instances = [] }) {
|
|
3
|
+
const seen = new Set();
|
|
4
|
+
const duplicates = [];
|
|
5
|
+
const dedupedSingletons = [];
|
|
6
|
+
const dedupedInstances = [];
|
|
7
|
+
function isDuplicate(entry) {
|
|
8
|
+
const token = getProvideToken(entry);
|
|
9
|
+
if (!seen.has(token)) {
|
|
10
|
+
seen.add(token);
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
if (!duplicates.includes(token)) {
|
|
14
|
+
duplicates.push(token);
|
|
15
|
+
}
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
for (const entry of singletons){
|
|
19
|
+
if (!isDuplicate(entry)) {
|
|
20
|
+
dedupedSingletons.push(entry);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
for (const entry of instances){
|
|
24
|
+
if (!isDuplicate(entry)) {
|
|
25
|
+
dedupedInstances.push(entry);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
duplicates,
|
|
30
|
+
singletons: dedupedSingletons,
|
|
31
|
+
instances: dedupedInstances
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
//# sourceMappingURL=dedupe-entries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/dedupe-entries.ts"],"sourcesContent":["import { Token } from './common';\nimport {\n getProvideToken,\n ProviderConfigEntries,\n ProviderConfigEntry,\n ProviderConfigEntryInstances,\n ProviderConfigEntrySingletons,\n} from './entry-helpers';\n\nexport interface DedupeEntriesResult {\n duplicates: Token<any>[];\n singletons: ProviderConfigEntrySingletons<any>[];\n instances: ProviderConfigEntryInstances<any>[];\n}\n\nexport function dedupeEntries({\n singletons = [],\n instances = [],\n}: ProviderConfigEntries): DedupeEntriesResult {\n const seen = new Set<Token<any>>();\n const duplicates: Token<any>[] = [];\n const dedupedSingletons: ProviderConfigEntrySingletons<any>[] = [];\n const dedupedInstances: ProviderConfigEntryInstances<any>[] = [];\n\n function isDuplicate(entry: ProviderConfigEntry<any>): boolean {\n const token = getProvideToken(entry);\n if (!seen.has(token)) {\n seen.add(token);\n return false;\n }\n if (!duplicates.includes(token)) {\n duplicates.push(token);\n }\n return true;\n }\n\n for (const entry of singletons) {\n if (!isDuplicate(entry)) {\n dedupedSingletons.push(entry);\n }\n }\n\n for (const entry of instances) {\n if (!isDuplicate(entry)) {\n dedupedInstances.push(entry);\n }\n }\n\n return { duplicates, singletons: dedupedSingletons, instances: dedupedInstances };\n}\n"],"names":["getProvideToken","dedupeEntries","singletons","instances","seen","Set","duplicates","dedupedSingletons","dedupedInstances","isDuplicate","entry","token","has","add","includes","push"],"mappings":"AACA,SACIA,eAAe,QAKZ,kBAAkB;AAQzB,OAAO,SAASC,cAAc,EAC1BC,aAAa,EAAE,EACfC,YAAY,EAAE,EACM;IACpB,MAAMC,OAAO,IAAIC;IACjB,MAAMC,aAA2B,EAAE;IACnC,MAAMC,oBAA0D,EAAE;IAClE,MAAMC,mBAAwD,EAAE;IAEhE,SAASC,YAAYC,KAA+B;QAChD,MAAMC,QAAQX,gBAAgBU;QAC9B,IAAI,CAACN,KAAKQ,GAAG,CAACD,QAAQ;YAClBP,KAAKS,GAAG,CAACF;YACT,OAAO;QACX;QACA,IAAI,CAACL,WAAWQ,QAAQ,CAACH,QAAQ;YAC7BL,WAAWS,IAAI,CAACJ;QACpB;QACA,OAAO;IACX;IAEA,KAAK,MAAMD,SAASR,WAAY;QAC5B,IAAI,CAACO,YAAYC,QAAQ;YACrBH,kBAAkBQ,IAAI,CAACL;QAC3B;IACJ;IAEA,KAAK,MAAMA,SAASP,UAAW;QAC3B,IAAI,CAACM,YAAYC,QAAQ;YACrBF,iBAAiBO,IAAI,CAACL;QAC1B;IACJ;IAEA,OAAO;QAAEJ;QAAYJ,YAAYK;QAAmBJ,WAAWK;IAAiB;AACpF"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { interfaces } from 'inversify';
|
|
2
|
+
import { SymbolToken, Token } from './common';
|
|
3
|
+
export type ProviderConfigEntrySingletons<T> = ClassProviderConfigEntry<T> | ValueProviderConfigEntry<T>;
|
|
4
|
+
export type ProviderConfigEntryInstances<T> = ClassProviderConfigEntryNoInherit<T>;
|
|
5
|
+
export type ProviderConfigEntry<T> = ProviderConfigEntrySingletons<T> | ProviderConfigEntryInstances<T>;
|
|
6
|
+
export interface ProviderConfigEntries {
|
|
7
|
+
singletons?: ProviderConfigEntrySingletons<any>[];
|
|
8
|
+
instances?: ProviderConfigEntryInstances<any>[];
|
|
9
|
+
}
|
|
10
|
+
export type ClassProviderConfigEntry<T> = interfaces.Newable<T> | ClassProviderConfigEntryUseClass<T> | ClassProviderConfigEntryToken<T>;
|
|
11
|
+
export type ClassProviderConfigEntryNoInherit<T> = interfaces.Newable<T> | Omit<ClassProviderConfigEntryUseClass<T>, 'inherit'>;
|
|
12
|
+
export interface ClassProviderConfigEntryUseClass<T> {
|
|
13
|
+
provide: Token<T>;
|
|
14
|
+
useClass: interfaces.Newable<T>;
|
|
15
|
+
inherit?: true;
|
|
16
|
+
}
|
|
17
|
+
export interface ClassProviderConfigEntryToken<T> {
|
|
18
|
+
provide: interfaces.Newable<T>;
|
|
19
|
+
inherit?: true;
|
|
20
|
+
}
|
|
21
|
+
export interface ValueProviderConfigEntry<T> {
|
|
22
|
+
provide: SymbolToken<T> | Function;
|
|
23
|
+
useValue: T;
|
|
24
|
+
inherit?: true;
|
|
25
|
+
}
|
|
26
|
+
export declare function formatToken(token: Token<unknown>): string;
|
|
27
|
+
export declare function getProvideToken<T>(entry: ProviderConfigEntry<T>): Token<T>;
|
|
28
|
+
export declare function getProvideTokenWithClass<T>(entry: ProviderConfigEntry<T>): [Token<T>, interfaces.Newable<T>] | [undefined, undefined];
|
|
29
|
+
export declare function isClassProviderConfigEntryToken<T>(entry: ProviderConfigEntry<T>): entry is Omit<ClassProviderConfigEntryToken<T>, 'inherit'>;
|
|
30
|
+
export declare function isClassProviderConfigEntryUseClass<T>(entry: ProviderConfigEntry<T>): entry is Omit<ClassProviderConfigEntryUseClass<T>, 'inherit'>;
|
|
31
|
+
export declare function isProviderConfigEntryInheritable<T>(entry: ProviderConfigEntry<T>): entry is ClassProviderConfigEntryUseClass<T> | ClassProviderConfigEntryToken<T> | ValueProviderConfigEntry<T>;
|
|
32
|
+
export declare function isValueProviderConfigEntry<T>(entry: ProviderConfigEntry<T>): entry is Omit<ValueProviderConfigEntry<T>, 'inherit'>;
|
|
33
|
+
//# sourceMappingURL=entry-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entry-helpers.d.ts","sourceRoot":"","sources":["../src/entry-helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export function formatToken(token) {
|
|
2
|
+
if (typeof token === 'symbol') {
|
|
3
|
+
var _token_description;
|
|
4
|
+
return (_token_description = token.description) !== null && _token_description !== void 0 ? _token_description : token.toString();
|
|
5
|
+
}
|
|
6
|
+
const name = token.name;
|
|
7
|
+
return name && name.length > 0 ? name : '(anonymous)';
|
|
8
|
+
}
|
|
9
|
+
export function getProvideToken(entry) {
|
|
10
|
+
if (isClassProviderConfigEntryUseClass(entry) || isClassProviderConfigEntryToken(entry) || isValueProviderConfigEntry(entry)) {
|
|
11
|
+
return entry.provide;
|
|
12
|
+
}
|
|
13
|
+
return entry;
|
|
14
|
+
}
|
|
15
|
+
export function getProvideTokenWithClass(entry) {
|
|
16
|
+
if (isClassProviderConfigEntryUseClass(entry)) {
|
|
17
|
+
return [
|
|
18
|
+
entry.provide,
|
|
19
|
+
entry.useClass
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
if (isClassProviderConfigEntryToken(entry)) {
|
|
23
|
+
return [
|
|
24
|
+
entry.provide,
|
|
25
|
+
entry.provide
|
|
26
|
+
];
|
|
27
|
+
}
|
|
28
|
+
if (isValueProviderConfigEntry(entry)) {
|
|
29
|
+
return [
|
|
30
|
+
undefined,
|
|
31
|
+
undefined
|
|
32
|
+
];
|
|
33
|
+
}
|
|
34
|
+
return [
|
|
35
|
+
entry,
|
|
36
|
+
entry
|
|
37
|
+
];
|
|
38
|
+
}
|
|
39
|
+
export function isClassProviderConfigEntryToken(entry) {
|
|
40
|
+
return Object.hasOwn(entry, 'provide') && !Object.hasOwn(entry, 'useClass') && !Object.hasOwn(entry, 'useValue');
|
|
41
|
+
}
|
|
42
|
+
export function isClassProviderConfigEntryUseClass(entry) {
|
|
43
|
+
return Object.hasOwn(entry, 'provide') && Object.hasOwn(entry, 'useClass');
|
|
44
|
+
}
|
|
45
|
+
export function isProviderConfigEntryInheritable(entry) {
|
|
46
|
+
return isClassProviderConfigEntryUseClass(entry) || isClassProviderConfigEntryToken(entry) || isValueProviderConfigEntry(entry);
|
|
47
|
+
}
|
|
48
|
+
export function isValueProviderConfigEntry(entry) {
|
|
49
|
+
return Object.hasOwn(entry, 'provide') && Object.hasOwn(entry, 'useValue');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
//# sourceMappingURL=entry-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/entry-helpers.ts"],"sourcesContent":["import { interfaces } from 'inversify';\nimport { SymbolToken, Token } from './common';\n\nexport type ProviderConfigEntrySingletons<T> =\n | ClassProviderConfigEntry<T>\n | ValueProviderConfigEntry<T>;\nexport type ProviderConfigEntryInstances<T> = ClassProviderConfigEntryNoInherit<T>;\nexport type ProviderConfigEntry<T> =\n | ProviderConfigEntrySingletons<T>\n | ProviderConfigEntryInstances<T>;\n\nexport interface ProviderConfigEntries {\n singletons?: ProviderConfigEntrySingletons<any>[];\n instances?: ProviderConfigEntryInstances<any>[];\n}\n\nexport type ClassProviderConfigEntry<T> =\n | interfaces.Newable<T>\n | ClassProviderConfigEntryUseClass<T>\n | ClassProviderConfigEntryToken<T>;\n\nexport type ClassProviderConfigEntryNoInherit<T> =\n | interfaces.Newable<T>\n | Omit<ClassProviderConfigEntryUseClass<T>, 'inherit'>;\n\nexport interface ClassProviderConfigEntryUseClass<T> {\n provide: Token<T>;\n useClass: interfaces.Newable<T>;\n inherit?: true;\n}\n\nexport interface ClassProviderConfigEntryToken<T> {\n provide: interfaces.Newable<T>;\n inherit?: true;\n}\n\nexport interface ValueProviderConfigEntry<T> {\n provide: SymbolToken<T> | Function;\n useValue: T;\n inherit?: true;\n}\n\nexport function formatToken(token: Token<unknown>): string {\n if (typeof token === 'symbol') {\n return token.description ?? token.toString();\n }\n const name = (token as Function).name;\n return name && name.length > 0 ? name : '(anonymous)';\n}\n\nexport function getProvideToken<T>(entry: ProviderConfigEntry<T>): Token<T> {\n if (\n isClassProviderConfigEntryUseClass(entry) ||\n isClassProviderConfigEntryToken(entry) ||\n isValueProviderConfigEntry(entry)\n ) {\n return entry.provide;\n }\n return entry;\n}\n\nexport function getProvideTokenWithClass<T>(\n entry: ProviderConfigEntry<T>\n): [Token<T>, interfaces.Newable<T>] | [undefined, undefined] {\n if (isClassProviderConfigEntryUseClass(entry)) {\n return [entry.provide, entry.useClass];\n }\n\n if (isClassProviderConfigEntryToken(entry)) {\n return [entry.provide, entry.provide];\n }\n\n if (isValueProviderConfigEntry(entry)) {\n return [undefined, undefined];\n }\n\n return [entry, entry];\n}\n\nexport function isClassProviderConfigEntryToken<T>(\n entry: ProviderConfigEntry<T>\n): entry is Omit<ClassProviderConfigEntryToken<T>, 'inherit'> {\n return (\n Object.hasOwn(entry, 'provide') &&\n !Object.hasOwn(entry, 'useClass') &&\n !Object.hasOwn(entry, 'useValue')\n );\n}\n\nexport function isClassProviderConfigEntryUseClass<T>(\n entry: ProviderConfigEntry<T>\n): entry is Omit<ClassProviderConfigEntryUseClass<T>, 'inherit'> {\n return Object.hasOwn(entry, 'provide') && Object.hasOwn(entry, 'useClass');\n}\n\nexport function isProviderConfigEntryInheritable<T>(\n entry: ProviderConfigEntry<T>\n): entry is\n | ClassProviderConfigEntryUseClass<T>\n | ClassProviderConfigEntryToken<T>\n | ValueProviderConfigEntry<T> {\n return (\n isClassProviderConfigEntryUseClass(entry) ||\n isClassProviderConfigEntryToken(entry) ||\n isValueProviderConfigEntry(entry)\n );\n}\n\nexport function isValueProviderConfigEntry<T>(\n entry: ProviderConfigEntry<T>\n): entry is Omit<ValueProviderConfigEntry<T>, 'inherit'> {\n return Object.hasOwn(entry, 'provide') && Object.hasOwn(entry, 'useValue');\n}\n"],"names":["formatToken","token","description","toString","name","length","getProvideToken","entry","isClassProviderConfigEntryUseClass","isClassProviderConfigEntryToken","isValueProviderConfigEntry","provide","getProvideTokenWithClass","useClass","undefined","Object","hasOwn","isProviderConfigEntryInheritable"],"mappings":"AA0CA,OAAO,SAASA,YAAYC,KAAqB;IAC7C,IAAI,OAAOA,UAAU,UAAU;YACpBA;QAAP,QAAOA,qBAAAA,MAAMC,WAAW,cAAjBD,gCAAAA,qBAAqBA,MAAME,QAAQ;IAC9C;IACA,MAAMC,OAAO,AAACH,MAAmBG,IAAI;IACrC,OAAOA,QAAQA,KAAKC,MAAM,GAAG,IAAID,OAAO;AAC5C;AAEA,OAAO,SAASE,gBAAmBC,KAA6B;IAC5D,IACIC,mCAAmCD,UACnCE,gCAAgCF,UAChCG,2BAA2BH,QAC7B;QACE,OAAOA,MAAMI,OAAO;IACxB;IACA,OAAOJ;AACX;AAEA,OAAO,SAASK,yBACZL,KAA6B;IAE7B,IAAIC,mCAAmCD,QAAQ;QAC3C,OAAO;YAACA,MAAMI,OAAO;YAAEJ,MAAMM,QAAQ;SAAC;IAC1C;IAEA,IAAIJ,gCAAgCF,QAAQ;QACxC,OAAO;YAACA,MAAMI,OAAO;YAAEJ,MAAMI,OAAO;SAAC;IACzC;IAEA,IAAID,2BAA2BH,QAAQ;QACnC,OAAO;YAACO;YAAWA;SAAU;IACjC;IAEA,OAAO;QAACP;QAAOA;KAAM;AACzB;AAEA,OAAO,SAASE,gCACZF,KAA6B;IAE7B,OACIQ,OAAOC,MAAM,CAACT,OAAO,cACrB,CAACQ,OAAOC,MAAM,CAACT,OAAO,eACtB,CAACQ,OAAOC,MAAM,CAACT,OAAO;AAE9B;AAEA,OAAO,SAASC,mCACZD,KAA6B;IAE7B,OAAOQ,OAAOC,MAAM,CAACT,OAAO,cAAcQ,OAAOC,MAAM,CAACT,OAAO;AACnE;AAEA,OAAO,SAASU,iCACZV,KAA6B;IAK7B,OACIC,mCAAmCD,UACnCE,gCAAgCF,UAChCG,2BAA2BH;AAEnC;AAEA,OAAO,SAASG,2BACZH,KAA6B;IAE7B,OAAOQ,OAAOC,MAAM,CAACT,OAAO,cAAcQ,OAAOC,MAAM,CAACT,OAAO;AACnE"}
|
package/dist/provide.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ComponentType, ReactInstance, ReactNode } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { ProviderConfigEntries } from './entry-helpers';
|
|
3
3
|
export interface WrappedComponent<P> {
|
|
4
4
|
wrappedComponent: ComponentType<P>;
|
|
5
5
|
wrappedInstance: ReactInstance | undefined;
|
|
@@ -8,9 +8,6 @@ export interface FallbackOptions {
|
|
|
8
8
|
loadingFallback?: ReactNode;
|
|
9
9
|
errorFallback?: ReactNode;
|
|
10
10
|
}
|
|
11
|
-
export type ProvideDecorator = (stores:
|
|
12
|
-
singletons?: ProviderConfigEntrySingletons<any>[];
|
|
13
|
-
instances?: ProviderConfigEntryInstances<any>[];
|
|
14
|
-
}, options?: ReactNode | FallbackOptions) => <T extends ComponentType<any>>(target: T) => T & WrappedComponent<T>;
|
|
11
|
+
export type ProvideDecorator = (stores: ProviderConfigEntries, options?: ReactNode | FallbackOptions) => <T extends ComponentType<any>>(target: T) => T & WrappedComponent<T>;
|
|
15
12
|
export declare const provide: ProvideDecorator;
|
|
16
13
|
//# sourceMappingURL=provide.d.ts.map
|
package/dist/provide.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provide.d.ts","sourceRoot":"","sources":["../src/provide.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAChE,OAAO,
|
|
1
|
+
{"version":3,"file":"provide.d.ts","sourceRoot":"","sources":["../src/provide.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAGxD,MAAM,WAAW,gBAAgB,CAAC,CAAC;IAC/B,gBAAgB,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;IACnC,eAAe,EAAE,aAAa,GAAG,SAAS,CAAC;CAC9C;AAED,MAAM,WAAW,eAAe;IAC5B,eAAe,CAAC,EAAE,SAAS,CAAC;IAC5B,aAAa,CAAC,EAAE,SAAS,CAAC;CAC7B;AAED,MAAM,MAAM,gBAAgB,GAAG,CAC3B,MAAM,EAAE,qBAAqB,EAC7B,OAAO,CAAC,EAAE,SAAS,GAAG,eAAe,KACpC,CAAC,CAAC,SAAS,aAAa,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC;AAE1E,eAAO,MAAM,OAAO,EAId,gBAAgB,CAAC"}
|
package/dist/provide.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/provide.tsx"],"sourcesContent":["import { ComponentType, ReactInstance, ReactNode } from 'react';\nimport {
|
|
1
|
+
{"version":3,"sources":["../src/provide.tsx"],"sourcesContent":["import { ComponentType, ReactInstance, ReactNode } from 'react';\nimport { ProviderConfigEntries } from './entry-helpers';\nimport { Provider } from './provider';\n\nexport interface WrappedComponent<P> {\n wrappedComponent: ComponentType<P>;\n wrappedInstance: ReactInstance | undefined;\n}\n\nexport interface FallbackOptions {\n loadingFallback?: ReactNode;\n errorFallback?: ReactNode;\n}\n\nexport type ProvideDecorator = (\n stores: ProviderConfigEntries,\n options?: ReactNode | FallbackOptions\n) => <T extends ComponentType<any>>(target: T) => T & WrappedComponent<T>;\n\nexport const provide = ((stores, elementOrOptions) => (Component: ComponentType) => props => (\n <Provider {...stores} {...getOptions(elementOrOptions)}>\n <Component {...props} />\n </Provider>\n)) as ProvideDecorator;\n\nfunction getOptions(arg?: FallbackOptions | ReactNode): FallbackOptions | undefined {\n return arg && isOptionsObject(arg) ? arg : { loadingFallback: arg };\n}\n\nfunction isOptionsObject(arg: FallbackOptions | NonNullable<ReactNode>): arg is FallbackOptions {\n return (\n typeof arg === 'object' &&\n (Object.hasOwn(arg, 'loadingFallback') ||\n Object.hasOwn(arg, 'errorFallback') ||\n Object.keys(arg).length === 0)\n );\n}\n"],"names":["Provider","provide","stores","elementOrOptions","Component","props","getOptions","arg","isOptionsObject","loadingFallback","Object","hasOwn","keys","length"],"mappings":";AAEA,SAASA,QAAQ,QAAQ,aAAa;AAiBtC,OAAO,MAAMC,UAAW,CAACC,QAAQC,mBAAqB,CAACC,YAA6BC,CAAAA,sBAChF,KAACL;gBAAU,GAAGE,MAAM;gBAAG,GAAGI,WAAWH,iBAAiB;0BAClD,cAAA,KAACC;oBAAW,GAAGC,KAAK;;eAEL;AAEvB,SAASC,WAAWC,GAAiC;IACjD,OAAOA,OAAOC,gBAAgBD,OAAOA,MAAM;QAAEE,iBAAiBF;IAAI;AACtE;AAEA,SAASC,gBAAgBD,GAA6C;IAClE,OACI,OAAOA,QAAQ,YACdG,CAAAA,OAAOC,MAAM,CAACJ,KAAK,sBAChBG,OAAOC,MAAM,CAACJ,KAAK,oBACnBG,OAAOE,IAAI,CAACL,KAAKM,MAAM,KAAK,CAAA;AAExC"}
|
package/dist/provider.d.ts
CHANGED
|
@@ -1,31 +1,8 @@
|
|
|
1
|
-
import { interfaces } from 'inversify';
|
|
2
1
|
import { FC, PropsWithChildren, ReactNode } from 'react';
|
|
3
|
-
import {
|
|
4
|
-
export type
|
|
5
|
-
export type ProviderConfigEntryInstances<T> = ClassProviderConfigEntryNoInherit<T>;
|
|
6
|
-
export type ProviderConfigEntry<T> = ProviderConfigEntrySingletons<T> | ProviderConfigEntryInstances<T>;
|
|
7
|
-
type ClassProviderConfigEntry<T> = interfaces.Newable<T> | ClassProviderConfigEntryUseClass<T> | ClassProviderConfigEntryToken<T>;
|
|
8
|
-
type ClassProviderConfigEntryNoInherit<T> = interfaces.Newable<T> | Omit<ClassProviderConfigEntryUseClass<T>, 'inherit'>;
|
|
9
|
-
interface ClassProviderConfigEntryUseClass<T> {
|
|
10
|
-
provide: Token<T>;
|
|
11
|
-
useClass: interfaces.Newable<T>;
|
|
12
|
-
inherit?: true;
|
|
13
|
-
}
|
|
14
|
-
interface ClassProviderConfigEntryToken<T> {
|
|
15
|
-
provide: interfaces.Newable<T>;
|
|
16
|
-
inherit?: true;
|
|
17
|
-
}
|
|
18
|
-
interface ValueProviderConfigEntry<T> {
|
|
19
|
-
provide: SymbolToken<T> | Function;
|
|
20
|
-
useValue: T;
|
|
21
|
-
inherit?: true;
|
|
22
|
-
}
|
|
23
|
-
export type ProviderProps = PropsWithChildren<{
|
|
24
|
-
singletons?: ProviderConfigEntrySingletons<any>[];
|
|
25
|
-
instances?: ProviderConfigEntryInstances<any>[];
|
|
2
|
+
import { ProviderConfigEntries } from './entry-helpers';
|
|
3
|
+
export type ProviderProps = PropsWithChildren<ProviderConfigEntries & {
|
|
26
4
|
loadingFallback?: ReactNode;
|
|
27
5
|
errorFallback?: ReactNode;
|
|
28
6
|
}>;
|
|
29
7
|
export declare const Provider: FC<ProviderProps>;
|
|
30
|
-
export {};
|
|
31
8
|
//# sourceMappingURL=provider.d.ts.map
|
package/dist/provider.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAE,iBAAiB,EAAE,SAAS,EAAmC,MAAM,OAAO,CAAC;AAI1F,OAAO,EAOH,qBAAqB,EAExB,MAAM,iBAAiB,CAAC;AA6GzB,MAAM,MAAM,aAAa,GAAG,iBAAiB,CACzC,qBAAqB,GAAG;IACpB,eAAe,CAAC,EAAE,SAAS,CAAC;IAC5B,aAAa,CAAC,EAAE,SAAS,CAAC;CAC7B,CACJ,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,EAAE,CAAC,aAAa,CA2EtC,CAAC"}
|
package/dist/provider.js
CHANGED
|
@@ -3,44 +3,10 @@ import { Container } from 'inversify';
|
|
|
3
3
|
import { useContext, useEffect, useState } from 'react';
|
|
4
4
|
import { Await } from './await';
|
|
5
5
|
import { ContainerContext } from './common';
|
|
6
|
+
import { dedupeEntries } from './dedupe-entries';
|
|
7
|
+
import { formatToken, getProvideTokenWithClass, isClassProviderConfigEntryToken, isClassProviderConfigEntryUseClass, isProviderConfigEntryInheritable, isValueProviderConfigEntry } from './entry-helpers';
|
|
6
8
|
import { defaultErrorFallback, defaultLoadingFallback } from './fallbacks';
|
|
7
9
|
import { isStore } from './store';
|
|
8
|
-
function isClassProviderConfigEntryUseClass(entry) {
|
|
9
|
-
return Object.hasOwn(entry, 'provide') && Object.hasOwn(entry, 'useClass');
|
|
10
|
-
}
|
|
11
|
-
function isValueProviderConfigEntry(entry) {
|
|
12
|
-
return Object.hasOwn(entry, 'provide') && Object.hasOwn(entry, 'useValue');
|
|
13
|
-
}
|
|
14
|
-
function isClassProviderConfigEntryToken(entry) {
|
|
15
|
-
return Object.hasOwn(entry, 'provide') && !Object.hasOwn(entry, 'useClass') && !Object.hasOwn(entry, 'useValue');
|
|
16
|
-
}
|
|
17
|
-
function isProviderConfigEntryInheritable(entry) {
|
|
18
|
-
return isClassProviderConfigEntryUseClass(entry) || isClassProviderConfigEntryToken(entry) || isValueProviderConfigEntry(entry);
|
|
19
|
-
}
|
|
20
|
-
function getProvideTokenWithClass(entry) {
|
|
21
|
-
if (isClassProviderConfigEntryUseClass(entry)) {
|
|
22
|
-
return [
|
|
23
|
-
entry.provide,
|
|
24
|
-
entry.useClass
|
|
25
|
-
];
|
|
26
|
-
}
|
|
27
|
-
if (isClassProviderConfigEntryToken(entry)) {
|
|
28
|
-
return [
|
|
29
|
-
entry.provide,
|
|
30
|
-
entry.provide
|
|
31
|
-
];
|
|
32
|
-
}
|
|
33
|
-
if (isValueProviderConfigEntry(entry)) {
|
|
34
|
-
return [
|
|
35
|
-
undefined,
|
|
36
|
-
undefined
|
|
37
|
-
];
|
|
38
|
-
}
|
|
39
|
-
return [
|
|
40
|
-
entry,
|
|
41
|
-
entry
|
|
42
|
-
];
|
|
43
|
-
}
|
|
44
10
|
function getStoreInstances(container, { singletons = [], instances = [] }) {
|
|
45
11
|
return [
|
|
46
12
|
...singletons,
|
|
@@ -112,6 +78,10 @@ function disposeStores(stores) {
|
|
|
112
78
|
(_instance_dispose = instance.dispose) === null || _instance_dispose === void 0 ? void 0 : _instance_dispose.call(instance);
|
|
113
79
|
}
|
|
114
80
|
}
|
|
81
|
+
function formatDuplicatesMessage(duplicates) {
|
|
82
|
+
const names = duplicates.map(formatToken).join(', ');
|
|
83
|
+
return `Provider: token listed more than once: ${names}. Remove the duplicate entries.`;
|
|
84
|
+
}
|
|
115
85
|
export const Provider = ({ singletons, instances, loadingFallback = defaultLoadingFallback, errorFallback = defaultErrorFallback, children })=>{
|
|
116
86
|
const parentContainer = useContext(ContainerContext);
|
|
117
87
|
const [container, setContainer] = useState();
|
|
@@ -128,24 +98,28 @@ export const Provider = ({ singletons, instances, loadingFallback = defaultLoadi
|
|
|
128
98
|
throw e;
|
|
129
99
|
});
|
|
130
100
|
};
|
|
131
|
-
|
|
101
|
+
const config = dedupeEntries({
|
|
132
102
|
singletons,
|
|
133
103
|
instances
|
|
134
104
|
});
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
105
|
+
if (config.duplicates.length > 0) {
|
|
106
|
+
const message = formatDuplicatesMessage(config.duplicates);
|
|
107
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
108
|
+
handleError(new Error(message));
|
|
109
|
+
return ()=>{
|
|
110
|
+
setContainer(undefined);
|
|
111
|
+
setPromises([]);
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
// eslint-disable-next-line no-console
|
|
115
|
+
console.warn(message);
|
|
116
|
+
}
|
|
117
|
+
bindEntries(container, config);
|
|
118
|
+
const promises = initializeStores(getStoreInstances(container, config), handleError);
|
|
139
119
|
setPromises(promises);
|
|
140
120
|
return ()=>{
|
|
141
|
-
const storeInstances = getStoreInstances(container,
|
|
142
|
-
|
|
143
|
-
instances
|
|
144
|
-
});
|
|
145
|
-
unbindEntries(container, {
|
|
146
|
-
singletons,
|
|
147
|
-
instances
|
|
148
|
-
});
|
|
121
|
+
const storeInstances = getStoreInstances(container, config);
|
|
122
|
+
unbindEntries(container, config);
|
|
149
123
|
disposeStores(storeInstances);
|
|
150
124
|
setContainer(undefined);
|
|
151
125
|
setPromises([]);
|
package/dist/provider.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/provider.tsx"],"sourcesContent":["import { Container, interfaces } from 'inversify';\nimport { FC, PropsWithChildren, ReactNode, useContext, useEffect, useState } from 'react';\nimport { Await } from './await';\nimport { ContainerContext, SymbolToken, Token } from './common';\nimport { defaultErrorFallback, defaultLoadingFallback } from './fallbacks';\nimport { isStore, Store } from './store';\n\nexport type ProviderConfigEntrySingletons<T> =\n | ClassProviderConfigEntry<T>\n | ValueProviderConfigEntry<T>;\nexport type ProviderConfigEntryInstances<T> = ClassProviderConfigEntryNoInherit<T>;\nexport type ProviderConfigEntry<T> =\n | ProviderConfigEntrySingletons<T>\n | ProviderConfigEntryInstances<T>;\n\ntype ClassProviderConfigEntry<T> =\n | interfaces.Newable<T>\n | ClassProviderConfigEntryUseClass<T>\n | ClassProviderConfigEntryToken<T>;\n\ntype ClassProviderConfigEntryNoInherit<T> =\n | interfaces.Newable<T>\n | Omit<ClassProviderConfigEntryUseClass<T>, 'inherit'>;\n\ninterface ClassProviderConfigEntryUseClass<T> {\n provide: Token<T>;\n useClass: interfaces.Newable<T>;\n inherit?: true;\n}\n\ninterface ClassProviderConfigEntryToken<T> {\n provide: interfaces.Newable<T>;\n inherit?: true;\n}\n\ninterface ValueProviderConfigEntry<T> {\n provide: SymbolToken<T> | Function;\n useValue: T;\n inherit?: true;\n}\n\nfunction isClassProviderConfigEntryUseClass<T>(\n entry: ProviderConfigEntry<T>\n): entry is Omit<ClassProviderConfigEntryUseClass<T>, 'inherit'> {\n return Object.hasOwn(entry, 'provide') && Object.hasOwn(entry, 'useClass');\n}\n\nfunction isValueProviderConfigEntry<T>(\n entry: ProviderConfigEntry<T>\n): entry is Omit<ValueProviderConfigEntry<T>, 'inherit'> {\n return Object.hasOwn(entry, 'provide') && Object.hasOwn(entry, 'useValue');\n}\n\nfunction isClassProviderConfigEntryToken<T>(\n entry: ProviderConfigEntry<T>\n): entry is Omit<ClassProviderConfigEntryToken<T>, 'inherit'> {\n return (\n Object.hasOwn(entry, 'provide') &&\n !Object.hasOwn(entry, 'useClass') &&\n !Object.hasOwn(entry, 'useValue')\n );\n}\n\nfunction isProviderConfigEntryInheritable<T>(\n entry: ProviderConfigEntry<T>\n): entry is\n | ClassProviderConfigEntryUseClass<T>\n | ClassProviderConfigEntryToken<T>\n | ValueProviderConfigEntry<T> {\n return (\n isClassProviderConfigEntryUseClass(entry) ||\n isClassProviderConfigEntryToken(entry) ||\n isValueProviderConfigEntry(entry)\n );\n}\n\nfunction getProvideTokenWithClass<T>(\n entry: ProviderConfigEntry<T>\n): [Token<T>, interfaces.Newable<T>] | [undefined, undefined] {\n if (isClassProviderConfigEntryUseClass(entry)) {\n return [entry.provide, entry.useClass];\n }\n\n if (isClassProviderConfigEntryToken(entry)) {\n return [entry.provide, entry.provide];\n }\n\n if (isValueProviderConfigEntry(entry)) {\n return [undefined, undefined];\n }\n\n return [entry, entry];\n}\n\nfunction getStoreInstances(\n container: Container,\n { singletons = [], instances = [] }: Pick<ProviderProps, 'singletons' | 'instances'>\n): Store[] {\n return [...singletons, ...instances].reduce((out, entry) => {\n const [provide, useClass] = getProvideTokenWithClass(entry);\n\n if (provide && useClass && container.isCurrentBound(provide) && isStore(useClass)) {\n out.push(container.get(provide));\n }\n\n return out;\n }, [] as Store[]);\n}\n\nconst bindEntry =\n (container: Container, checkInherit: boolean) => (entry: ProviderConfigEntry<any>) => {\n if (\n checkInherit &&\n isProviderConfigEntryInheritable(entry) &&\n entry.inherit &&\n container.isBound(entry.provide)\n ) {\n return undefined;\n }\n\n if (isClassProviderConfigEntryUseClass(entry)) {\n return container.bind(entry.provide).to(entry.useClass);\n }\n\n if (isClassProviderConfigEntryToken(entry)) {\n return container.bind(entry.provide).to(entry.provide);\n }\n\n if (isValueProviderConfigEntry(entry)) {\n // using toDynamicValue to return BindingInSyntax\n return container.bind(entry.provide).toDynamicValue(() => entry.useValue);\n }\n\n return container.bind(entry).to(entry);\n };\n\nconst unbindEntry = (container: Container) => (entry: ProviderConfigEntry<any>) => {\n if (isProviderConfigEntryInheritable(entry) && !container.isCurrentBound(entry.provide)) {\n return;\n }\n if (\n isClassProviderConfigEntryUseClass(entry) ||\n isValueProviderConfigEntry(entry) ||\n isClassProviderConfigEntryToken(entry)\n ) {\n return container.unbind(entry.provide);\n }\n\n return container.unbind(entry);\n};\n\nfunction bindEntries(\n container: Container,\n { singletons = [], instances = [] }: Pick<ProviderProps, 'singletons' | 'instances'>\n) {\n singletons.map(bindEntry(container, true)).forEach(binding => {\n binding?.inSingletonScope();\n });\n instances.forEach(bindEntry(container, false));\n}\n\nfunction unbindEntries(\n container: Container,\n { singletons = [], instances = [] }: Pick<ProviderProps, 'singletons' | 'instances'>\n) {\n [...singletons, ...instances].forEach(unbindEntry(container));\n}\n\nfunction initializeStores(stores: Store[], onError: (error: any) => void) {\n const promises: Promise<void>[] = [];\n\n for (const instance of stores) {\n let promise;\n\n try {\n promise = instance.initialize?.();\n } catch (e: any) {\n onError(e);\n }\n\n if (promise && typeof promise.catch === 'function') {\n promises.push(promise.catch(onError));\n }\n }\n\n return promises;\n}\n\nfunction disposeStores(stores: Store[]) {\n for (const instance of stores) {\n instance.dispose?.();\n }\n}\n\nexport type ProviderProps = PropsWithChildren<{\n singletons?: ProviderConfigEntrySingletons<any>[];\n instances?: ProviderConfigEntryInstances<any>[];\n loadingFallback?: ReactNode;\n errorFallback?: ReactNode;\n}>;\n\nexport const Provider: FC<ProviderProps> = ({\n singletons,\n instances,\n loadingFallback = defaultLoadingFallback,\n errorFallback = defaultErrorFallback,\n children,\n}) => {\n const parentContainer = useContext(ContainerContext);\n const [container, setContainer] = useState<Container>();\n const [promises, setPromises] = useState<Promise<void>[]>([]);\n const [error, setError] = useState(false);\n\n useEffect(() => {\n const container = new Container();\n container.parent = parentContainer;\n setContainer(container);\n\n const handleError = (e: any) => {\n setError(true);\n // Rethrow asynchronously for global error handler\n setTimeout(() => {\n throw e;\n });\n };\n\n bindEntries(container, { singletons, instances });\n const promises = initializeStores(\n getStoreInstances(container, { singletons, instances }),\n handleError\n );\n setPromises(promises);\n\n return () => {\n const storeInstances = getStoreInstances(container, { singletons, instances });\n\n unbindEntries(container, { singletons, instances });\n disposeStores(storeInstances);\n setContainer(undefined);\n setPromises([]);\n };\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n if (!container) {\n return null;\n }\n\n const getContent = () => {\n if (error) {\n return errorFallback;\n }\n\n if (promises.length) {\n return (\n <Await promises={promises} fallback={loadingFallback}>\n {children}\n </Await>\n );\n }\n\n return children;\n };\n\n return <ContainerContext.Provider value={container}>{getContent()}</ContainerContext.Provider>;\n};\n"],"names":["Container","useContext","useEffect","useState","Await","ContainerContext","defaultErrorFallback","defaultLoadingFallback","isStore","isClassProviderConfigEntryUseClass","entry","Object","hasOwn","isValueProviderConfigEntry","isClassProviderConfigEntryToken","isProviderConfigEntryInheritable","getProvideTokenWithClass","provide","useClass","undefined","getStoreInstances","container","singletons","instances","reduce","out","isCurrentBound","push","get","bindEntry","checkInherit","inherit","isBound","bind","to","toDynamicValue","useValue","unbindEntry","unbind","bindEntries","map","forEach","binding","inSingletonScope","unbindEntries","initializeStores","stores","onError","promises","instance","promise","initialize","e","catch","disposeStores","dispose","Provider","loadingFallback","errorFallback","children","parentContainer","setContainer","setPromises","error","setError","parent","handleError","setTimeout","storeInstances","getContent","length","fallback","value"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/provider.tsx"],"sourcesContent":["import { Container } from 'inversify';\nimport { FC, PropsWithChildren, ReactNode, useContext, useEffect, useState } from 'react';\nimport { Await } from './await';\nimport { ContainerContext, Token } from './common';\nimport { dedupeEntries } from './dedupe-entries';\nimport {\n formatToken,\n getProvideTokenWithClass,\n isClassProviderConfigEntryToken,\n isClassProviderConfigEntryUseClass,\n isProviderConfigEntryInheritable,\n isValueProviderConfigEntry,\n ProviderConfigEntries,\n ProviderConfigEntry,\n} from './entry-helpers';\nimport { defaultErrorFallback, defaultLoadingFallback } from './fallbacks';\nimport { isStore, Store } from './store';\n\nfunction getStoreInstances(\n container: Container,\n { singletons = [], instances = [] }: ProviderConfigEntries\n): Store[] {\n return [...singletons, ...instances].reduce((out, entry) => {\n const [provide, useClass] = getProvideTokenWithClass(entry);\n\n if (provide && useClass && container.isCurrentBound(provide) && isStore(useClass)) {\n out.push(container.get(provide));\n }\n\n return out;\n }, [] as Store[]);\n}\n\nconst bindEntry =\n (container: Container, checkInherit: boolean) => (entry: ProviderConfigEntry<any>) => {\n if (\n checkInherit &&\n isProviderConfigEntryInheritable(entry) &&\n entry.inherit &&\n container.isBound(entry.provide)\n ) {\n return undefined;\n }\n\n if (isClassProviderConfigEntryUseClass(entry)) {\n return container.bind(entry.provide).to(entry.useClass);\n }\n\n if (isClassProviderConfigEntryToken(entry)) {\n return container.bind(entry.provide).to(entry.provide);\n }\n\n if (isValueProviderConfigEntry(entry)) {\n // using toDynamicValue to return BindingInSyntax\n return container.bind(entry.provide).toDynamicValue(() => entry.useValue);\n }\n\n return container.bind(entry).to(entry);\n };\n\nconst unbindEntry = (container: Container) => (entry: ProviderConfigEntry<any>) => {\n if (isProviderConfigEntryInheritable(entry) && !container.isCurrentBound(entry.provide)) {\n return;\n }\n if (\n isClassProviderConfigEntryUseClass(entry) ||\n isValueProviderConfigEntry(entry) ||\n isClassProviderConfigEntryToken(entry)\n ) {\n return container.unbind(entry.provide);\n }\n\n return container.unbind(entry);\n};\n\nfunction bindEntries(\n container: Container,\n { singletons = [], instances = [] }: ProviderConfigEntries\n) {\n singletons.map(bindEntry(container, true)).forEach(binding => {\n binding?.inSingletonScope();\n });\n instances.forEach(bindEntry(container, false));\n}\n\nfunction unbindEntries(\n container: Container,\n { singletons = [], instances = [] }: ProviderConfigEntries\n) {\n [...singletons, ...instances].forEach(unbindEntry(container));\n}\n\nfunction initializeStores(stores: Store[], onError: (error: any) => void) {\n const promises: Promise<void>[] = [];\n\n for (const instance of stores) {\n let promise;\n\n try {\n promise = instance.initialize?.();\n } catch (e: any) {\n onError(e);\n }\n\n if (promise && typeof promise.catch === 'function') {\n promises.push(promise.catch(onError));\n }\n }\n\n return promises;\n}\n\nfunction disposeStores(stores: Store[]) {\n for (const instance of stores) {\n instance.dispose?.();\n }\n}\n\nfunction formatDuplicatesMessage(duplicates: Token<any>[]): string {\n const names = duplicates.map(formatToken).join(', ');\n return `Provider: token listed more than once: ${names}. Remove the duplicate entries.`;\n}\n\nexport type ProviderProps = PropsWithChildren<\n ProviderConfigEntries & {\n loadingFallback?: ReactNode;\n errorFallback?: ReactNode;\n }\n>;\n\nexport const Provider: FC<ProviderProps> = ({\n singletons,\n instances,\n loadingFallback = defaultLoadingFallback,\n errorFallback = defaultErrorFallback,\n children,\n}) => {\n const parentContainer = useContext(ContainerContext);\n const [container, setContainer] = useState<Container>();\n const [promises, setPromises] = useState<Promise<void>[]>([]);\n const [error, setError] = useState(false);\n\n useEffect(() => {\n const container = new Container();\n container.parent = parentContainer;\n setContainer(container);\n\n const handleError = (e: any) => {\n setError(true);\n // Rethrow asynchronously for global error handler\n setTimeout(() => {\n throw e;\n });\n };\n\n const config = dedupeEntries({ singletons, instances });\n\n if (config.duplicates.length > 0) {\n const message = formatDuplicatesMessage(config.duplicates);\n if (process.env.NODE_ENV !== 'production') {\n handleError(new Error(message));\n return () => {\n setContainer(undefined);\n setPromises([]);\n };\n }\n // eslint-disable-next-line no-console\n console.warn(message);\n }\n\n bindEntries(container, config);\n const promises = initializeStores(getStoreInstances(container, config), handleError);\n setPromises(promises);\n\n return () => {\n const storeInstances = getStoreInstances(container, config);\n\n unbindEntries(container, config);\n disposeStores(storeInstances);\n setContainer(undefined);\n setPromises([]);\n };\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n if (!container) {\n return null;\n }\n\n const getContent = () => {\n if (error) {\n return errorFallback;\n }\n\n if (promises.length) {\n return (\n <Await promises={promises} fallback={loadingFallback}>\n {children}\n </Await>\n );\n }\n\n return children;\n };\n\n return <ContainerContext.Provider value={container}>{getContent()}</ContainerContext.Provider>;\n};\n"],"names":["Container","useContext","useEffect","useState","Await","ContainerContext","dedupeEntries","formatToken","getProvideTokenWithClass","isClassProviderConfigEntryToken","isClassProviderConfigEntryUseClass","isProviderConfigEntryInheritable","isValueProviderConfigEntry","defaultErrorFallback","defaultLoadingFallback","isStore","getStoreInstances","container","singletons","instances","reduce","out","entry","provide","useClass","isCurrentBound","push","get","bindEntry","checkInherit","inherit","isBound","undefined","bind","to","toDynamicValue","useValue","unbindEntry","unbind","bindEntries","map","forEach","binding","inSingletonScope","unbindEntries","initializeStores","stores","onError","promises","instance","promise","initialize","e","catch","disposeStores","dispose","formatDuplicatesMessage","duplicates","names","join","Provider","loadingFallback","errorFallback","children","parentContainer","setContainer","setPromises","error","setError","parent","handleError","setTimeout","config","length","message","process","env","NODE_ENV","Error","console","warn","storeInstances","getContent","fallback","value"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@servicetitan/react-ioc",
|
|
3
|
-
"version": "36.
|
|
3
|
+
"version": "36.3.1",
|
|
4
4
|
"description": "Implementation of InversifyJS for React applications using Context API",
|
|
5
5
|
"homepage": "https://docs.st.dev/docs/frontend/uikit/react-ioc",
|
|
6
6
|
"repository": {
|
|
@@ -35,5 +35,5 @@
|
|
|
35
35
|
"cli": {
|
|
36
36
|
"webpack": false
|
|
37
37
|
},
|
|
38
|
-
"gitHead": "
|
|
38
|
+
"gitHead": "93a049ba1e5cb737afb7bc95c06020736bc61a38"
|
|
39
39
|
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { symbolToken } from '../common';
|
|
2
|
+
import { dedupeEntries } from '../dedupe-entries';
|
|
3
|
+
|
|
4
|
+
class StoreA {}
|
|
5
|
+
class StoreB {}
|
|
6
|
+
class StoreC {}
|
|
7
|
+
|
|
8
|
+
describe('[react-ioc] dedupeEntries', () => {
|
|
9
|
+
let singletons: any;
|
|
10
|
+
let instances: any;
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
singletons = undefined;
|
|
14
|
+
instances = undefined;
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const subject = () => dedupeEntries({ singletons, instances });
|
|
18
|
+
|
|
19
|
+
describe('with empty input', () => {
|
|
20
|
+
test('reports no duplicates', () => {
|
|
21
|
+
expect(subject().duplicates).toEqual([]);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('returns empty singletons', () => {
|
|
25
|
+
expect(subject().singletons).toEqual([]);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('returns empty instances', () => {
|
|
29
|
+
expect(subject().instances).toEqual([]);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe('with all distinct tokens', () => {
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
singletons = [StoreA, { provide: StoreB }];
|
|
36
|
+
instances = [StoreC];
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('reports no duplicates', () => {
|
|
40
|
+
expect(subject().duplicates).toEqual([]);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('returns singletons unchanged', () => {
|
|
44
|
+
expect(subject().singletons).toEqual(singletons);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('returns instances unchanged', () => {
|
|
48
|
+
expect(subject().instances).toEqual(instances);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
function itReturnsDuplicatedToken() {
|
|
53
|
+
test('returns the duplicate token', () => {
|
|
54
|
+
const token = singletons[0].provide ?? singletons[0];
|
|
55
|
+
expect(subject().duplicates).toEqual([token]);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function itReturnsDedupedSingletons() {
|
|
60
|
+
test('returns deduped singletons', () => {
|
|
61
|
+
expect(subject().singletons).toEqual(singletons?.slice(0, 1));
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
describe('with duplicate class', () => {
|
|
66
|
+
beforeEach(() => (singletons = [StoreA, StoreA]));
|
|
67
|
+
|
|
68
|
+
itReturnsDuplicatedToken();
|
|
69
|
+
itReturnsDedupedSingletons();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe('with duplicate class and provide entry', () => {
|
|
73
|
+
beforeEach(() => {
|
|
74
|
+
singletons = [StoreA, { provide: StoreA }];
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
itReturnsDuplicatedToken();
|
|
78
|
+
itReturnsDedupedSingletons();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe('with duplicate provide entries', () => {
|
|
82
|
+
beforeEach(() => {
|
|
83
|
+
singletons = [
|
|
84
|
+
{ provide: StoreA, useClass: StoreB },
|
|
85
|
+
{ provide: StoreA, useClass: StoreC },
|
|
86
|
+
];
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
itReturnsDuplicatedToken();
|
|
90
|
+
itReturnsDedupedSingletons();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe('with duplicate useValue entries', () => {
|
|
94
|
+
const valueToken = symbolToken<{ kind: string }>('test/value');
|
|
95
|
+
|
|
96
|
+
beforeEach(() => {
|
|
97
|
+
singletons = [
|
|
98
|
+
{ provide: valueToken, useValue: { kind: 'first' } },
|
|
99
|
+
{ provide: valueToken, useValue: { kind: 'second' } },
|
|
100
|
+
];
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
itReturnsDuplicatedToken();
|
|
104
|
+
itReturnsDedupedSingletons();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
describe('with the same token in singletons and instances', () => {
|
|
108
|
+
beforeEach(() => {
|
|
109
|
+
singletons = [StoreA];
|
|
110
|
+
instances = [StoreA];
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
itReturnsDuplicatedToken();
|
|
114
|
+
|
|
115
|
+
test('keeps singletons entry', () => {
|
|
116
|
+
expect(subject().singletons).toEqual([singletons[0]]);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test('drops instances the entry', () => {
|
|
120
|
+
expect(subject().instances).toEqual([]);
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
describe('with multiple duplicate tokens', () => {
|
|
125
|
+
beforeEach(() => (singletons = [StoreA, StoreA, { provide: StoreB }, StoreB]));
|
|
126
|
+
|
|
127
|
+
test('returns duplicated tokens', () => {
|
|
128
|
+
expect(subject().duplicates).toEqual([singletons[1], singletons[3]]);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test('returns deduped singletons', () => {
|
|
132
|
+
expect(subject().singletons).toEqual([singletons[0], singletons[2]]);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
describe('when a token appears >2 times', () => {
|
|
137
|
+
beforeEach(() => (singletons = [StoreA, StoreA, StoreA]));
|
|
138
|
+
|
|
139
|
+
test('returns duplicated token once', () => {
|
|
140
|
+
expect(subject().duplicates).toEqual([singletons[0]]);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
});
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { symbolToken } from '../common';
|
|
2
|
+
import {
|
|
3
|
+
formatToken,
|
|
4
|
+
getProvideToken,
|
|
5
|
+
getProvideTokenWithClass,
|
|
6
|
+
isClassProviderConfigEntryToken,
|
|
7
|
+
isClassProviderConfigEntryUseClass,
|
|
8
|
+
isProviderConfigEntryInheritable,
|
|
9
|
+
isValueProviderConfigEntry,
|
|
10
|
+
} from '../entry-helpers';
|
|
11
|
+
|
|
12
|
+
class StoreA {}
|
|
13
|
+
class StoreB {}
|
|
14
|
+
|
|
15
|
+
function itReturns(subject: () => boolean, value: boolean) {
|
|
16
|
+
test(`returns ${value}`, () => {
|
|
17
|
+
expect(subject()).toBe(value);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe('[react-ioc] formatToken', () => {
|
|
22
|
+
let token: any;
|
|
23
|
+
|
|
24
|
+
const subject = () => formatToken(token);
|
|
25
|
+
|
|
26
|
+
describe('with a named class', () => {
|
|
27
|
+
beforeEach(() => (token = StoreA));
|
|
28
|
+
|
|
29
|
+
test('returns class name', () => {
|
|
30
|
+
expect(subject()).toBe(token.name);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe('with unnamed class', () => {
|
|
35
|
+
beforeEach(() => (token = (() => class {})()));
|
|
36
|
+
|
|
37
|
+
test('returns (anonymous)', () => {
|
|
38
|
+
expect(subject()).toBe('(anonymous)');
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe('with a symbol token', () => {
|
|
43
|
+
beforeEach(() => (token = symbolToken('test/symbol-token')));
|
|
44
|
+
|
|
45
|
+
test('returns symbol description', () => {
|
|
46
|
+
expect(subject()).toEqual(token.description);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('when symbol has no description', () => {
|
|
50
|
+
beforeEach(() => (token = Symbol()));
|
|
51
|
+
|
|
52
|
+
test('returns token.toString()', () => {
|
|
53
|
+
expect(subject()).toEqual(token.toString());
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe('[react-ioc] getProvideToken', () => {
|
|
60
|
+
let entry: any;
|
|
61
|
+
|
|
62
|
+
const subject = () => getProvideToken(entry);
|
|
63
|
+
|
|
64
|
+
describe('with a bare class entry', () => {
|
|
65
|
+
beforeEach(() => (entry = StoreA));
|
|
66
|
+
|
|
67
|
+
test('returns the class', () => {
|
|
68
|
+
expect(subject()).toBe(entry);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe('with a provide entry', () => {
|
|
73
|
+
beforeEach(() => (entry = { provide: StoreA }));
|
|
74
|
+
|
|
75
|
+
function itReturnsEntryProvide() {
|
|
76
|
+
test('returns entry.provide', () => {
|
|
77
|
+
expect(subject()).toBe(entry.provide);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
itReturnsEntryProvide();
|
|
82
|
+
|
|
83
|
+
describe('with useClass', () => {
|
|
84
|
+
beforeEach(() => (entry.useClass = StoreB));
|
|
85
|
+
|
|
86
|
+
itReturnsEntryProvide();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
describe('with useValue', () => {
|
|
90
|
+
beforeEach(() => (entry.useValue = { kind: 'first' }));
|
|
91
|
+
|
|
92
|
+
itReturnsEntryProvide();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe('with inherit: true', () => {
|
|
96
|
+
beforeEach(() => (entry.inherit = true));
|
|
97
|
+
|
|
98
|
+
itReturnsEntryProvide();
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe('[react-ioc] getProvideTokenWithClass', () => {
|
|
104
|
+
let entry: any;
|
|
105
|
+
|
|
106
|
+
const subject = () => getProvideTokenWithClass(entry);
|
|
107
|
+
|
|
108
|
+
describe('with a bare class entry', () => {
|
|
109
|
+
beforeEach(() => (entry = StoreA));
|
|
110
|
+
|
|
111
|
+
test('returns [class, class]', () => {
|
|
112
|
+
expect(subject()).toEqual([entry, entry]);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
describe('with a provide entry', () => {
|
|
117
|
+
beforeEach(() => (entry = { provide: StoreA }));
|
|
118
|
+
|
|
119
|
+
test('returns [entry.provide, entry.provide]', () => {
|
|
120
|
+
expect(subject()).toEqual([entry.provide, entry.provide]);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
describe('with useClass', () => {
|
|
124
|
+
beforeEach(() => (entry.useClass = StoreB));
|
|
125
|
+
|
|
126
|
+
test('returns [entry.provide, entry.useClass]', () => {
|
|
127
|
+
expect(subject()).toEqual([entry.provide, entry.useClass]);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
describe('with useValue', () => {
|
|
132
|
+
beforeEach(() => (entry.useValue = { kind: 'first' }));
|
|
133
|
+
|
|
134
|
+
test('returns [undefined, undefined]', () => {
|
|
135
|
+
expect(subject()).toEqual([undefined, undefined]);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
describe('[react-ioc] isClassProviderConfigEntryToken', () => {
|
|
142
|
+
let entry: any;
|
|
143
|
+
|
|
144
|
+
const subject = () => isClassProviderConfigEntryToken(entry);
|
|
145
|
+
|
|
146
|
+
describe('with a bare class entry', () => {
|
|
147
|
+
beforeEach(() => (entry = StoreA));
|
|
148
|
+
|
|
149
|
+
itReturns(subject, false);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
describe('with a provide entry', () => {
|
|
153
|
+
beforeEach(() => (entry = { provide: StoreA }));
|
|
154
|
+
|
|
155
|
+
itReturns(subject, true);
|
|
156
|
+
|
|
157
|
+
describe('with useClass', () => {
|
|
158
|
+
beforeEach(() => (entry.useClass = StoreB));
|
|
159
|
+
|
|
160
|
+
itReturns(subject, false);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
describe('with useValue', () => {
|
|
164
|
+
beforeEach(() => (entry.useValue = { kind: 'first' }));
|
|
165
|
+
|
|
166
|
+
itReturns(subject, false);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
describe('[react-ioc] isClassProviderConfigEntryUseClass', () => {
|
|
172
|
+
let entry: any;
|
|
173
|
+
|
|
174
|
+
const subject = () => isClassProviderConfigEntryUseClass(entry);
|
|
175
|
+
|
|
176
|
+
describe('with a bare class entry', () => {
|
|
177
|
+
beforeEach(() => (entry = StoreA));
|
|
178
|
+
|
|
179
|
+
itReturns(subject, false);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
describe('with a provide-only entry', () => {
|
|
183
|
+
beforeEach(() => (entry = { provide: StoreA }));
|
|
184
|
+
|
|
185
|
+
itReturns(subject, false);
|
|
186
|
+
|
|
187
|
+
describe('with a useClass entry', () => {
|
|
188
|
+
beforeEach(() => (entry.useClass = StoreB));
|
|
189
|
+
|
|
190
|
+
itReturns(subject, true);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
describe('[react-ioc] isProviderConfigEntryInheritable', () => {
|
|
196
|
+
let entry: any;
|
|
197
|
+
|
|
198
|
+
const subject = () => isProviderConfigEntryInheritable(entry);
|
|
199
|
+
|
|
200
|
+
describe('with a bare class entry', () => {
|
|
201
|
+
beforeEach(() => (entry = StoreA));
|
|
202
|
+
|
|
203
|
+
itReturns(subject, false);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
describe('with a provide entry', () => {
|
|
207
|
+
beforeEach(() => (entry = { provide: StoreA }));
|
|
208
|
+
|
|
209
|
+
itReturns(subject, true);
|
|
210
|
+
|
|
211
|
+
describe('with useClass', () => {
|
|
212
|
+
beforeEach(() => (entry.useClass = StoreB));
|
|
213
|
+
|
|
214
|
+
itReturns(subject, true);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
describe('with useValue', () => {
|
|
218
|
+
beforeEach(() => (entry.useValue = { kind: 'first' }));
|
|
219
|
+
|
|
220
|
+
itReturns(subject, true);
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
describe('[react-ioc] isValueProviderConfigEntry', () => {
|
|
226
|
+
let entry: any;
|
|
227
|
+
|
|
228
|
+
const subject = () => isValueProviderConfigEntry(entry);
|
|
229
|
+
|
|
230
|
+
describe('with a bare class entry', () => {
|
|
231
|
+
beforeEach(() => (entry = StoreA));
|
|
232
|
+
|
|
233
|
+
itReturns(subject, false);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
describe('with a provide entry', () => {
|
|
237
|
+
beforeEach(() => (entry = { provide: StoreA }));
|
|
238
|
+
|
|
239
|
+
itReturns(subject, false);
|
|
240
|
+
|
|
241
|
+
describe('with a useValue entry', () => {
|
|
242
|
+
beforeEach(() => (entry.useValue = { kind: 'first' }));
|
|
243
|
+
|
|
244
|
+
itReturns(subject, true);
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
});
|
|
@@ -386,4 +386,77 @@ describe('[react-ioc] Provider', () => {
|
|
|
386
386
|
expect(stat.testDispose).not.toHaveBeenCalled();
|
|
387
387
|
});
|
|
388
388
|
});
|
|
389
|
+
|
|
390
|
+
describe('duplicates handling', () => {
|
|
391
|
+
const originalNodeEnv = process.env.NODE_ENV;
|
|
392
|
+
const childContent = 'foo';
|
|
393
|
+
const errorFallback = 'Oops!';
|
|
394
|
+
let singletons: ProviderProps['singletons'];
|
|
395
|
+
let instances: ProviderProps['instances'];
|
|
396
|
+
let warnSpy: jest.SpyInstance;
|
|
397
|
+
|
|
398
|
+
beforeAll(() => jest.useFakeTimers());
|
|
399
|
+
afterAll(() => jest.useRealTimers());
|
|
400
|
+
|
|
401
|
+
beforeEach(() => {
|
|
402
|
+
jest.clearAllMocks();
|
|
403
|
+
warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
404
|
+
singletons = undefined;
|
|
405
|
+
instances = undefined;
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
afterEach(() => {
|
|
409
|
+
process.env.NODE_ENV = originalNodeEnv;
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
const subject = () =>
|
|
413
|
+
render(
|
|
414
|
+
<Provider
|
|
415
|
+
singletons={singletons}
|
|
416
|
+
instances={instances}
|
|
417
|
+
errorFallback={<div>{errorFallback}</div>}
|
|
418
|
+
>
|
|
419
|
+
<div>{childContent}</div>
|
|
420
|
+
</Provider>
|
|
421
|
+
);
|
|
422
|
+
|
|
423
|
+
describe('with a duplicate singleton', () => {
|
|
424
|
+
beforeEach(() => {
|
|
425
|
+
singletons = [StoreSimple, StoreSimple];
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
test('renders error fallback', async () => {
|
|
429
|
+
subject();
|
|
430
|
+
|
|
431
|
+
await jest.runAllTimersAsync().catch(() => {});
|
|
432
|
+
expect(screen.getByText(errorFallback)).toBeInTheDocument();
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
test('throws error', async () => {
|
|
436
|
+
subject();
|
|
437
|
+
|
|
438
|
+
await expect(() => jest.runAllTimersAsync()).rejects.toThrow(
|
|
439
|
+
/listed more than once/
|
|
440
|
+
);
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
describe('when in production', () => {
|
|
444
|
+
beforeEach(() => (process.env.NODE_ENV = 'production'));
|
|
445
|
+
|
|
446
|
+
test('logs warning', () => {
|
|
447
|
+
subject();
|
|
448
|
+
|
|
449
|
+
expect(warnSpy).toHaveBeenCalledWith(
|
|
450
|
+
expect.stringMatching(/listed more than once/)
|
|
451
|
+
);
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
test('renders children', () => {
|
|
455
|
+
subject();
|
|
456
|
+
|
|
457
|
+
expect(screen.getByText(childContent)).toBeInTheDocument();
|
|
458
|
+
});
|
|
459
|
+
});
|
|
460
|
+
});
|
|
461
|
+
});
|
|
389
462
|
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Token } from './common';
|
|
2
|
+
import {
|
|
3
|
+
getProvideToken,
|
|
4
|
+
ProviderConfigEntries,
|
|
5
|
+
ProviderConfigEntry,
|
|
6
|
+
ProviderConfigEntryInstances,
|
|
7
|
+
ProviderConfigEntrySingletons,
|
|
8
|
+
} from './entry-helpers';
|
|
9
|
+
|
|
10
|
+
export interface DedupeEntriesResult {
|
|
11
|
+
duplicates: Token<any>[];
|
|
12
|
+
singletons: ProviderConfigEntrySingletons<any>[];
|
|
13
|
+
instances: ProviderConfigEntryInstances<any>[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function dedupeEntries({
|
|
17
|
+
singletons = [],
|
|
18
|
+
instances = [],
|
|
19
|
+
}: ProviderConfigEntries): DedupeEntriesResult {
|
|
20
|
+
const seen = new Set<Token<any>>();
|
|
21
|
+
const duplicates: Token<any>[] = [];
|
|
22
|
+
const dedupedSingletons: ProviderConfigEntrySingletons<any>[] = [];
|
|
23
|
+
const dedupedInstances: ProviderConfigEntryInstances<any>[] = [];
|
|
24
|
+
|
|
25
|
+
function isDuplicate(entry: ProviderConfigEntry<any>): boolean {
|
|
26
|
+
const token = getProvideToken(entry);
|
|
27
|
+
if (!seen.has(token)) {
|
|
28
|
+
seen.add(token);
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
if (!duplicates.includes(token)) {
|
|
32
|
+
duplicates.push(token);
|
|
33
|
+
}
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
for (const entry of singletons) {
|
|
38
|
+
if (!isDuplicate(entry)) {
|
|
39
|
+
dedupedSingletons.push(entry);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
for (const entry of instances) {
|
|
44
|
+
if (!isDuplicate(entry)) {
|
|
45
|
+
dedupedInstances.push(entry);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return { duplicates, singletons: dedupedSingletons, instances: dedupedInstances };
|
|
50
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { interfaces } from 'inversify';
|
|
2
|
+
import { SymbolToken, Token } from './common';
|
|
3
|
+
|
|
4
|
+
export type ProviderConfigEntrySingletons<T> =
|
|
5
|
+
| ClassProviderConfigEntry<T>
|
|
6
|
+
| ValueProviderConfigEntry<T>;
|
|
7
|
+
export type ProviderConfigEntryInstances<T> = ClassProviderConfigEntryNoInherit<T>;
|
|
8
|
+
export type ProviderConfigEntry<T> =
|
|
9
|
+
| ProviderConfigEntrySingletons<T>
|
|
10
|
+
| ProviderConfigEntryInstances<T>;
|
|
11
|
+
|
|
12
|
+
export interface ProviderConfigEntries {
|
|
13
|
+
singletons?: ProviderConfigEntrySingletons<any>[];
|
|
14
|
+
instances?: ProviderConfigEntryInstances<any>[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type ClassProviderConfigEntry<T> =
|
|
18
|
+
| interfaces.Newable<T>
|
|
19
|
+
| ClassProviderConfigEntryUseClass<T>
|
|
20
|
+
| ClassProviderConfigEntryToken<T>;
|
|
21
|
+
|
|
22
|
+
export type ClassProviderConfigEntryNoInherit<T> =
|
|
23
|
+
| interfaces.Newable<T>
|
|
24
|
+
| Omit<ClassProviderConfigEntryUseClass<T>, 'inherit'>;
|
|
25
|
+
|
|
26
|
+
export interface ClassProviderConfigEntryUseClass<T> {
|
|
27
|
+
provide: Token<T>;
|
|
28
|
+
useClass: interfaces.Newable<T>;
|
|
29
|
+
inherit?: true;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface ClassProviderConfigEntryToken<T> {
|
|
33
|
+
provide: interfaces.Newable<T>;
|
|
34
|
+
inherit?: true;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface ValueProviderConfigEntry<T> {
|
|
38
|
+
provide: SymbolToken<T> | Function;
|
|
39
|
+
useValue: T;
|
|
40
|
+
inherit?: true;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function formatToken(token: Token<unknown>): string {
|
|
44
|
+
if (typeof token === 'symbol') {
|
|
45
|
+
return token.description ?? token.toString();
|
|
46
|
+
}
|
|
47
|
+
const name = (token as Function).name;
|
|
48
|
+
return name && name.length > 0 ? name : '(anonymous)';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function getProvideToken<T>(entry: ProviderConfigEntry<T>): Token<T> {
|
|
52
|
+
if (
|
|
53
|
+
isClassProviderConfigEntryUseClass(entry) ||
|
|
54
|
+
isClassProviderConfigEntryToken(entry) ||
|
|
55
|
+
isValueProviderConfigEntry(entry)
|
|
56
|
+
) {
|
|
57
|
+
return entry.provide;
|
|
58
|
+
}
|
|
59
|
+
return entry;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function getProvideTokenWithClass<T>(
|
|
63
|
+
entry: ProviderConfigEntry<T>
|
|
64
|
+
): [Token<T>, interfaces.Newable<T>] | [undefined, undefined] {
|
|
65
|
+
if (isClassProviderConfigEntryUseClass(entry)) {
|
|
66
|
+
return [entry.provide, entry.useClass];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (isClassProviderConfigEntryToken(entry)) {
|
|
70
|
+
return [entry.provide, entry.provide];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (isValueProviderConfigEntry(entry)) {
|
|
74
|
+
return [undefined, undefined];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return [entry, entry];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function isClassProviderConfigEntryToken<T>(
|
|
81
|
+
entry: ProviderConfigEntry<T>
|
|
82
|
+
): entry is Omit<ClassProviderConfigEntryToken<T>, 'inherit'> {
|
|
83
|
+
return (
|
|
84
|
+
Object.hasOwn(entry, 'provide') &&
|
|
85
|
+
!Object.hasOwn(entry, 'useClass') &&
|
|
86
|
+
!Object.hasOwn(entry, 'useValue')
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function isClassProviderConfigEntryUseClass<T>(
|
|
91
|
+
entry: ProviderConfigEntry<T>
|
|
92
|
+
): entry is Omit<ClassProviderConfigEntryUseClass<T>, 'inherit'> {
|
|
93
|
+
return Object.hasOwn(entry, 'provide') && Object.hasOwn(entry, 'useClass');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function isProviderConfigEntryInheritable<T>(
|
|
97
|
+
entry: ProviderConfigEntry<T>
|
|
98
|
+
): entry is
|
|
99
|
+
| ClassProviderConfigEntryUseClass<T>
|
|
100
|
+
| ClassProviderConfigEntryToken<T>
|
|
101
|
+
| ValueProviderConfigEntry<T> {
|
|
102
|
+
return (
|
|
103
|
+
isClassProviderConfigEntryUseClass(entry) ||
|
|
104
|
+
isClassProviderConfigEntryToken(entry) ||
|
|
105
|
+
isValueProviderConfigEntry(entry)
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function isValueProviderConfigEntry<T>(
|
|
110
|
+
entry: ProviderConfigEntry<T>
|
|
111
|
+
): entry is Omit<ValueProviderConfigEntry<T>, 'inherit'> {
|
|
112
|
+
return Object.hasOwn(entry, 'provide') && Object.hasOwn(entry, 'useValue');
|
|
113
|
+
}
|
package/src/provide.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ComponentType, ReactInstance, ReactNode } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { ProviderConfigEntries } from './entry-helpers';
|
|
3
|
+
import { Provider } from './provider';
|
|
3
4
|
|
|
4
5
|
export interface WrappedComponent<P> {
|
|
5
6
|
wrappedComponent: ComponentType<P>;
|
|
@@ -12,10 +13,7 @@ export interface FallbackOptions {
|
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
export type ProvideDecorator = (
|
|
15
|
-
stores:
|
|
16
|
-
singletons?: ProviderConfigEntrySingletons<any>[];
|
|
17
|
-
instances?: ProviderConfigEntryInstances<any>[];
|
|
18
|
-
},
|
|
16
|
+
stores: ProviderConfigEntries,
|
|
19
17
|
options?: ReactNode | FallbackOptions
|
|
20
18
|
) => <T extends ComponentType<any>>(target: T) => T & WrappedComponent<T>;
|
|
21
19
|
|
package/src/provider.tsx
CHANGED
|
@@ -1,100 +1,24 @@
|
|
|
1
|
-
import { Container
|
|
1
|
+
import { Container } from 'inversify';
|
|
2
2
|
import { FC, PropsWithChildren, ReactNode, useContext, useEffect, useState } from 'react';
|
|
3
3
|
import { Await } from './await';
|
|
4
|
-
import { ContainerContext,
|
|
4
|
+
import { ContainerContext, Token } from './common';
|
|
5
|
+
import { dedupeEntries } from './dedupe-entries';
|
|
6
|
+
import {
|
|
7
|
+
formatToken,
|
|
8
|
+
getProvideTokenWithClass,
|
|
9
|
+
isClassProviderConfigEntryToken,
|
|
10
|
+
isClassProviderConfigEntryUseClass,
|
|
11
|
+
isProviderConfigEntryInheritable,
|
|
12
|
+
isValueProviderConfigEntry,
|
|
13
|
+
ProviderConfigEntries,
|
|
14
|
+
ProviderConfigEntry,
|
|
15
|
+
} from './entry-helpers';
|
|
5
16
|
import { defaultErrorFallback, defaultLoadingFallback } from './fallbacks';
|
|
6
17
|
import { isStore, Store } from './store';
|
|
7
18
|
|
|
8
|
-
export type ProviderConfigEntrySingletons<T> =
|
|
9
|
-
| ClassProviderConfigEntry<T>
|
|
10
|
-
| ValueProviderConfigEntry<T>;
|
|
11
|
-
export type ProviderConfigEntryInstances<T> = ClassProviderConfigEntryNoInherit<T>;
|
|
12
|
-
export type ProviderConfigEntry<T> =
|
|
13
|
-
| ProviderConfigEntrySingletons<T>
|
|
14
|
-
| ProviderConfigEntryInstances<T>;
|
|
15
|
-
|
|
16
|
-
type ClassProviderConfigEntry<T> =
|
|
17
|
-
| interfaces.Newable<T>
|
|
18
|
-
| ClassProviderConfigEntryUseClass<T>
|
|
19
|
-
| ClassProviderConfigEntryToken<T>;
|
|
20
|
-
|
|
21
|
-
type ClassProviderConfigEntryNoInherit<T> =
|
|
22
|
-
| interfaces.Newable<T>
|
|
23
|
-
| Omit<ClassProviderConfigEntryUseClass<T>, 'inherit'>;
|
|
24
|
-
|
|
25
|
-
interface ClassProviderConfigEntryUseClass<T> {
|
|
26
|
-
provide: Token<T>;
|
|
27
|
-
useClass: interfaces.Newable<T>;
|
|
28
|
-
inherit?: true;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
interface ClassProviderConfigEntryToken<T> {
|
|
32
|
-
provide: interfaces.Newable<T>;
|
|
33
|
-
inherit?: true;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
interface ValueProviderConfigEntry<T> {
|
|
37
|
-
provide: SymbolToken<T> | Function;
|
|
38
|
-
useValue: T;
|
|
39
|
-
inherit?: true;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function isClassProviderConfigEntryUseClass<T>(
|
|
43
|
-
entry: ProviderConfigEntry<T>
|
|
44
|
-
): entry is Omit<ClassProviderConfigEntryUseClass<T>, 'inherit'> {
|
|
45
|
-
return Object.hasOwn(entry, 'provide') && Object.hasOwn(entry, 'useClass');
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function isValueProviderConfigEntry<T>(
|
|
49
|
-
entry: ProviderConfigEntry<T>
|
|
50
|
-
): entry is Omit<ValueProviderConfigEntry<T>, 'inherit'> {
|
|
51
|
-
return Object.hasOwn(entry, 'provide') && Object.hasOwn(entry, 'useValue');
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function isClassProviderConfigEntryToken<T>(
|
|
55
|
-
entry: ProviderConfigEntry<T>
|
|
56
|
-
): entry is Omit<ClassProviderConfigEntryToken<T>, 'inherit'> {
|
|
57
|
-
return (
|
|
58
|
-
Object.hasOwn(entry, 'provide') &&
|
|
59
|
-
!Object.hasOwn(entry, 'useClass') &&
|
|
60
|
-
!Object.hasOwn(entry, 'useValue')
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function isProviderConfigEntryInheritable<T>(
|
|
65
|
-
entry: ProviderConfigEntry<T>
|
|
66
|
-
): entry is
|
|
67
|
-
| ClassProviderConfigEntryUseClass<T>
|
|
68
|
-
| ClassProviderConfigEntryToken<T>
|
|
69
|
-
| ValueProviderConfigEntry<T> {
|
|
70
|
-
return (
|
|
71
|
-
isClassProviderConfigEntryUseClass(entry) ||
|
|
72
|
-
isClassProviderConfigEntryToken(entry) ||
|
|
73
|
-
isValueProviderConfigEntry(entry)
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function getProvideTokenWithClass<T>(
|
|
78
|
-
entry: ProviderConfigEntry<T>
|
|
79
|
-
): [Token<T>, interfaces.Newable<T>] | [undefined, undefined] {
|
|
80
|
-
if (isClassProviderConfigEntryUseClass(entry)) {
|
|
81
|
-
return [entry.provide, entry.useClass];
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (isClassProviderConfigEntryToken(entry)) {
|
|
85
|
-
return [entry.provide, entry.provide];
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (isValueProviderConfigEntry(entry)) {
|
|
89
|
-
return [undefined, undefined];
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return [entry, entry];
|
|
93
|
-
}
|
|
94
|
-
|
|
95
19
|
function getStoreInstances(
|
|
96
20
|
container: Container,
|
|
97
|
-
{ singletons = [], instances = [] }:
|
|
21
|
+
{ singletons = [], instances = [] }: ProviderConfigEntries
|
|
98
22
|
): Store[] {
|
|
99
23
|
return [...singletons, ...instances].reduce((out, entry) => {
|
|
100
24
|
const [provide, useClass] = getProvideTokenWithClass(entry);
|
|
@@ -151,7 +75,7 @@ const unbindEntry = (container: Container) => (entry: ProviderConfigEntry<any>)
|
|
|
151
75
|
|
|
152
76
|
function bindEntries(
|
|
153
77
|
container: Container,
|
|
154
|
-
{ singletons = [], instances = [] }:
|
|
78
|
+
{ singletons = [], instances = [] }: ProviderConfigEntries
|
|
155
79
|
) {
|
|
156
80
|
singletons.map(bindEntry(container, true)).forEach(binding => {
|
|
157
81
|
binding?.inSingletonScope();
|
|
@@ -161,7 +85,7 @@ function bindEntries(
|
|
|
161
85
|
|
|
162
86
|
function unbindEntries(
|
|
163
87
|
container: Container,
|
|
164
|
-
{ singletons = [], instances = [] }:
|
|
88
|
+
{ singletons = [], instances = [] }: ProviderConfigEntries
|
|
165
89
|
) {
|
|
166
90
|
[...singletons, ...instances].forEach(unbindEntry(container));
|
|
167
91
|
}
|
|
@@ -192,12 +116,17 @@ function disposeStores(stores: Store[]) {
|
|
|
192
116
|
}
|
|
193
117
|
}
|
|
194
118
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
119
|
+
function formatDuplicatesMessage(duplicates: Token<any>[]): string {
|
|
120
|
+
const names = duplicates.map(formatToken).join(', ');
|
|
121
|
+
return `Provider: token listed more than once: ${names}. Remove the duplicate entries.`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export type ProviderProps = PropsWithChildren<
|
|
125
|
+
ProviderConfigEntries & {
|
|
126
|
+
loadingFallback?: ReactNode;
|
|
127
|
+
errorFallback?: ReactNode;
|
|
128
|
+
}
|
|
129
|
+
>;
|
|
201
130
|
|
|
202
131
|
export const Provider: FC<ProviderProps> = ({
|
|
203
132
|
singletons,
|
|
@@ -224,17 +153,29 @@ export const Provider: FC<ProviderProps> = ({
|
|
|
224
153
|
});
|
|
225
154
|
};
|
|
226
155
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
156
|
+
const config = dedupeEntries({ singletons, instances });
|
|
157
|
+
|
|
158
|
+
if (config.duplicates.length > 0) {
|
|
159
|
+
const message = formatDuplicatesMessage(config.duplicates);
|
|
160
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
161
|
+
handleError(new Error(message));
|
|
162
|
+
return () => {
|
|
163
|
+
setContainer(undefined);
|
|
164
|
+
setPromises([]);
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
// eslint-disable-next-line no-console
|
|
168
|
+
console.warn(message);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
bindEntries(container, config);
|
|
172
|
+
const promises = initializeStores(getStoreInstances(container, config), handleError);
|
|
232
173
|
setPromises(promises);
|
|
233
174
|
|
|
234
175
|
return () => {
|
|
235
|
-
const storeInstances = getStoreInstances(container,
|
|
176
|
+
const storeInstances = getStoreInstances(container, config);
|
|
236
177
|
|
|
237
|
-
unbindEntries(container,
|
|
178
|
+
unbindEntries(container, config);
|
|
238
179
|
disposeStores(storeInstances);
|
|
239
180
|
setContainer(undefined);
|
|
240
181
|
setPromises([]);
|