Skip to content

Commit 36a4559

Browse files
committed
feat(config): add register state provider api
in order to allow other libraries to register custom providers
1 parent 6bf716f commit 36a4559

14 files changed

+104
-32
lines changed

Diff for: config/config.js

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
const path = require('path');
12
const transformStateOptions = require('./transformStateOptions');
23
const getDirectiveSource = require('./getDirectiveSource');
4+
const { registerProvider } = require('./providers');
5+
6+
registerProvider('session', path.resolve(__dirname, '../src/runtimes/session'));
37

48
module.exports = [
59
{
@@ -14,3 +18,5 @@ module.exports = [
1418
transformOptions: transformStateOptions,
1519
},
1620
];
21+
22+
module.exports.register = registerProvider;

Diff for: config/getDirectiveSource.js

+11-7
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,25 @@
1+
const { getProviders } = require('./providers');
2+
13
function isScopeProp(property) {
24
return property.key.name === 'scope';
35
}
46

57
module.exports = function getDirectiveSource(optionsNode, bootstrap) {
8+
const providers = getProviders();
69
const scope = optionsNode.expression.properties.find(isScopeProp).value.value;
710
const scopeDefinition = bootstrap[scope];
811

912
if (!scopeDefinition) {
1013
throw new Error(`State scope "${scope}" is not defined.`);
1114
}
1215

13-
switch (scopeDefinition.type) {
14-
case 'session':
15-
return './src/runtimes/session';
16-
default:
17-
throw new Error(
18-
`Unexpected use of unknown scope type "${scopeDefinition.type}"`,
19-
);
16+
if (!providers[scopeDefinition.type]) {
17+
throw new Error(
18+
`There is no registered provider for scope of type "${
19+
scopeDefinition.type
20+
}"`,
21+
);
2022
}
23+
24+
return providers[scopeDefinition.type];
2125
};

Diff for: config/providers.js

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
let providers = {};
2+
3+
exports.registerProvider = function registerProvider(name, entry) {
4+
if (providers[name]) {
5+
throw new Error(`state provider "${name}" is already registered`);
6+
}
7+
8+
providers[name] = entry;
9+
};
10+
11+
exports.getProviders = function getProviders() {
12+
return providers;
13+
};
14+
15+
// eslint-disable-next-line no-underscore-dangle
16+
exports.__reset = () => {
17+
providers = {};
18+
};

Diff for: src/runtimes/helpers/createBootstrap.js renamed to src/createBootstrap.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
export default function createBootstrap(providerKey, bootstrapFn) {
1+
import { registerProvider } from './StateProviderDirective';
2+
3+
export default function createBootstrap(providerKey, bootstrapFn, Provider) {
24
return options => {
35
const typeOptions = Object.keys(options).reduce((memo, key) => {
46
const definition = options[key];
@@ -11,6 +13,7 @@ export default function createBootstrap(providerKey, bootstrapFn) {
1113
return memo;
1214
}, {});
1315

16+
registerProvider(Provider);
1417
bootstrapFn(typeOptions);
1518
};
1619
}

Diff for: src/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from './createBootstrap';

Diff for: src/runtimes/helpers/index.js

-3
This file was deleted.

Diff for: src/runtimes/session.js

-11
This file was deleted.

Diff for: src/stateProviders/session/bootstrap.js

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
import { createStore } from 'redux';
22
import { devToolsEnhancer } from 'redux-devtools-extension';
33
import createReducers from './createReducers';
4+
import Provider from './Provider';
5+
import createBootstrap from '../../';
46

57
let store = null;
68

79
export function getStore() {
810
return store;
911
}
1012

11-
export default function bootstrap(options) {
12-
store = createStore(createReducers(options), devToolsEnhancer());
13-
}
13+
export default createBootstrap(
14+
'session',
15+
options => {
16+
store = createStore(createReducers(options), devToolsEnhancer());
17+
},
18+
Provider,
19+
);

Diff for: src/stateProviders/session/index.js

-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
export { default } from './SessionDirective';
2-
export { default as Provider } from './Provider';
32
export { default as bootstrap } from './bootstrap';

Diff for: test/config/__snapshots__/getDirectiveSouce.spec.js.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22

33
exports[`getDirectiveSource throws when a undefined scope is being used 1`] = `"State scope \\"foo\\" is not defined."`;
44

5-
exports[`getDirectiveSource throws when a undefined scope type is being used 1`] = `"Unexpected use of unknown scope type \\"bar\\""`;
5+
exports[`getDirectiveSource throws when a undefined scope type is being used 1`] = `"There is no registered provider for scope of type \\"bar\\""`;

Diff for: test/config/__snapshots__/providers.spec.js.snap

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`providers does not support overwrites of providers 1`] = `"state provider \\"foo\\" is already registered"`;

Diff for: test/config/getDirectiveSouce.spec.js

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const getDirectiveSource = require('../../config/getDirectiveSource');
2+
const { registerProvider, __reset } = require('../../config/providers');
23

34
function createNode(properties) {
45
return {
@@ -16,11 +17,15 @@ function createProperty(name, value) {
1617
}
1718

1819
describe('getDirectiveSource', () => {
20+
afterEach(() => {
21+
__reset();
22+
});
23+
1924
it('throws when a undefined scope is being used', () => {
2025
const fakeNode = createNode([createProperty('scope', 'foo')]);
2126

2227
expect(() => {
23-
getDirectiveSource(fakeNode, { bar: {} });
28+
getDirectiveSource(fakeNode, {});
2429
}).toThrowErrorMatchingSnapshot();
2530
});
2631

@@ -32,11 +37,12 @@ describe('getDirectiveSource', () => {
3237
}).toThrowErrorMatchingSnapshot();
3338
});
3439

35-
it('supports a session scope type', () => {
40+
it('supports a registered scope type', () => {
41+
registerProvider('bar', '/bar.js');
3642
const fakeNode = createNode([createProperty('scope', 'foo')]);
3743

38-
const source = getDirectiveSource(fakeNode, { foo: { type: 'session' } });
44+
const source = getDirectiveSource(fakeNode, { foo: { type: 'bar' } });
3945

40-
expect(source).toBe('./src/runtimes/session');
46+
expect(source).toBe('/bar.js');
4147
});
4248
});

Diff for: test/config/providers.spec.js

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
const {
2+
registerProvider,
3+
__reset,
4+
getProviders,
5+
} = require('../../config/providers');
6+
7+
describe('providers', () => {
8+
afterEach(() => {
9+
__reset();
10+
});
11+
12+
it('has no registered providers by default', () => {
13+
expect(getProviders()).toEqual({});
14+
});
15+
16+
it('provides registered providers', () => {
17+
registerProvider('foo', 'bar');
18+
19+
expect(getProviders()).toEqual({ foo: 'bar' });
20+
});
21+
22+
it('does not support overwrites of providers', () => {
23+
registerProvider('foo', 'bar');
24+
expect(() => {
25+
registerProvider('foo', 'bar');
26+
}).toThrowErrorMatchingSnapshot();
27+
});
28+
});

Diff for: test/runtimes/session.spec.jsx

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
/* eslint-disable no-console */
2+
13
import React from 'react';
24
import Enzyme, { mount } from 'enzyme';
35
import Adapter from 'enzyme-adapter-react-16';
46
import renderer from 'react-test-renderer';
5-
import SessionDirective, { bootstrap } from '../../src/runtimes/session';
7+
import SessionDirective, { bootstrap } from '../../src/stateProviders/session';
68
import StateProviderDirective from '../../src/StateProviderDirective';
79

810
Enzyme.configure({ adapter: new Adapter() });
@@ -31,7 +33,15 @@ function withState({ options, as }) {
3133
};
3234
}
3335

36+
const originalConsoleError = console.error;
37+
38+
function noop() {}
39+
3440
describe('session runtime', () => {
41+
afterEach(() => {
42+
console.error = originalConsoleError;
43+
});
44+
3545
it('renders without error', () => {
3646
const SimpleDiv = withState({})('div');
3747

@@ -176,6 +186,7 @@ describe('session runtime', () => {
176186

177187
bootstrap({ bar: { type: 'session', initialState: { bar: 'baf' } } });
178188

189+
console.error = noop;
179190
expect(() => {
180191
renderer
181192
.create(
@@ -215,6 +226,7 @@ describe('session runtime', () => {
215226
as: 'children',
216227
})('div');
217228

229+
console.error = noop;
218230
expect(() => {
219231
renderer
220232
.create(

0 commit comments

Comments
 (0)