mirror of
https://github.com/storybookjs/storybook.git
synced 2025-04-06 05:31:06 +08:00
`@storybook/semver` is a browser friendly fork of `semver`. We use it to avoid issue with IE11 as classic "compiled" `semver` is now compatible with it. If we just recompile `semver` from `node_modules` it ends with a package that `require('core-js')` but `core-js` is not listed in the dependency. And so Yarn 2 throw an error. So to avoid that we need to use a "proper" dependency which is `semver` recompile and with all needed dependencies in its package.json.
146 lines
3.5 KiB
TypeScript
146 lines
3.5 KiB
TypeScript
import { VERSIONCHECK } from 'global';
|
|
import semver from '@storybook/semver';
|
|
import memoize from 'memoizerific';
|
|
|
|
import { version as currentVersion } from '../version';
|
|
|
|
import { ModuleFn } from '../index';
|
|
|
|
export interface Version {
|
|
version: string;
|
|
info?: { plain: string };
|
|
[key: string]: any;
|
|
}
|
|
|
|
export interface UnknownEntries {
|
|
[key: string]: {
|
|
[key: string]: any;
|
|
};
|
|
}
|
|
|
|
export interface Versions {
|
|
latest?: Version;
|
|
next?: Version;
|
|
current?: Version;
|
|
}
|
|
|
|
export interface SubState {
|
|
versions: Versions & UnknownEntries;
|
|
lastVersionCheck: number;
|
|
dismissedVersionNotification: undefined | string;
|
|
}
|
|
|
|
const getVersionCheckData = memoize(1)(
|
|
(): Versions => {
|
|
try {
|
|
return { ...(JSON.parse(VERSIONCHECK).data || {}) };
|
|
} catch (e) {
|
|
return {};
|
|
}
|
|
}
|
|
);
|
|
|
|
export interface SubAPI {
|
|
getCurrentVersion: () => Version;
|
|
getLatestVersion: () => Version;
|
|
versionUpdateAvailable: () => boolean;
|
|
}
|
|
|
|
export const init: ModuleFn = ({ store, mode, fullAPI }) => {
|
|
const { dismissedVersionNotification } = store.getState();
|
|
|
|
const state = {
|
|
versions: {
|
|
current: {
|
|
version: currentVersion,
|
|
},
|
|
...getVersionCheckData(),
|
|
},
|
|
dismissedVersionNotification,
|
|
};
|
|
|
|
const api: SubAPI = {
|
|
getCurrentVersion: () => {
|
|
const {
|
|
versions: { current },
|
|
} = store.getState();
|
|
return current;
|
|
},
|
|
getLatestVersion: () => {
|
|
const {
|
|
versions: { latest, next, current },
|
|
} = store.getState();
|
|
if (current && semver.prerelease(current.version) && next) {
|
|
return latest && semver.gt(latest.version, next.version) ? latest : next;
|
|
}
|
|
return latest;
|
|
},
|
|
versionUpdateAvailable: () => {
|
|
const latest = api.getLatestVersion();
|
|
const current = api.getCurrentVersion();
|
|
|
|
if (latest) {
|
|
if (!latest.version) {
|
|
return true;
|
|
}
|
|
if (!current.version) {
|
|
return true;
|
|
}
|
|
|
|
const onPrerelease = !!semver.prerelease(current.version);
|
|
|
|
const actualCurrent = onPrerelease
|
|
? `${semver.major(current.version)}.${semver.minor(current.version)}.${semver.patch(
|
|
current.version
|
|
)}`
|
|
: current.version;
|
|
|
|
const diff = semver.diff(actualCurrent, latest.version);
|
|
|
|
return (
|
|
semver.gt(latest.version, actualCurrent) && diff !== 'patch' && !diff.includes('pre')
|
|
);
|
|
}
|
|
return false;
|
|
},
|
|
};
|
|
|
|
// Grab versions from the server/local storage right away
|
|
const initModule = async () => {
|
|
const { versions = {} } = store.getState();
|
|
|
|
const { latest, next } = getVersionCheckData();
|
|
|
|
await store.setState({
|
|
versions: { ...versions, latest, next },
|
|
});
|
|
|
|
if (api.versionUpdateAvailable()) {
|
|
const latestVersion = api.getLatestVersion().version;
|
|
|
|
const diff = semver.diff(versions.current.version, versions.latest.version);
|
|
|
|
if (
|
|
latestVersion !== dismissedVersionNotification &&
|
|
diff !== 'patch' &&
|
|
!semver.prerelease(latestVersion) &&
|
|
mode !== 'production'
|
|
) {
|
|
fullAPI.addNotification({
|
|
id: 'update',
|
|
link: '/settings/about',
|
|
content: `🎉 Storybook ${latestVersion} is available!`,
|
|
onClear() {
|
|
store.setState(
|
|
{ dismissedVersionNotification: latestVersion },
|
|
{ persistence: 'permanent' }
|
|
);
|
|
},
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
return { init: initModule, state, api };
|
|
};
|