@servicetitan/react-ioc 32.0.1 → 32.1.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/provider.js +1 -1
- package/dist/provider.js.map +1 -1
- package/package.json +3 -4
- package/src/__tests__/provider.test.tsx +26 -1
- package/src/provider.tsx +1 -1
package/dist/provider.js
CHANGED
|
@@ -70,7 +70,7 @@ const bindEntry = (container, checkInherit)=>(entry)=>{
|
|
|
70
70
|
return container.bind(entry).to(entry);
|
|
71
71
|
};
|
|
72
72
|
const unbindEntry = (container)=>(entry)=>{
|
|
73
|
-
if (isProviderConfigEntryInheritable(entry) && !container.
|
|
73
|
+
if (isProviderConfigEntryInheritable(entry) && !container.isCurrentBound(entry.provide)) {
|
|
74
74
|
return;
|
|
75
75
|
}
|
|
76
76
|
if (isClassProviderConfigEntryUseClass(entry) || isValueProviderConfigEntry(entry) || isClassProviderConfigEntryToken(entry)) {
|
package/dist/provider.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/provider.tsx"],"sourcesContent":["import { FC, PropsWithChildren, ReactNode, useState, useContext, useEffect } from 'react';\n\nimport { Container, interfaces } from 'inversify';\n\nimport { Await } from './await';\nimport { ContainerContext, Token, SymbolToken } 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.isBound(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":["useState","useContext","useEffect","Container","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 { FC, PropsWithChildren, ReactNode, useState, useContext, useEffect } from 'react';\n\nimport { Container, interfaces } from 'inversify';\n\nimport { Await } from './await';\nimport { ContainerContext, Token, SymbolToken } 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":["useState","useContext","useEffect","Container","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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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@servicetitan/react-ioc",
|
|
3
|
-
"version": "32.
|
|
3
|
+
"version": "32.1.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"homepage": "https://docs.st.dev/docs/frontend/react-ioc",
|
|
6
6
|
"repository": {
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@testing-library/dom": "^10.4.1",
|
|
24
|
-
"@testing-library/jest-dom": "^6.
|
|
24
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
25
25
|
"@testing-library/react": "^16.3.0",
|
|
26
26
|
"@types/react": "~18.3.3",
|
|
27
27
|
"react": "~18.3.1"
|
|
@@ -34,6 +34,5 @@
|
|
|
34
34
|
},
|
|
35
35
|
"cli": {
|
|
36
36
|
"webpack": false
|
|
37
|
-
}
|
|
38
|
-
"gitHead": "2b74dd72d39c2023151699d1cf7a6e6130d64279"
|
|
37
|
+
}
|
|
39
38
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import '@testing-library/jest-dom';
|
|
2
2
|
import { act, render, screen, waitFor } from '@testing-library/react';
|
|
3
|
-
import { PropsWithChildren, ReactNode, useEffect } from 'react';
|
|
3
|
+
import { FC, PropsWithChildren, ReactNode, useEffect, useState } from 'react';
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
6
|
inject,
|
|
@@ -361,5 +361,30 @@ describe('[react-ioc] Provider', () => {
|
|
|
361
361
|
|
|
362
362
|
expect(stat.testDispose).toHaveBeenCalledTimes(1);
|
|
363
363
|
});
|
|
364
|
+
|
|
365
|
+
test('does not dispose inheritable singleton from parent container when child container is unmounted', () => {
|
|
366
|
+
const UnmountOnMount: FC<PropsWithChildren> = ({ children }) => {
|
|
367
|
+
const [isMounted, setIsMounted] = useState(false);
|
|
368
|
+
|
|
369
|
+
useEffect(() => {
|
|
370
|
+
setIsMounted(true);
|
|
371
|
+
}, []);
|
|
372
|
+
|
|
373
|
+
return isMounted ? null : children;
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
subject(
|
|
377
|
+
<TestProvider store={StoreWithInitialize} singletons={[StoreWithInitialize]}>
|
|
378
|
+
<UnmountOnMount>
|
|
379
|
+
<TestProvider
|
|
380
|
+
store={StoreWithInitialize}
|
|
381
|
+
singletons={[{ provide: StoreWithInitialize, inherit: true }]}
|
|
382
|
+
/>
|
|
383
|
+
</UnmountOnMount>
|
|
384
|
+
</TestProvider>
|
|
385
|
+
);
|
|
386
|
+
|
|
387
|
+
expect(stat.testDispose).not.toHaveBeenCalled();
|
|
388
|
+
});
|
|
364
389
|
});
|
|
365
390
|
});
|
package/src/provider.tsx
CHANGED
|
@@ -137,7 +137,7 @@ const bindEntry =
|
|
|
137
137
|
};
|
|
138
138
|
|
|
139
139
|
const unbindEntry = (container: Container) => (entry: ProviderConfigEntry<any>) => {
|
|
140
|
-
if (isProviderConfigEntryInheritable(entry) && !container.
|
|
140
|
+
if (isProviderConfigEntryInheritable(entry) && !container.isCurrentBound(entry.provide)) {
|
|
141
141
|
return;
|
|
142
142
|
}
|
|
143
143
|
if (
|