Skip to content
This repository has been archived by the owner on Oct 20, 2022. It is now read-only.

Commit

Permalink
fix: add deprecation warning HOCs
Browse files Browse the repository at this point in the history
  • Loading branch information
JacobBlomgren committed Feb 11, 2019
1 parent c8050cc commit 54d2068
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 6 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"docs-publish": "gh-pages -d documentation/dist --repo https://$GH_TOKEN@github.com/nordnet/nordnet-ui-kit.git --silent",
"semantic-release": "semantic-release",
"eslint-check": "eslint --print-config .eslintrc | eslint-config-prettier-check",
"format": "prettier --write '{src}/**/*.{js,jsx}'"
"format": "prettier --write 'src/**/*.{js,jsx}'"
},
"files": [
"dist",
Expand Down Expand Up @@ -81,6 +81,7 @@
},
"peerDependencies": {
"prop-types": ">=15",
"ramda": "^0.26.1",
"react": ">=15",
"react-dom": ">=15",
"react-jss": ">=7"
Expand Down
62 changes: 62 additions & 0 deletions src/components/deprecate/deprecate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/* eslint-disable react/no-multi-comp */
import React, { Component } from 'react';
import * as R from 'ramda';

// Only want to warn once per component
const hasWarned = {};
// Usage: deprecatedComponent('Pane', 'Use Tabs instead')(Component);
const deprecatedComponent = (
displayName,
extraMessage = 'Please consult the docs for a migration guide.',
) => C => {
class Deprecated extends Component {
componentDidMount() {
if (!hasWarned[displayName]) {
// eslint-disable-next-line no-console
console.warn(`${displayName} is deprecated. ${extraMessage}`);
hasWarned[displayName] = true;
}
}

render() {
return <C {...this.props} />;
}
}
return Deprecated;
};

// Only want to warn once per component and prop
const hasWarnedProps = {};

/* Usage:
deprecatedProps('Flag', [{
prop: 'size',
message: 'size in Flag as a number is deprecated. Use sm, md or lg instead',
}])(Flag)
*/
const deprecatedProps = (displayName, deprecated) => C => {
class Deprecated extends Component {
componentDidMount() {
if (!hasWarnedProps[displayName]) hasWarnedProps[displayName] = {};
R.intersection(Object.keys(this.props), deprecated.map(d => d.prop)).forEach(p => {
if (!hasWarnedProps[displayName][p]) {
// eslint-disable-next-line no-console
console.warn((deprecated.find(d1 => d1.prop === p) || {}).message);
hasWarnedProps[displayName][p] = true;
}
});
}

render() {
return <C {...this.props} />;
}
}
return Deprecated;
};

const isNotProd = process.env.NODE_ENV !== 'production';

const dc = isNotProd ? deprecatedComponent : C => C;
const dp = isNotProd ? deprecatedProps : C => C;

export { dc as deprecatedComponent, dp as deprecatedProps };
54 changes: 54 additions & 0 deletions src/components/deprecate/deprecate.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from 'react';
import { shallow } from 'enzyme';

import { deprecatedProps, deprecatedComponent } from './deprecate';

let warnMock;
beforeEach(() => {
warnMock = jest.fn();
global.console.warn = warnMock;
});

const DEFAULT_MESSAGE = 'Please consult the docs for a migration guide.';

test('deprecatedComponent', () => {
const Component = () => <div />;
const DC = deprecatedComponent('Flag')(Component);
shallow(<DC />);
expect(warnMock).toHaveBeenCalled();
expect(warnMock.mock.calls[0][0]).toMatch('Flag is deprecated.');
expect(warnMock.mock.calls[0][0]).toMatch(DEFAULT_MESSAGE);
});

test('deprecatedComponent with custom message', () => {
const Component = () => <div />;
const msg = 'Use the new Flag component instead.';
const DC = deprecatedComponent('Flag2', msg)(Component);
shallow(<DC />);
expect(warnMock).toHaveBeenCalled();
expect(warnMock.mock.calls[0][0]).toMatch('Flag2 is deprecated.');
expect(warnMock.mock.calls[0][0]).toMatch(msg);
});

test('deprecatedComponent should only warn once', () => {
const Component = () => <div />;
const DC = deprecatedComponent('Flag3')(Component);
shallow(<DC />);
expect(warnMock).toHaveBeenCalled();
shallow(<DC />);
expect(warnMock).toHaveBeenCalledTimes(1);
expect(warnMock.mock.calls[0][0]).toMatch('Flag3 is deprecated.');
});

test('deprecatedProps', () => {
const Component = () => <div />;
const DC = deprecatedProps('Flag', [
{
prop: 'size',
message: 'size in Flag as a number is deprecated. Use sm, md or lg instead',
},
])(Component);
shallow(<DC size={16} />);
expect(warnMock).toHaveBeenCalled();
expect(warnMock.mock.calls[0][0]).toMatch('Use sm, md or lg instead');
});
3 changes: 3 additions & 0 deletions src/components/deprecate/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { deprecatedComponent, deprecatedProps } from './deprecate';

export { deprecatedComponent, deprecatedProps };
9 changes: 8 additions & 1 deletion src/components/flag/flag.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React from 'react';
import { SvgFlag, CurrencyFlag } from './flags';
import FlagDeprecated from './flag-deprecated';
import color from '../../styles/color';
import { deprecatedProps } from '../deprecate';

const addBorder = props => !props.hideBorder && !props.round && !props.secondaryCountryCode;

Expand Down Expand Up @@ -110,4 +111,10 @@ Flag.propTypes = {
borderColor: PropTypes.string,
};
export { Flag as Component };
export default Flag;
export default deprecatedProps('Flag', [
{
prop: 'size',
message:
"size in Flag as a number is deprecated. Please use one of 'xs', 'sm', 'md', 'lg' instead",
},
])(Flag);
10 changes: 9 additions & 1 deletion src/components/instrument-badge/instrument-badge.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import injectSheet from 'react-jss';
import cn from 'classnames';
import { Icon, Tooltip } from '../..';
import omit from '../../utilities/omit';
import { deprecatedComponent } from '../deprecate';

export const styles = theme => {
const { palette, typography, mixins } = theme;
Expand Down Expand Up @@ -293,4 +294,11 @@ InstrumentBadge.defaultProps = {
};

export { InstrumentBadge as Component };
export default injectSheet(styles)(InstrumentBadge);
// prettier-ignore
export default
injectSheet(styles)(
deprecatedComponent(
'InstrumentBadge',
'See https://github.com/nordnet/nordnet-ui-kit/blob/v3.0.0/docs/migrations/v3.0.0.md for migration guide.',
)
(InstrumentBadge));
10 changes: 9 additions & 1 deletion src/components/pane/pane.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import injectSheet from 'react-jss';
import classNames from 'classnames';
import { kebabCase } from 'lodash';
import styles from './pane-styles';
import { deprecatedComponent } from '../deprecate';

class Pane extends React.PureComponent {
constructor(props, context) {
Expand Down Expand Up @@ -111,4 +112,11 @@ Pane.defaultProps = {
};

export { Pane as Component, styles };
export default injectSheet(styles)(Pane);
// prettier-ignore
export default
injectSheet(styles)(
deprecatedComponent(
'Pane',
'See https://github.com/nordnet/nordnet-ui-kit/blob/v3.0.0/docs/migrations/v3.0.0.md for migration guide.',
)
(Pane));
10 changes: 9 additions & 1 deletion src/components/segmented-control/segmented-control.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import injectSheet from 'react-jss';
import cn from 'classnames';
import styles from './segmented-control-styles';
import { deprecatedProps } from '../deprecate';

class SegmentedControl extends React.PureComponent {
constructor(props, context) {
Expand Down Expand Up @@ -176,4 +177,11 @@ SegmentedControl.propTypes = {
};

export { SegmentedControl as Component, styles };
export default injectSheet(styles)(SegmentedControl);
// prettier-ignore
export default
injectSheet(styles)
(deprecatedProps('SegmentedControl', [{
prop: 'variant',
message: 'variant="secondary" in SegmentedControl is deprecated. Use another Tab component instead. See https://github.com/nordnet/nordnet-ui-kit/blob/v3.0.0/docs/migrations/v3.0.0.md',
}])
(SegmentedControl));
10 changes: 9 additions & 1 deletion src/components/tabs/tabs.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import injectSheet from 'react-jss';
import cn from 'classnames';
import { Tab, Tabpanel } from '../..';
import styles from './tabs-styles';
import { deprecatedComponent } from '../deprecate';

class Tabs extends Component {
injectContextProps(displayName) {
Expand Down Expand Up @@ -65,4 +66,11 @@ Tabs.propTypes = {
};

export { Tabs as Component, styles };
export default injectSheet(styles)(Tabs);
// prettier-ignore
export default
injectSheet(styles)(
deprecatedComponent(
'Tabs',
'See https://github.com/nordnet/nordnet-ui-kit/blob/v3.0.0/docs/migrations/v3.0.0.md for migration guide.',
)
(Tabs));
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8659,6 +8659,11 @@ railroad-diagrams@^1.0.0:
resolved "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e"
integrity sha1-635iZ1SN3t+4mcG5Dlc3RVnN234=

ramda@^0.26.1:
version "0.26.1"
resolved "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz#8d41351eb8111c55353617fc3bbffad8e4d35d06"
integrity sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ==

randexp@0.4.6:
version "0.4.6"
resolved "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz#e986ad5e5e31dae13ddd6f7b3019aa7c87f60ca3"
Expand Down

0 comments on commit 54d2068

Please sign in to comment.