2018-06-25 12:47:09 +03:00
|
|
|
import memoize from 'memoize-one';
|
2018-07-30 12:51:50 +03:00
|
|
|
import { Component, createContext } from 'react';
|
2017-11-20 19:02:49 +03:00
|
|
|
|
2017-11-14 18:46:50 +03:00
|
|
|
import { AppStore } from '../services/';
|
2017-11-21 14:00:33 +03:00
|
|
|
import { RedocRawOptions } from '../services/RedocNormalizedOptions';
|
2018-03-13 14:04:55 +03:00
|
|
|
import { loadAndBundleSpec } from '../utils';
|
2017-10-12 00:01:37 +03:00
|
|
|
|
2018-07-30 12:51:50 +03:00
|
|
|
export interface StoreBuilderProps {
|
2017-10-12 00:01:37 +03:00
|
|
|
specUrl?: string;
|
|
|
|
spec?: object;
|
|
|
|
store?: AppStore;
|
2017-11-14 18:46:50 +03:00
|
|
|
|
2017-11-21 14:00:33 +03:00
|
|
|
options?: RedocRawOptions;
|
|
|
|
|
2018-06-25 13:48:51 +03:00
|
|
|
onLoaded?: (e?: Error) => void;
|
|
|
|
|
2017-11-22 12:02:26 +03:00
|
|
|
children: (props: { loading: boolean; store?: AppStore }) => any;
|
2017-10-12 00:01:37 +03:00
|
|
|
}
|
|
|
|
|
2018-07-30 12:51:50 +03:00
|
|
|
export interface StoreBuilderState {
|
2017-11-14 18:46:50 +03:00
|
|
|
error?: Error;
|
|
|
|
loading: boolean;
|
2018-06-25 13:48:51 +03:00
|
|
|
resolvedSpec?: any;
|
|
|
|
prevSpec?: any;
|
2018-06-25 12:47:09 +03:00
|
|
|
prevSpecUrl?: string;
|
2017-11-14 18:46:50 +03:00
|
|
|
}
|
2017-10-12 00:01:37 +03:00
|
|
|
|
2018-07-30 12:51:50 +03:00
|
|
|
const { Provider, Consumer } = createContext<AppStore | undefined>(undefined);
|
|
|
|
export { Provider as StoreProvider, Consumer as StoreConsumer };
|
|
|
|
|
|
|
|
export class StoreBuilder extends Component<StoreBuilderProps, StoreBuilderState> {
|
|
|
|
static getDerivedStateFromProps(nextProps: StoreBuilderProps, prevState: StoreBuilderState) {
|
2018-06-25 13:48:51 +03:00
|
|
|
if (nextProps.specUrl !== prevState.prevSpecUrl || nextProps.spec !== prevState.prevSpec) {
|
2018-06-25 12:47:09 +03:00
|
|
|
return {
|
2018-06-25 13:48:51 +03:00
|
|
|
loading: true,
|
|
|
|
resolvedSpec: null,
|
|
|
|
prevSpec: nextProps.spec,
|
|
|
|
prevSpecUrl: nextProps.specUrl,
|
2018-06-25 12:47:09 +03:00
|
|
|
};
|
|
|
|
}
|
2017-10-12 00:01:37 +03:00
|
|
|
|
2018-06-25 12:47:09 +03:00
|
|
|
return null;
|
|
|
|
}
|
2018-03-09 22:11:28 +03:00
|
|
|
|
2018-07-30 12:51:50 +03:00
|
|
|
state: StoreBuilderState = {
|
2018-06-25 12:47:09 +03:00
|
|
|
loading: true,
|
2018-06-25 13:48:51 +03:00
|
|
|
resolvedSpec: null,
|
2018-06-25 12:47:09 +03:00
|
|
|
};
|
2017-11-14 18:46:50 +03:00
|
|
|
|
2018-06-25 12:47:09 +03:00
|
|
|
@memoize
|
|
|
|
makeStore(spec, specUrl, options) {
|
|
|
|
if (!spec) {
|
|
|
|
return undefined;
|
|
|
|
}
|
2018-11-06 12:47:02 +03:00
|
|
|
try {
|
|
|
|
return new AppStore(spec, specUrl, options);
|
|
|
|
} catch (e) {
|
|
|
|
if (this.props.onLoaded) {
|
|
|
|
this.props.onLoaded(e);
|
|
|
|
}
|
|
|
|
throw e;
|
|
|
|
}
|
2017-11-20 02:00:43 +03:00
|
|
|
}
|
2017-11-14 18:46:50 +03:00
|
|
|
|
2017-11-20 02:00:43 +03:00
|
|
|
componentDidMount() {
|
2017-11-14 18:46:50 +03:00
|
|
|
this.load();
|
|
|
|
}
|
|
|
|
|
2018-06-25 12:47:09 +03:00
|
|
|
componentDidUpdate() {
|
2018-06-25 13:48:51 +03:00
|
|
|
if (this.state.resolvedSpec === null) {
|
2018-06-25 12:47:09 +03:00
|
|
|
this.load();
|
2018-06-25 13:48:51 +03:00
|
|
|
} else if (!this.state.loading && this.props.onLoaded) {
|
|
|
|
// may run multiple time
|
|
|
|
this.props.onLoaded();
|
2018-03-09 22:11:28 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-25 12:47:09 +03:00
|
|
|
async load() {
|
2018-07-17 12:15:22 +03:00
|
|
|
const { specUrl, spec } = this.props;
|
2018-03-09 22:11:28 +03:00
|
|
|
try {
|
2018-06-25 12:47:09 +03:00
|
|
|
const resolvedSpec = await loadAndBundleSpec(spec || specUrl!);
|
2018-06-25 13:48:51 +03:00
|
|
|
this.setState({ resolvedSpec, loading: false });
|
2017-11-14 18:46:50 +03:00
|
|
|
} catch (e) {
|
2018-06-25 13:48:51 +03:00
|
|
|
if (this.props.onLoaded) {
|
|
|
|
this.props.onLoaded(e);
|
|
|
|
}
|
2018-06-25 12:47:09 +03:00
|
|
|
this.setState({ error: e });
|
2018-03-09 22:11:28 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-12 00:01:37 +03:00
|
|
|
render() {
|
2018-01-22 21:30:53 +03:00
|
|
|
if (this.state.error) {
|
|
|
|
throw this.state.error;
|
|
|
|
}
|
2018-06-25 12:47:09 +03:00
|
|
|
|
|
|
|
const { specUrl, options } = this.props;
|
2018-06-25 13:48:51 +03:00
|
|
|
const { loading, resolvedSpec } = this.state;
|
2018-06-25 12:47:09 +03:00
|
|
|
return this.props.children({
|
|
|
|
loading,
|
2018-06-25 13:48:51 +03:00
|
|
|
store: this.makeStore(resolvedSpec, specUrl, options),
|
2018-06-25 12:47:09 +03:00
|
|
|
});
|
2017-10-12 00:01:37 +03:00
|
|
|
}
|
|
|
|
}
|