-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore!: Extract auto-registration as extension
In addition to keeping the injectable core minimal, with this we have control over order of registrations in extensions and normal injectables. Eg. decorators for registration need to register before they are expected to do anything.
- Loading branch information
Showing
16 changed files
with
306 additions
and
153 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
packages/injectable-extension-for-auto-registration/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# Auto-registration for Injectable in Ogre Tools | ||
|
||
Auto register injectables from default exports of files that match a require.context. | ||
|
||
## Usage | ||
|
||
``` | ||
$ npm install @ogre-tools/injectable | ||
$ npm install @ogre-tools/injectable-extension-for-auto-registration | ||
... | ||
const di = createContainer(); | ||
autoRegister({ | ||
di, | ||
requireContexts: [ | ||
require.context("./some-directory", true, /\.injectable\.(ts|tsx)$/), | ||
require.context("./some-other-directory", true, /\.injectable\.(ts|tsx)$/), | ||
], | ||
}); | ||
``` | ||
|
||
## Documentation | ||
|
||
Check unit tests for documentation. |
14 changes: 14 additions & 0 deletions
14
packages/injectable-extension-for-auto-registration/babel.config.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
module.exports = { | ||
presets: [ | ||
[ | ||
'@babel/preset-env', | ||
{ | ||
targets: { | ||
node: 'current', | ||
}, | ||
}, | ||
], | ||
|
||
'@babel/react', | ||
], | ||
}; |
8 changes: 8 additions & 0 deletions
8
packages/injectable-extension-for-auto-registration/index.d.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { DiContainer } from '@ogre-tools/injectable'; | ||
|
||
declare module '@ogre-tools/injectable-extension-for-mobx' { | ||
export function autoRegister(arg: { | ||
di: DiContainer; | ||
requireContexts: __WebpackModuleApi.RequireContext[]; | ||
}): void; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import autoRegister from './src/autoRegister'; | ||
|
||
export { autoRegister }; |
19 changes: 19 additions & 0 deletions
19
packages/injectable-extension-for-auto-registration/package-lock.json
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
29 changes: 29 additions & 0 deletions
29
packages/injectable-extension-for-auto-registration/package.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
{ | ||
"name": "@ogre-tools/injectable-extension-for-auto-registration", | ||
"private": false, | ||
"version": "6.0.1", | ||
"description": "Auto-registration of injectables for Injectable in Ogre Tools", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/ogre-works/ogre-tools" | ||
}, | ||
"main": "build/index.js", | ||
"types": "./index.d.ts", | ||
"keywords": [ | ||
"js" | ||
], | ||
"author": "Ogre Works", | ||
"license": "MIT", | ||
"dependencies": { | ||
"@ogre-tools/fp": "^6.0.1", | ||
"@ogre-tools/injectable": "^6.0.1", | ||
"lodash": "^4.17.21" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/ogre-works/ogre-tools/issues" | ||
}, | ||
"homepage": "https://github.com/ogre-works/ogre-tools#readme", | ||
"publishConfig": { | ||
"access": "public" | ||
} | ||
} |
43 changes: 43 additions & 0 deletions
43
packages/injectable-extension-for-auto-registration/src/autoRegister.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import conforms from 'lodash/fp/conforms'; | ||
import isString from 'lodash/fp/isString'; | ||
import isFunction from 'lodash/fp/isFunction'; | ||
import { pipeline } from '@ogre-tools/fp'; | ||
import tap from 'lodash/fp/tap'; | ||
import forEach from 'lodash/fp/forEach'; | ||
import flatMap from 'lodash/fp/flatMap'; | ||
|
||
const hasInjectableSignature = conforms({ | ||
id: isString, | ||
instantiate: isFunction, | ||
}); | ||
|
||
const getFileNameAndDefaultExport = requireContext => | ||
requireContext.keys().map(key => [key, requireContext(key).default]); | ||
|
||
const registerInjectableFor = | ||
di => | ||
([, injectable]) => | ||
di.register(injectable); | ||
|
||
const verifyInjectable = ([fileName, injectable]) => { | ||
if (!injectable) { | ||
throw new Error( | ||
`Tried to register injectable from ${fileName}, but no default export`, | ||
); | ||
} | ||
|
||
if (!hasInjectableSignature(injectable)) { | ||
throw new Error( | ||
`Tried to register injectable from ${fileName}, but default export is of wrong shape`, | ||
); | ||
} | ||
}; | ||
|
||
export default ({ di, requireContexts }) => { | ||
pipeline( | ||
requireContexts, | ||
flatMap(getFileNameAndDefaultExport), | ||
tap(forEach(verifyInjectable)), | ||
forEach(registerInjectableFor(di)), | ||
); | ||
}; |
152 changes: 152 additions & 0 deletions
152
packages/injectable-extension-for-auto-registration/src/autoRegister.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
import { createContainer, getInjectable } from '@ogre-tools/injectable'; | ||
import { pipeline } from '@ogre-tools/fp'; | ||
import map from 'lodash/fp/map'; | ||
import fromPairs from 'lodash/fp/fromPairs'; | ||
import keys from 'lodash/fp/keys'; | ||
import autoRegister from './autoRegister'; | ||
|
||
const nonCappedMap = map.convert({ cap: false }); | ||
|
||
describe('autoRegister', () => { | ||
it('injects auto-registered injectable without sub-injectables', () => { | ||
const injectableStub = getInjectable({ | ||
id: 'irrelevant', | ||
instantiate: () => 'some-injected-instance', | ||
}); | ||
|
||
const di = createContainer(); | ||
|
||
const someRequireContext = getRequireContextStub(injectableStub); | ||
|
||
autoRegister({ di, requireContexts: [someRequireContext] }); | ||
|
||
const actual = di.inject(injectableStub); | ||
|
||
expect(actual).toBe('some-injected-instance'); | ||
}); | ||
|
||
it('given injectable file with no default export, when auto-registering, throws with name of faulty file', () => { | ||
const requireContextStub = Object.assign( | ||
() => ({ | ||
notDefault: 'irrelevant', | ||
}), | ||
|
||
{ | ||
keys: () => ['./some.injectable.js'], | ||
}, | ||
); | ||
|
||
const di = createContainer(); | ||
|
||
expect(() => | ||
autoRegister({ di, requireContexts: [requireContextStub] }), | ||
).toThrowError( | ||
'Tried to register injectable from ./some.injectable.js, but no default export', | ||
); | ||
}); | ||
|
||
it('given injectable file with default export without id, when auto-registering, throws with name of faulty file', () => { | ||
const requireContextStub = Object.assign( | ||
() => ({ | ||
default: 'irrelevant', | ||
}), | ||
{ | ||
keys: () => ['./some.injectable.js'], | ||
}, | ||
); | ||
|
||
const di = createContainer(); | ||
|
||
expect(() => | ||
autoRegister({ di, requireContexts: [requireContextStub] }), | ||
).toThrowError( | ||
'Tried to register injectable from ./some.injectable.js, but default export is of wrong shape', | ||
); | ||
}); | ||
|
||
it('given injectable file with default export with in but without instantiate, when auto-registering, throws with name of faulty file', () => { | ||
const requireContextStub = Object.assign( | ||
() => ({ | ||
default: { | ||
id: 'irrelevant', | ||
}, | ||
}), | ||
{ | ||
keys: () => ['./some.injectable.js'], | ||
}, | ||
); | ||
|
||
const di = createContainer(); | ||
|
||
expect(() => | ||
autoRegister({ di, requireContexts: [requireContextStub] }), | ||
).toThrowError( | ||
'Tried to register injectable from ./some.injectable.js, but default export is of wrong shape', | ||
); | ||
}); | ||
|
||
it('given injectable file with default export of correct shape, when auto-registering, does not throw', () => { | ||
const requireContextStub = Object.assign( | ||
() => ({ | ||
default: { | ||
id: 'some-injectable-id', | ||
instantiate: () => {}, | ||
}, | ||
}), | ||
{ | ||
keys: () => ['./some.injectable.js'], | ||
}, | ||
); | ||
|
||
const di = createContainer(); | ||
|
||
expect(() => | ||
autoRegister({ di, requireContexts: [requireContextStub] }), | ||
).not.toThrow(); | ||
}); | ||
|
||
it('injects auto-registered injectable with a another auto-registered child-injectable', () => { | ||
const childInjectable = getInjectable({ | ||
id: 'some-injectable', | ||
instantiate: () => 'some-child-instance', | ||
}); | ||
|
||
const parentInjectable = getInjectable({ | ||
id: 'some-other-injectable', | ||
instantiate: di => di.inject(childInjectable), | ||
}); | ||
|
||
const di = createContainer(); | ||
|
||
autoRegister({ | ||
di, | ||
|
||
requireContexts: [ | ||
getRequireContextStub(childInjectable), | ||
getRequireContextStub(parentInjectable), | ||
], | ||
}); | ||
|
||
const actual = di.inject(parentInjectable); | ||
|
||
expect(actual).toBe('some-child-instance'); | ||
}); | ||
}); | ||
|
||
const getRequireContextStub = (...injectables) => { | ||
const contextDictionary = pipeline( | ||
injectables, | ||
map(injectable => ({ default: injectable })), | ||
|
||
nonCappedMap((file, index) => [ | ||
`stubbed-require-context-key-${index}`, | ||
file, | ||
]), | ||
|
||
fromPairs, | ||
); | ||
|
||
return Object.assign(contextKey => contextDictionary[contextKey], { | ||
keys: () => keys(contextDictionary), | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.