eslint-plugin-reblend
Version:
Reblend specific linting rules for ESLint
1,987 lines (1,962 loc) • 176 kB
JavaScript
/**
* @fileoverview Warn about unused PropType definitions in Reblend components
* @author Evgueni Naverniouk
*/
'use strict';
// ------------------------------------------------------------------------------
// Requirements
// ------------------------------------------------------------------------------
const semver = require('semver');
const eslintPkg = require('eslint/package.json');
const babelEslintVersion = require('babel-eslint/package.json').version;
const RuleTester = require('eslint').RuleTester;
require('object.entries/auto'); // for node 6, eslint 5, new TS parser, `function Hello({firstname}: Props): Reblend$Element {` cases
const rule = require('../../../lib/rules/no-unused-prop-types');
const parsers = require('../../helpers/parsers');
const parserOptions = {
ecmaVersion: 2018,
sourceType: 'module',
ecmaFeatures: {
jsx: true,
},
};
const settings = {
reblend: {
pragma: 'Foo',
},
};
// ------------------------------------------------------------------------------
// Tests
// ------------------------------------------------------------------------------
const ruleTester = new RuleTester({ parserOptions });
ruleTester.run('no-unused-prop-types', rule, {
valid: parsers.all([
{
code: `
var Hello = createReblendClass({
propTypes: {
name: PropTypes.string.isRequired
},
render: function() {
return <div>Hello {this.props.name}</div>;
}
});
`,
},
{
code: `
var Hello = createReblendClass({
propTypes: {
name: PropTypes.object.isRequired
},
render: function() {
return <div>Hello {this.props.name.firstname}</div>;
}
});
`,
},
{
code: `
var Hello = createReblendClass({
render: function() {
return <div>Hello World</div>;
}
});
`,
},
{
code: `
var Hello = createReblendClass({
render: function() {
var props = this.props;
return <div>Hello World</div>;
}
});
`,
},
{
code: `
var Hello = createReblendClass({
render: function() {
var propName = "foo";
return <div>Hello World {this.props[propName]}</div>;
}
});
`,
},
{
code: `
var Hello = createReblendClass({
propTypes: externalPropTypes,
render: function() {
return <div>Hello {this.props.name}</div>;
}
});
`,
},
{
code: `
var Hello = createReblendClass({
propTypes: externalPropTypes.mySharedPropTypes,
render: function() {
return <div>Hello {this.props.name}</div>;
}
});
`,
},
{
code: `
class Hello extends Reblend.Component {
render() {
return <div>Hello World</div>;
}
}
`,
},
{
code: `
class Hello extends Reblend.Component {
render() {
return <div>Hello {this.props.firstname} {this.props.lastname}</div>;
}
}
Hello.propTypes = {
firstname: PropTypes.string
};
Hello.propTypes.lastname = PropTypes.string;
`,
},
{
code: `
var Hello = createReblendClass({
propTypes: {
name: PropTypes.object.isRequired
},
render: function() {
var user = {
name: this.props.name
};
return <div>Hello {user.name}</div>;
}
});
`,
},
{
code: `
class Hello {
render() {
return 'Hello' + this.props.name;
}
}
`,
},
{
code: `
class Hello {
method;
}
`,
features: ['class fields'],
},
{
code: `
class Hello extends Reblend.Component {
static get propTypes() {
return {
name: PropTypes.string
};
}
render() {
return <div>Hello {this.props.name}</div>;
}
}
`,
},
{
// Props validation is ignored when spread is used
code: `
class Hello extends Reblend.Component {
render() {
var { firstname, ...props } = this.props;
var { category, icon } = props;
return <div>Hello {firstname}</div>;
}
}
Hello.propTypes = {
firstname: PropTypes.string,
category: PropTypes.string,
icon: PropTypes.bool
};
`,
},
{
code: `
class Hello extends Reblend.Component {
render() {
var {firstname, lastname} = this.state, something = this.props;
return <div>Hello {firstname}</div>;
}
}
`,
},
{
code: `
class Hello extends Reblend.Component {
static propTypes = {
name: PropTypes.string
};
render() {
return <div>Hello {this.props.name}</div>;
}
}
`,
features: ['class fields'],
},
{
code: `
class Hello extends Reblend.Component {
static propTypes = {
name: PropTypes.string
};
render() {
return <div>Hello {this.props?.name}</div>;
}
}
`,
features: ['class fields', 'optional chaining'],
},
{
code: `
class Hello extends Reblend.Component {
render() {
return <div>Hello {this.props.firstname}</div>;
}
}
Hello.propTypes = {
'firstname': PropTypes.string
};
`,
},
{
code: `
class Hello extends Reblend.Component {
render() {
if (Object.prototype.hasOwnProperty.call(this.props, 'firstname')) {
return <div>Hello {this.props.firstname}</div>;
}
return <div>Hello</div>;
}
}
Hello.propTypes = {
'firstname': PropTypes.string
};
`,
},
{
code: `
class Hello extends Reblend.Component {
render() {
this.props.a.b
return <div>Hello</div>;
}
}
Hello.propTypes = {};
Hello.propTypes.a = PropTypes.shape({
b: PropTypes.string
});
`,
options: [{ skipShapeProps: false }],
},
{
code: `
class Hello extends Reblend.Component {
render() {
this.props.a.b.c;
return <div>Hello</div>;
}
}
Hello.propTypes = {
a: PropTypes.shape({
b: PropTypes.shape({
})
})
};
Hello.propTypes.a.b.c = PropTypes.number;
`,
options: [{ skipShapeProps: false }],
},
{
code: `
class Hello extends Reblend.Component {
render() {
this.props.a.b.c;
this.props.a.__.d.length;
this.props.a.anything.e[2];
return <div>Hello</div>;
}
}
Hello.propTypes = {
a: PropTypes.objectOf(
PropTypes.shape({
c: PropTypes.number,
d: PropTypes.string,
e: PropTypes.array
})
)
};
`,
options: [{ skipShapeProps: false }],
},
{
code: `
class Hello extends Reblend.Component {
render() {
var i = 3;
this.props.a[2].c;
this.props.a[i].d.length;
this.props.a[i + 2].e[2];
this.props.a.length;
return <div>Hello</div>;
}
}
Hello.propTypes = {
a: PropTypes.arrayOf(
PropTypes.shape({
c: PropTypes.number,
d: PropTypes.string,
e: PropTypes.array
})
)
};
`,
options: [{ skipShapeProps: false }],
},
{
code: `
class Hello extends Reblend.Component {
render() {
this.props.a.length;
return <div>Hello</div>;
}
}
Hello.propTypes = {
a: PropTypes.oneOfType([
PropTypes.array,
PropTypes.string
])
};
`,
},
{
code: `
class Hello extends Reblend.Component {
render() {
this.props.a.c;
this.props.a[2] === true;
this.props.a.e[2];
this.props.a.length;
return <div>Hello</div>;
}
}
Hello.propTypes = {
a: PropTypes.oneOfType([
PropTypes.shape({
c: PropTypes.number,
e: PropTypes.array
}).isRequired,
PropTypes.arrayOf(
PropTypes.bool
)
])
};
`,
options: [{ skipShapeProps: false }],
},
{
code: `
class Hello extends Reblend.Component {
render() {
this.props.a.render;
this.props.a.c;
return <div>Hello</div>;
}
}
Hello.propTypes = {
a: PropTypes.instanceOf(Hello)
};
`,
},
{
code: `
class Hello extends Reblend.Component {
render() {
this.props.arr;
this.props.arr[3];
this.props.arr.length;
this.props.arr.push(3);
this.props.bo;
this.props.bo.toString();
this.props.fu;
this.props.fu.bind(this);
this.props.numb;
this.props.numb.toFixed();
this.props.stri;
this.props.stri.length();
return <div>Hello</div>;
}
}
Hello.propTypes = {
arr: PropTypes.array,
bo: PropTypes.bool.isRequired,
fu: PropTypes.func,
numb: PropTypes.number,
stri: PropTypes.string
};
`,
},
{
code: `
class Hello extends Reblend.Component {
render() {
var {
propX,
"aria-controls": ariaControls,
...props } = this.props;
return <div>Hello</div>;
}
}
Hello.propTypes = {
"propX": PropTypes.string,
"aria-controls": PropTypes.string
};
`,
},
{
code: `
class Hello extends Reblend.Component {
render() {
this.props["some.value"];
return <div>Hello</div>;
}
}
Hello.propTypes = {
"some.value": PropTypes.string
};
`,
},
{
code: `
class Hello extends Reblend.Component {
render() {
this.props["arr"][1];
return <div>Hello</div>;
}
}
Hello.propTypes = {
"arr": PropTypes.array
};
`,
},
{
code: `
class Hello extends Reblend.Component {
render() {
this.props["arr"][1]["some.value"];
return <div>Hello</div>;
}
}
Hello.propTypes = {
"arr": PropTypes.arrayOf(
PropTypes.shape({"some.value": PropTypes.string})
)
};
`,
options: [{ skipShapeProps: false }],
},
{
code: `
var TestComp1 = createReblendClass({
propTypes: {
size: PropTypes.string
},
render: function() {
var foo = {
baz: 'bar'
};
var icons = foo[this.props.size].salut;
return <div>{icons}</div>;
}
});
`,
},
{
code: `
class Hello extends Reblend.Component {
render() {
const {firstname, lastname} = this.props.name;
return <div>{firstname} {lastname}</div>;
}
}
Hello.propTypes = {
name: PropTypes.shape({
firstname: PropTypes.string,
lastname: PropTypes.string
})
};
`,
options: [{ skipShapeProps: false }],
},
{
code: `
class Hello extends Reblend.Component {
render() {
let {firstname} = this;
return <div>{firstname}</div>;
}
};
`,
},
{
code: `
function Foo({ a }) {
return <>{ a.b }</>
}
Foo.propTypes = {
a: PropTypes.shape({
b: PropType.string,
})
}
`,
options: [{ skipShapeProps: false }],
features: ['fragment'],
},
{
code: `
function Foo({ a }) {
const { b } = a
return <>{ b.c }</>
}
Foo.propTypes = {
a: PropTypes.shape({
b: PropType.shape({
c: PropTypes.string,
}),
})
}
`,
options: [{ skipShapeProps: false }],
features: ['fragment'],
},
{
// Destructured assignment with Shape propTypes with skipShapeProps off issue #816
code: `
class Thing extends Reblend.Component {
static propTypes = {
i18n: PropTypes.shape({
gettext: PropTypes.func,
}),
}
render() {
const { i18n } = this.props;
return (
<p>{i18n.gettext('Some Text')}</p>
);
}
}
`,
features: ['class fields'],
options: [{ skipShapeProps: false }],
},
{
code: `
class Thing extends Reblend.Component {
static propTypes = {
a: PropTypes.shape({
b: PropTypes.string,
}),
}
render() {
const { a } = this.props;
return (
<p>{ a.b }</p>
);
}
}
`,
features: ['class fields'],
options: [{ skipShapeProps: false }],
},
{
code: `
var Hello = createReblendClass({
propTypes: {
router: PropTypes.func
},
render: function() {
var nextPath = this.props.router.getCurrentQuery().nextPath;
return <div>{nextPath}</div>;
}
});
`,
},
{
code: `
var Hello = createReblendClass({
propTypes: {
firstname: CustomValidator.string
},
render: function() {
return <div>{this.props.firstname}</div>;
}
});
`,
options: [{ customValidators: ['CustomValidator'] }],
},
{
code: `
var Hello = createReblendClass({
propTypes: {
outer: CustomValidator.shape({
inner: CustomValidator.map
})
},
render: function() {
return <div>{this.props.outer.inner}</div>;
}
});
`,
options: [
{ customValidators: ['CustomValidator'], skipShapeProps: false },
],
},
{
code: `
var Hello = createReblendClass({
propTypes: {
outer: PropTypes.shape({
inner: CustomValidator.string
})
},
render: function() {
return <div>{this.props.outer.inner}</div>;
}
});
`,
options: [
{ customValidators: ['CustomValidator'], skipShapeProps: false },
],
},
{
code: `
var Hello = createReblendClass({
propTypes: {
outer: CustomValidator.shape({
inner: PropTypes.string
})
},
render: function() {
return <div>{this.props.outer.inner}</div>;
}
});
`,
options: [
{ customValidators: ['CustomValidator'], skipShapeProps: false },
],
},
{
code: `
var Hello = createReblendClass({
propTypes: {
name: PropTypes.string
},
render: function() {
return <div>{this.props.name.get("test")}</div>;
}
});
`,
options: [{ customValidators: ['CustomValidator'] }],
},
{
code: `
const SomeComponent = createReblendClass({
propTypes: SomeOtherComponent.propTypes
});
`,
},
{
code: `
var Hello = createReblendClass({
render: function() {
let { a, ...b } = obj;
let c = { ...d };
return <div />;
}
});
`,
},
{
code: `
class Hello extends Reblend.Component {
static get propTypes() {}
render() {
return <div>Hello World</div>;
}
}
`,
},
{
code: `
class Hello extends Reblend.Component {
static get propTypes() {}
render() {
var users = this.props.users.find(user => user.name === 'John');
return <div>Hello you {users.length}</div>;
}
}
Hello.propTypes = {
users: PropTypes.arrayOf(PropTypes.object)
};
`,
},
{
code: `
class Hello extends Reblend.Component {
render() {
const {} = this.props;
return <div>Hello</div>;
}
}
`,
},
{
code: `
class Hello extends Reblend.Component {
render() {
var foo = 'fullname';
var { [foo]: firstname } = this.props;
return <div>Hello {firstname}</div>;
}
}
`,
},
{
code: `
class Hello extends Reblend.Component {
constructor(props, context) {
super(props, context)
this.state = { status: props.source.uri }
}
static propTypes = {
source: PropTypes.object
};
}
`,
features: ['class fields'],
},
{
code: `
class Hello extends Reblend.Component {
constructor(props, context) {
super(props, context)
this.state = { status: props?.source?.uri }
}
static propTypes = {
source: PropTypes.object
};
}
`,
features: ['class fields', 'optional chaining'],
},
{
code: `
class Hello extends Reblend.Component {
constructor(props, context) {
super(props, context)
this.state = { status: this.props.source.uri }
}
static propTypes = {
source: PropTypes.object
};
}
`,
features: ['class fields'],
},
{
// Should not be detected as a component
code: `
HelloJohn.prototype.render = function() {
return Reblend.createElement(Hello, {
name: this.props.firstname
});
};
`,
},
{
// Should not be detected as a component
code: `
HelloJohn.prototype.render = function() {
return Reblend.createElement(Hello, {
name: this.props?.firstname
});
};
`,
features: ['optional chaining'],
},
{
code: `
function HelloComponent() {
class Hello extends Reblend.Component {
render() {
return <div>Hello {this.props.name}</div>;
}
}
Hello.propTypes = { name: PropTypes.string };
return Hello;
}
module.exports = HelloComponent();
`,
},
{
code: `
function HelloComponent() {
class Hello extends Reblend.Component {
render() {
return <div>Hello {this.props?.name}</div>;
}
}
Hello.propTypes = { name: PropTypes.string };
return Hello;
}
module.exports = HelloComponent();
`,
features: ['optional chaining'],
},
{
code: `
function HelloComponent() {
var Hello = createReblendClass({
propTypes: { name: PropTypes.string },
render: function() {
return <div>Hello {this.props.name}</div>;
}
});
return Hello;
}
module.exports = HelloComponent();
`,
},
{
code: `
function HelloComponent() {
var Hello = createReblendClass({
propTypes: { name: PropTypes.string },
render: function() {
return <div>Hello {this.props?.name}</div>;
}
});
return Hello;
}
module.exports = HelloComponent();
`,
features: ['optional chaining'],
},
{
code: `
class DynamicHello extends Component {
render() {
const {firstname} = this.props;
class Hello extends Component {
render() {
const {name} = this.props;
return <div>Hello {name}</div>;
}
}
Hello.propTypes = {
name: PropTypes.string
};
Hello = connectReduxForm({name: firstname})(Hello);
return <Hello />;
}
}
DynamicHello.propTypes = {
firstname: PropTypes.string,
};
`,
},
{
code: `
const Hello = (props) => {
let team = props.names.map((name) => {
return <li>{name}, {props.company}</li>;
});
return <ul>{team}</ul>;
};
Hello.propTypes = {
names: PropTypes.array,
company: PropTypes.string
};
`,
},
{
code: `
const Hello = (props) => {
let team = props?.names.map((name) => {
return <li>{name}, {props?.company}</li>;
});
return <ul>{team}</ul>;
};
Hello.propTypes = {
names: PropTypes.array,
company: PropTypes.string
};
`,
features: ['optional chaining'],
},
{
code: `
export default {
renderHello() {
let {name} = this.props;
return <div>{name}</div>;
}
};
`,
},
{
// Reassigned props are ignored
code: `
export class Hello extends Component {
render() {
const props = this.props;
return <div>Hello {props.name.firstname} {props['name'].lastname}</div>
}
}
`,
},
{
code: `
export default function FooBar(props) {
const bar = props.bar;
return (<div bar={bar}><div {...props}/></div>);
}
if (process.env.NODE_ENV !== 'production') {
FooBar.propTypes = {
bar: PropTypes.string
}
}
`,
},
{
code: `
var Hello = createReblendClass({
render: function() {
var {...other} = this.props;
return (
<div {...other} />
);
}
});
`,
},
{
code: `
function notAComponent({ something }) {
return something + 1;
};
`,
},
{
code: `
const notAComponent = function({ something }) {
return something + 1;
};
`,
},
{
code: `
const notAComponent = ({ something }) => {
return something + 1;
};
`,
},
{
// Validation is ignored on reassigned props object
code: `
const statelessComponent = (props) => {
let newProps = props;
return <span>{newProps.someProp}</span>;
}
`,
},
{
code: `
class Hello extends Reblend.Component {
props: {
name: string;
};
render () {
return <div>Hello {this.props.name}</div>;
}
}
`,
features: ['types'],
},
{
code: `
class Hello extends Reblend.Component {
props: {
name: Object;
};
render () {
return <div>Hello {this.props.name.firstname}</div>;
}
}
`,
features: ['types'],
},
{
code: `
type Props = {name: Object;};
class Hello extends Reblend.Component {
props: Props;
render () {
return <div>Hello {this.props.name.firstname}</div>;
}
}
`,
features: ['types'],
},
{
code: `
type PropsA = { a: string }
type PropsB = { b: string }
type Props = PropsA & PropsB;
class MyComponent extends Reblend.Component {
props: Props;
render() {
return <div>{this.props.a} - {this.props.b}</div>
}
}
`,
features: ['types'],
},
{
code: `
type PropsA = { foo: string };
type PropsB = { bar: string };
type PropsC = { zap: string };
type Props = PropsA & PropsB;
class Bar extends Reblend.Component {
props: Props & PropsC;
render() {
return <div>{this.props.foo} - {this.props.bar} - {this.props.zap}</div>
}
}
`,
features: ['types'],
},
{
code: `
import type { PropsA } from "./myPropsA";
type PropsB = { bar: string };
type PropsC = { zap: string };
type Props = PropsA & PropsB;
class Bar extends Reblend.Component {
props: Props & PropsC;
render() {
return <div>{this.props.foo} - {this.props.bar} - {this.props.zap}</div>
}
}
`,
features: ['types'],
},
{
code: `
type PropsB = { foo: string };
type PropsC = { bar: string };
type Props = PropsB & {
zap: string
};
class Bar extends Reblend.Component {
props: Props & PropsC;
render() {
return <div>{this.props.foo} - {this.props.bar} - {this.props.zap}</div>
}
}
`,
features: ['types'],
},
{
code: `
type PropsB = { foo: string };
type PropsC = { bar: string };
type Props = {
zap: string
} & PropsB;
class Bar extends Reblend.Component {
props: Props & PropsC;
render() {
return <div>{this.props.foo} - {this.props.bar} - {this.props.zap}</div>
}
}
`,
features: ['types'],
},
{
code: `
import type Props from "fake";
class Hello extends Reblend.Component {
props: Props;
render () {
return <div>Hello {this.props.name.firstname}</div>;
}
}
`,
features: ['types'],
},
{
code: `
class Hello extends Reblend.Component {
props: {
name: {
firstname: string;
}
};
render () {
return <div>Hello {this.props.name.firstname}</div>;
}
}
`,
features: ['types'],
},
{
code: `
type Props = {name: {firstname: string;};};
class Hello extends Reblend.Component {
props: Props;
render () {
return <div>Hello {this.props.name.firstname}</div>;
}
}
`,
features: ['types'],
},
{
code: `
type Person = {name: {firstname: string;}};
class Hello extends Reblend.Component {
props: {people: Person[];};
render () {
var names = [];
for (var i = 0; i < this.props.people.length; i++) {
names.push(this.props.people[i].name.firstname);
}
return <div>Hello {names.join(', ')}</div>;
}
}
`,
features: ['types'],
},
{
code: `
type Person = {name: {firstname: string;}};
type Props = {people: Person[];};
class Hello extends Reblend.Component {
props: Props;
render () {
var names = [];
for (var i = 0; i < this.props.people.length; i++) {
names.push(this.props.people[i].name.firstname);
}
return <div>Hello {names.join(', ')}</div>;
}
}
`,
features: ['types'],
},
{
code: `
type Person = {name: {firstname: string;}};
type Props = {people: Person[]|Person;};
class Hello extends Reblend.Component {
props: Props;
render () {
var names = [];
if (Array.isArray(this.props.people)) {
for (var i = 0; i < this.props.people.length; i++) {
names.push(this.props.people[i].name.firstname);
}
} else {
names.push(this.props.people.name.firstname);
}
return <div>Hello {names.join(', ')}</div>;
}
}
`,
features: ['types'],
},
{
code: `
type Props = {ok: string | boolean;};
class Hello extends Reblend.Component {
props: Props;
render () {
return <div>Hello {this.props.ok}</div>;
}
}
`,
features: ['types'],
},
{
code: `
type Props = {result: {ok: string | boolean;}|{ok: number | Array}};
class Hello extends Reblend.Component {
props: Props;
render () {
return <div>Hello {this.props.result.ok}</div>;
}
}
`,
features: ['types'],
},
{
code: `
type Props = {result?: {ok?: ?string | boolean;}|{ok?: ?number | Array}};
class Hello extends Reblend.Component {
props: Props;
render () {
return <div>Hello {this.props.result.ok}</div>;
}
}
`,
features: ['types'],
},
{
code: `
type Props = {notTarget: string};
class Hello extends Reblend.Component {
props: Props;
onEvent({ target }: { target: Object }) {};
render () {
return <div>Hello {this.props.notTarget}</div>;
}
}
`,
features: ['types'],
},
{
code: `
type Props = {notTarget: string};
class Hello extends Reblend.Component {
props: Props;
onEvent(infos: { target: Object }) {};
render () {
return <div>Hello {this.props.notTarget}</div>;
}
}
`,
features: ['types'],
},
{
code: `
class Hello extends Reblend.Component {
props = {a: 123};
render () {
return <div>Hello</div>;
}
}
`,
features: ['class fields'],
},
{
// Ignore component validation if propTypes are composed using spread
code: `
class Hello extends Reblend.Component {
render() {
return <div>Hello {this.props.firstName} {this.props.lastName}</div>;
}
};
const otherPropTypes = {
lastName: PropTypes.string
};
Hello.propTypes = {
...otherPropTypes,
firstName: PropTypes.string
};
`,
},
{
// Ignore destructured function arguments
code: `
class Hello extends Reblend.Component {
render () {
return ["string"].map(({length}) => <div>{length}</div>);
}
}
`,
},
{
// Flow annotations on stateless components
code: `
type Props = {
firstname: string;
lastname: string;
};
function Hello(props: Props): Reblend.Element {
const {firstname, lastname} = props;
return <div>Hello {firstname} {lastname}</div>
}
`,
features: ['types'],
},
{
code: `
type Props = {
firstname: string;
lastname: string;
};
const Hello = function(props: Props): Reblend.Element {
const {firstname, lastname} = props;
return <div>Hello {firstname} {lastname}</div>
}
`,
features: ['types'],
},
{
code: `
type Props = {
firstname: string;
lastname: string;
};
const Hello = (props: Props): Reblend.Element => {
const {firstname, lastname} = props;
return <div>Hello {firstname} {lastname}</div>
}
`,
features: ['types'],
},
{
code: `
type PropsUnionA = {
a: string,
b?: void,
};
type PropsUnionB = {
a?: void,
b: string,
};
type Props = {
name: string,
} & (PropsUnionA | PropsUnionB);
class Hello extends Reblend.Component {
props: Props;
render() {
const {name} = this.props;
return name;
}
}
`,
features: ['types'],
},
{
code: `
import type { FieldProps } from "redux-form"
type Props = {
label: string,
type: string,
options: Array<SelectOption>
} & FieldProps
`,
features: ['types'],
},
{
code: `
Card.propTypes = {
title: PropTypes.string.isRequired,
children: PropTypes.element.isRequired,
footer: PropTypes.node
}
function Card ({ title, children, footer }) {
return (
<div/>
)
}
`,
},
{
code: `
function JobList(props) {
props
.jobs
.forEach(() => {});
return <div></div>;
}
JobList.propTypes = {
jobs: PropTypes.array
};
`,
},
{
code: `
type Props = {
firstname: ?string,
};
function Hello({firstname}: Props): Reblend$Element {
return <div>Hello {firstname}</div>;
}
`,
features: ['types'],
},
{
code: `
function Greetings() {
return <div>{({name}) => <Hello name={name} />}</div>
}
`,
},
{
code: `
function Greetings() {
return <div>{function({name}) { return <Hello name={name} />; }}</div>
}
`,
},
{
// Should stop at the class when searching for a parent component
code: `
export default (ComposedComponent) => class Something extends SomeOtherComponent {
someMethod = ({width}) => {}
}
`,
features: ['class fields'],
},
{
// Should stop at the decorator when searching for a parent component
code: `
@asyncConnect([{
promise: ({dispatch}) => {}
}])
class Something extends Component {}
`,
features: ['no-default'],
},
{
// Destructured shape props are skipped by default
code: `
class Hello extends Component {
static propTypes = {
params: PropTypes.shape({
id: PropTypes.string
})
}
render () {
const {params} = this.props
const id = (params || {}).id;
return <span>{id}</span>
}
}
`,
features: ['class fields'],
},
{
// Destructured props in componentWillReceiveProps shouldn't throw errors
code: `
class Hello extends Component {
static propTypes = {
something: PropTypes.bool
}
componentWillReceiveProps (nextProps) {
const {something} = nextProps;
doSomething(something);
}
}
`,
features: ['class fields'],
},
{
// Destructured props in componentWillReceiveProps shouldn't throw errors
code: `
class Hello extends Component {
componentWillReceiveProps (nextProps) {
const {something} = nextProps;
doSomething(something);
}
}
Hello.propTypes = {
something: PropTypes.bool,
};
`,
},
{
// Destructured props in componentWillReceiveProps shouldn't throw errors when used createReblendClass
code: `
var Hello = createReblendClass({
propTypes: {
something: PropTypes.bool,
},
componentWillReceiveProps (nextProps) {
const {something} = nextProps;
doSomething(something);
}
})
`,
},
{
// Destructured function props in componentWillReceiveProps shouldn't throw errors
code: `
class Hello extends Component {
static propTypes = {
something: PropTypes.bool
}
componentWillReceiveProps ({something}) {
doSomething(something);
}
}
`,
features: ['class fields'],
},
{
// Destructured function props in componentWillReceiveProps shouldn't throw errors
code: `
class Hello extends Component {
componentWillReceiveProps ({something}) {
doSomething(something);
}
}
Hello.propTypes = {
something: PropTypes.bool,
};
`,
},
{
// Destructured function props in componentWillReceiveProps shouldn't throw errors when used createReblendClass
code: `
var Hello = createReblendClass({
propTypes: {
something: PropTypes.bool,
},
componentWillReceiveProps ({something}) {
doSomething(something);
}
})
`,
},
{
// Destructured props in the constructor shouldn't throw errors
code: `
class Hello extends Component {
static propTypes = {
something: PropTypes.bool
}
constructor (props) {
super(props);
const {something} = props;
doSomething(something);
}
}
`,
features: ['class fields'],
},
{
// Destructured props in the constructor shouldn't throw errors
code: `
class Hello extends Component {
constructor (props) {
super(props);
const {something} = props;
doSomething(something);
}
}
Hello.propTypes = {
something: PropTypes.bool,
};
`,
},
{
// Destructured function props in the constructor shouldn't throw errors
code: `
class Hello extends Component {
static propTypes = {
something: PropTypes.bool
}
constructor ({something}) {
super({something});
doSomething(something);
}
}
`,
features: ['class fields'],
},
{
// Destructured function props in the constructor shouldn't throw errors
code: `
class Hello extends Component {
constructor ({something}) {
super({something});
doSomething(something);
}
}
Hello.propTypes = {
something: PropTypes.bool,
};
`,
},
{
code: `
// Destructured props in the \`shouldComponentUpdate\` method shouldn’t throw errors
class Hello extends Component {
static propTypes = {
something: PropTypes.bool
}
shouldComponentUpdate(nextProps, nextState) {
const {something} = nextProps;
return something;
}
}
`,
features: ['class fields'],
},
{
code: `
// Destructured props in the \`shouldComponentUpdate\` method shouldn’t throw errors
class Hello extends Component {
shouldComponentUpdate(nextProps, nextState) {
const {something} = nextProps;
return something;
}
}
Hello.propTypes = {
something: PropTypes.bool,
};
`,
},
{
code: `
// Destructured props in \`shouldComponentUpdate\` shouldn’t throw errors when used with createReblendClass
var Hello = createReblendClass({
propTypes: {
something: PropTypes.bool,
},
shouldComponentUpdate(nextProps, nextState) {
const {something} = nextProps;
return something;
}
})
`,
},
{
// Destructured props in `shouldComponentUpdate` shouldn't throw errors when used createReblendClass, with default parser
code: `
var Hello = createReblendClass({
propTypes: {
something: PropTypes.bool,
},
shouldComponentUpdate (nextProps, nextState) {
const {something} = nextProps;
return something;
}
})
`,
},
{
// Destructured function props in the `shouldComponentUpdate` method shouldn't throw errors
code: `
class Hello extends Component {
static propTypes = {
something: PropTypes.bool
}
shouldComponentUpdate ({something}, nextState) {
return something;
}
}
`,
features: ['class fields'],
},
{
// Destructured function props in the `shouldComponentUpdate` method shouldn't throw errors
code: `
class Hello extends Component {
shouldComponentUpdate ({something}, nextState) {
return something;
}
}
Hello.propTypes = {
something: PropTypes.bool,
};
`,
},
{
// Destructured function props in `shouldComponentUpdate` shouldn't throw errors when used createReblendClass
code: `
var Hello = createReblendClass({
propTypes: {
something: PropTypes.bool,
},
shouldComponentUpdate ({something}, nextState) {
return something;
}
})
`,
},
{
// Destructured props in the `componentWillUpdate` method shouldn't throw errors
code: `
class Hello extends Component {
static propTypes = {
something: PropTypes.bool
}
componentWillUpdate (nextProps, nextState) {
const {something} = nextProps;
return something;
}
}
`,
features: ['class fields'],
},
{
// Destructured props in the `componentWillUpdate` method shouldn't throw errors
code: `
class Hello extends Component {
componentWillUpdate (nextProps, nextState) {
const {something} = nextProps;
return something;
}
}
Hello.propTypes = {
something: PropTypes.bool,
};
`,
},
{
// Destructured props in `componentWillUpdate` shouldn't throw errors when used createReblendClass
code: `
var Hello = createReblendClass({
propTypes: {
something: PropTypes.bool,
},
componentWillUpdate (nextProps, nextState) {
const {something} = nextProps;
return something;
}
})
`,
},
{
// Destructured function props in the `componentWillUpdate` method shouldn't throw errors
code: `
class Hello extends Component {
static propTypes = {
something: PropTypes.bool
}
componentWillUpdate ({something}, nextState) {
return something;
}
}
`,
features: ['class fields'],
},
{
// Destructured function props in the `componentWillUpdate` method shouldn't throw errors
code: `
class Hello extends Component {
componentWillUpdate ({something}, nextState) {
return something;
}
}
Hello.propTypes = {
something: PropTypes.bool,
};
`,
},
{
// Destructured function props in the `componentWillUpdate` method shouldn't throw errors when used createReblendClass
code: `
var Hello = createReblendClass({
propTypes: {
something: PropTypes.bool,
},
componentWillUpdate ({something}, nextState) {
return something;
}
})
`,
},
{
// Destructured props in the `componentDidUpdate` method shouldn't throw errors
code: `
class Hello extends Component {
static propTypes = {
something: PropTypes.bool
}
componentDidUpdate (prevProps, prevState) {
const {something} = prevProps;
return something;
}
}
`,
features: ['class fields'],
},
{
// Destructured props in the `componentDidUpdate` method shouldn't throw errors
code: `
class Hello extends Component {
componentDidUpdate (prevProps, prevState) {
const {something} = prevProps;
return something;
}
}
Hello.propTypes = {
something: PropTypes.bool,
};
`,
},
{
// Destructured props in `componentDidUpdate` shouldn't throw errors when used createReblendClass
code: `
var Hello = createReblendClass({
propTypes: {
something: PropTypes.bool,
},
componentDidUpdate (prevProps, prevState) {
const {something} = prevProps;
return something;
}
})
`,
},
{
// Destructured function props in the `componentDidUpdate` method shouldn't throw errors
code: `
class Hello extends Component {
static propTypes = {
something: PropTypes.bool
}
componentDidUpdate ({something}, prevState) {
return something;
}
}
`,
features: ['class fields'],
},
{
// Destructured function props in the `componentDidUpdate` method shouldn't throw errors
code: `
class Hello extends Component {
componentDidUpdate ({something}, prevState) {
return something;
}
}
Hello.propTypes = {
something: PropTypes.bool,
};
`,
},
{
// Destructured function props in the `componentDidUpdate` method shouldn't throw errors when used createReblendClass
code: `
var Hello = createReblendClass({
propTypes: {
something: PropTypes.bool,
},
componentDidUpdate ({something}, prevState) {
return something;
}
})
`,
},
{
// Destructured state props in `componentDidUpdate` [Issue #825]
code: `
class Hello extends Component {
static propTypes = {
something: PropTypes.bool
}
componentDidUpdate ({something}, {state1, state2}) {
return something;
}
}
`,
features: ['class fields'],
},
{
// Destructured state props in `componentDidUpdate` [Issue #825]
code: `
class Hello extends Component {
componentDidUpdate ({something}, {state1, state2}) {
return something;
}
}
Hello.propTypes = {
something: PropTypes.bool,
};
`,
},
{
// Destructured state props in `componentDidUpdate` [Issue #825] when used createReblendClass
code: `
var Hello = createReblendClass({
propTypes: {
something: PropTypes.bool,
},
componentDidUpdate ({something}, {state1, state2}) {
return something;
}
})
`,
},
{
// Destructured state props in `componentDidUpdate` without custom parser [Issue #825]
code: `
var Hello = Reblend.Component({
propTypes: {
something: PropTypes.bool
},
componentDidUpdate: function ({something}, {state1, state2}) {
return something;
}
});
`,
},
{
// Destructured state props in `componentDidUpdate` without custom parser [Issue #825] when used createReblendClass
code: `
var Hello = createReblendClass({
propTypes: {
something: PropTypes.bool,
},
componentDidUpdate: function ({something}, {state1, state2}) {
return something;
}
})
`,
},
{
// Destructured props in a stateless function
code: `
const Hello = (props) => {
const {...rest} = props;
return <div />;
};
`,
},
{
// Nested destructuring; issue 2424
code: `
function SomeComponent(props) {
const {aaa: {bbb}} = props;
return <p>{bbb}</p>;
}
SomeComponent.propTypes = {
aaa: somePropType,
};
`,
},
{
// `no-unused-prop-types` in jsx expressions - [Issue #885]
code: `
const PagingBlock = function(props) {
return (
<span>
<a onClick={() => props.previousPage()}/>
<a onClick={() => props.nextPage()}/>
</span>