Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better warnings for nested propTypes #27

Merged
merged 1 commit into from
Apr 11, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 16 additions & 15 deletions src/ImmutablePropTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,19 @@ function getPropType(propValue) {
}

function createChainableTypeChecker(validate) {
function checkType(isRequired, props, propName, componentName, location) {
function checkType(isRequired, props, propName, componentName, location, propFullName) {
propFullName = propFullName || propName;
componentName = componentName || ANONYMOUS;
if (props[propName] == null) {
var locationName = location;
if (isRequired) {
return new Error(
`Required ${locationName} \`${propName}\` was not specified in ` +
`Required ${locationName} \`${propFullName}\` was not specified in ` +
`\`${componentName}\`.`
);
}
} else {
return validate(props, propName, componentName, location);
return validate(props, propName, componentName, location, propFullName);
}
}

Expand All @@ -72,12 +73,12 @@ function createChainableTypeChecker(validate) {
}

function createImmutableTypeChecker(immutableClassName, immutableClassTypeValidator) {
function validate(props, propName, componentName, location) {
function validate(props, propName, componentName, location, propFullName) {
var propValue = props[propName];
if(!immutableClassTypeValidator(propValue)) {
var propType = getPropType(propValue);
return new Error(
`Invalid ${location} \`${propName}\` of type \`${propType}\` ` +
`Invalid ${location} \`${propFullName}\` of type \`${propType}\` ` +
`supplied to \`${componentName}\`, expected \`${immutableClassName}\`.`
);
}
Expand All @@ -88,27 +89,27 @@ function createImmutableTypeChecker(immutableClassName, immutableClassTypeValida

function createIterableTypeChecker(typeChecker, immutableClassName, immutableClassTypeValidator) {

function validate(props, propName, componentName, location) {
function validate(props, propName, componentName, location, propFullName) {
var propValue = props[propName];
if (!immutableClassTypeValidator(propValue)) {
var locationName = location;
var propType = getPropType(propValue);
return new Error(
`Invalid ${locationName} \`${propName}\` of type ` +
`Invalid ${locationName} \`${propFullName}\` of type ` +
`\`${propType}\` supplied to \`${componentName}\`, expected an Immutable.js ${immutableClassName}.`
);
}

if (typeof typeChecker !== 'function') {
return new Error(
`Invalid typeChecker supplied to \`${componentName}\` ` +
`for propType \`${propName}\`, expected a function.`
`for propType \`${propFullName}\`, expected a function.`
);
}

var propValues = propValue.toArray();
for (var i = 0, len = propValues.length; i < len; i++) {
var error = typeChecker(propValues, i, componentName, location);
var error = typeChecker(propValues, i, componentName, location, `${propFullName}[${i}]`);
if (error instanceof Error) {
return error;
}
Expand Down Expand Up @@ -146,13 +147,13 @@ function createIterableOfTypeChecker(typeChecker) {
}

function createRecordOfTypeChecker(recordKeys) {
function validate(props, propName, componentName, location) {
function validate(props, propName, componentName, location, propFullName) {
var propValue = props[propName];
var propType = getPropType(propValue);
if (!(propValue instanceof Immutable.Record)) {
var locationName = location;
return new Error(
`Invalid ${locationName} \`${propName}\` of type \`${propType}\` ` +
`Invalid ${locationName} \`${propFullName}\` of type \`${propType}\` ` +
`supplied to \`${componentName}\`, expected an Immutable.js Record.`
);
}
Expand All @@ -162,7 +163,7 @@ function createRecordOfTypeChecker(recordKeys) {
continue;
}
var mutablePropValue = propValue.toObject();
var error = checker(mutablePropValue, key, componentName, location);
var error = checker(mutablePropValue, key, componentName, location, `${propFullName}.${key}`);
if (error) {
return error;
}
Expand All @@ -173,13 +174,13 @@ function createRecordOfTypeChecker(recordKeys) {

// there is some irony in the fact that shapeTypes is a standard hash and not an immutable collection
function createShapeTypeChecker(shapeTypes, immutableClassName = 'Iterable', immutableClassTypeValidator = Immutable.Iterable.isIterable) {
function validate(props, propName, componentName, location) {
function validate(props, propName, componentName, location, propFullName) {
var propValue = props[propName];
var propType = getPropType(propValue);
if (!immutableClassTypeValidator(propValue)) {
var locationName = location;
return new Error(
`Invalid ${locationName} \`${propName}\` of type \`${propType}\` ` +
`Invalid ${locationName} \`${propFullName}\` of type \`${propType}\` ` +
`supplied to \`${componentName}\`, expected an Immutable.js ${immutableClassName}.`
);
}
Expand All @@ -189,7 +190,7 @@ function createShapeTypeChecker(shapeTypes, immutableClassName = 'Iterable', imm
if (!checker) {
continue;
}
var error = checker(mutablePropValue, key, componentName, location);
var error = checker(mutablePropValue, key, componentName, location, `${propFullName}.${key}`);
if (error) {
return error;
}
Expand Down
58 changes: 29 additions & 29 deletions src/__tests__/ImmutablePropTypes-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ describe('ImmutablePropTypes', function() {
typeCheckFail(
PropTypes.listOf(React.PropTypes.number),
Immutable.List([1, 2, 'b']),
'Invalid prop `2` of type `string` supplied to `testComponent`, ' +
'Invalid prop `testProp[2]` of type `string` supplied to `testComponent`, ' +
'expected `number`.'
);
});
Expand All @@ -255,7 +255,7 @@ describe('ImmutablePropTypes', function() {
typeCheckFail(
PropTypes.listOf(React.PropTypes.instanceOf(Thing)),
Immutable.List([new Thing(), 'xyz']),
'Invalid prop `1` of type `String` supplied to `testComponent`, expected instance of `' +
'Invalid prop `testProp[1]` of type `String` supplied to `testComponent`, expected instance of `' +
name + '`.'
);
});
Expand Down Expand Up @@ -335,7 +335,7 @@ describe('ImmutablePropTypes', function() {
typeCheckFail(
PropTypes.stackOf(React.PropTypes.number),
Immutable.Stack([1, 2, 'b']),
'Invalid prop `2` of type `string` supplied to `testComponent`, ' +
'Invalid prop `testProp[2]` of type `string` supplied to `testComponent`, ' +
'expected `number`.'
);
});
Expand All @@ -347,7 +347,7 @@ describe('ImmutablePropTypes', function() {
typeCheckFail(
PropTypes.stackOf(React.PropTypes.instanceOf(Thing)),
Immutable.Stack([new Thing(), 'xyz']),
'Invalid prop `1` of type `String` supplied to `testComponent`, expected instance of `' +
'Invalid prop `testProp[1]` of type `String` supplied to `testComponent`, expected instance of `' +
name + '`.'
);
});
Expand Down Expand Up @@ -432,7 +432,7 @@ describe('ImmutablePropTypes', function() {
typeCheckFail(
PropTypes.mapOf(React.PropTypes.number),
Immutable.Map({ 1: 1, 2: 2, 3: 'b' }),
'Invalid prop `2` of type `string` supplied to `testComponent`, ' +
'Invalid prop `testProp[2]` of type `string` supplied to `testComponent`, ' +
'expected `number`.'
);
});
Expand All @@ -444,7 +444,7 @@ describe('ImmutablePropTypes', function() {
typeCheckFail(
PropTypes.mapOf(React.PropTypes.instanceOf(Thing)),
Immutable.Map({ 1: new Thing(), 2: 'xyz' }),
'Invalid prop `1` of type `String` supplied to `testComponent`, expected instance of `' +
'Invalid prop `testProp[1]` of type `String` supplied to `testComponent`, expected instance of `' +
name + '`.'
);
});
Expand Down Expand Up @@ -529,7 +529,7 @@ describe('ImmutablePropTypes', function() {
typeCheckFail(
PropTypes.orderedMapOf(React.PropTypes.number),
Immutable.OrderedMap({ 1: 1, 2: 2, 3: 'b' }),
'Invalid prop `2` of type `string` supplied to `testComponent`, ' +
'Invalid prop `testProp[2]` of type `string` supplied to `testComponent`, ' +
'expected `number`.'
);
});
Expand All @@ -541,7 +541,7 @@ describe('ImmutablePropTypes', function() {
typeCheckFail(
PropTypes.orderedMapOf(React.PropTypes.instanceOf(Thing)),
Immutable.OrderedMap({ 1: new Thing(), 2: 'xyz' }),
'Invalid prop `1` of type `String` supplied to `testComponent`, expected instance of `' +
'Invalid prop `testProp[1]` of type `String` supplied to `testComponent`, expected instance of `' +
name + '`.'
);
});
Expand Down Expand Up @@ -627,7 +627,7 @@ describe('ImmutablePropTypes', function() {
typeCheckFail(
PropTypes.setOf(React.PropTypes.number),
Immutable.Set([1, 2, 'b']),
'Invalid prop `2` of type `string` supplied to `testComponent`, ' +
'Invalid prop `testProp[2]` of type `string` supplied to `testComponent`, ' +
'expected `number`.'
);
});
Expand All @@ -639,7 +639,7 @@ describe('ImmutablePropTypes', function() {
typeCheckFail(
PropTypes.setOf(React.PropTypes.instanceOf(Thing)),
Immutable.Set([new Thing(), 'xyz' ]),
'Invalid prop `1` of type `String` supplied to `testComponent`, expected instance of `' +
'Invalid prop `testProp[1]` of type `String` supplied to `testComponent`, expected instance of `' +
name + '`.'
);
});
Expand Down Expand Up @@ -719,7 +719,7 @@ describe('ImmutablePropTypes', function() {
typeCheckFail(
PropTypes.orderedSetOf(React.PropTypes.number),
Immutable.OrderedSet([1, 2, 'b']),
'Invalid prop `2` of type `string` supplied to `testComponent`, ' +
'Invalid prop `testProp[2]` of type `string` supplied to `testComponent`, ' +
'expected `number`.'
);
});
Expand All @@ -731,7 +731,7 @@ describe('ImmutablePropTypes', function() {
typeCheckFail(
PropTypes.orderedSetOf(React.PropTypes.instanceOf(Thing)),
Immutable.OrderedSet([new Thing(), 'xyz' ]),
'Invalid prop `1` of type `String` supplied to `testComponent`, expected instance of `' +
'Invalid prop `testProp[1]` of type `String` supplied to `testComponent`, expected instance of `' +
name + '`.'
);
});
Expand Down Expand Up @@ -848,14 +848,14 @@ describe('ImmutablePropTypes', function() {
typeCheckFail(
PropTypes.iterableOf(React.PropTypes.number),
Immutable.List([1, 2, 'b']),
'Invalid prop `2` of type `string` supplied to `testComponent`, ' +
'Invalid prop `testProp[2]` of type `string` supplied to `testComponent`, ' +
'expected `number`.'
);

typeCheckFail(
PropTypes.iterableOf(React.PropTypes.number),
Immutable.Map({ 1: 1, 2: 2, 3: 'b' }),
'Invalid prop `2` of type `string` supplied to `testComponent`, ' +
'Invalid prop `testProp[2]` of type `string` supplied to `testComponent`, ' +
'expected `number`.'
);
});
Expand All @@ -867,14 +867,14 @@ describe('ImmutablePropTypes', function() {
typeCheckFail(
PropTypes.iterableOf(React.PropTypes.instanceOf(Thing)),
Immutable.List([new Thing(), 'xyz']),
'Invalid prop `1` of type `String` supplied to `testComponent`, expected instance of `' +
'Invalid prop `testProp[1]` of type `String` supplied to `testComponent`, expected instance of `' +
name + '`.'
);

typeCheckFail(
PropTypes.iterableOf(React.PropTypes.instanceOf(Thing)),
Immutable.Map({ 1: new Thing(), 2: 'xyz' }),
'Invalid prop `1` of type `String` supplied to `testComponent`, expected instance of `' +
'Invalid prop `testProp[1]` of type `String` supplied to `testComponent`, expected instance of `' +
name + '`.'
);
});
Expand Down Expand Up @@ -984,7 +984,7 @@ describe('ImmutablePropTypes', function() {
typeCheckFail(
PropTypes.recordOf({key: React.PropTypes.number.isRequired}),
new (Immutable.Record({}))(),
'Required prop `key` was not specified in `testComponent`.'
'Required prop `testProp.key` was not specified in `testComponent`.'
);
});

Expand All @@ -995,14 +995,14 @@ describe('ImmutablePropTypes', function() {
secondKey: React.PropTypes.number.isRequired
}),
new (Immutable.Record({}))(),
'Required prop `key` was not specified in `testComponent`.'
'Required prop `testProp.key` was not specified in `testComponent`.'
);
});

it('should warn for invalid key types', function() {
typeCheckFail(PropTypes.recordOf({key: React.PropTypes.number}),
new (Immutable.Record({key: 'abc'}))(),
'Invalid prop `key` of type `string` supplied to `testComponent`, ' +
'Invalid prop `testProp.key` of type `string` supplied to `testComponent`, ' +
'expected `number`.'
);
});
Expand Down Expand Up @@ -1078,7 +1078,7 @@ describe('ImmutablePropTypes', function() {
typeCheckFail(
PropTypes.shape({key: React.PropTypes.number.isRequired}),
Immutable.fromJS({}),
'Required prop `key` was not specified in `testComponent`.'
'Required prop `testProp.key` was not specified in `testComponent`.'
);
});

Expand All @@ -1089,14 +1089,14 @@ describe('ImmutablePropTypes', function() {
secondKey: React.PropTypes.number.isRequired
}),
Immutable.fromJS({}),
'Required prop `key` was not specified in `testComponent`.'
'Required prop `testProp.key` was not specified in `testComponent`.'
);
});

it('should warn for invalid key types', function() {
typeCheckFail(PropTypes.shape({key: React.PropTypes.number}),
Immutable.fromJS({key: 'abc'}),
'Invalid prop `key` of type `string` supplied to `testComponent`, ' +
'Invalid prop `testProp.key` of type `string` supplied to `testComponent`, ' +
'expected `number`.'
);
});
Expand Down Expand Up @@ -1181,7 +1181,7 @@ describe('ImmutablePropTypes', function() {
typeCheckFail(
PropTypes.contains({key: React.PropTypes.number.isRequired}),
Immutable.fromJS({}),
'Required prop `key` was not specified in `testComponent`.'
'Required prop `testProp.key` was not specified in `testComponent`.'
);
});

Expand All @@ -1192,14 +1192,14 @@ describe('ImmutablePropTypes', function() {
secondKey: React.PropTypes.number.isRequired
}),
Immutable.fromJS({}),
'Required prop `key` was not specified in `testComponent`.'
'Required prop `testProp.key` was not specified in `testComponent`.'
);
});

it('should warn for invalid key types', function() {
typeCheckFail(PropTypes.contains({key: React.PropTypes.number}),
Immutable.fromJS({key: 'abc'}),
'Invalid prop `key` of type `string` supplied to `testComponent`, ' +
'Invalid prop `testProp.key` of type `string` supplied to `testComponent`, ' +
'expected `number`.'
);
});
Expand Down Expand Up @@ -1295,7 +1295,7 @@ describe('ImmutablePropTypes', function() {
})).isRequired
}),
Immutable.fromJS({data: [{id: 1}, {}]}),
'Required prop `id` was not specified in `testComponent`.'
'Required prop `testProp.data[1].id` was not specified in `testComponent`.'
);
});

Expand All @@ -1307,7 +1307,7 @@ describe('ImmutablePropTypes', function() {
typeCheckFail(
PropTypes.mapContains({key: React.PropTypes.number.isRequired}),
Immutable.fromJS({}),
'Required prop `key` was not specified in `testComponent`.'
'Required prop `testProp.key` was not specified in `testComponent`.'
);
});

Expand All @@ -1318,14 +1318,14 @@ describe('ImmutablePropTypes', function() {
secondKey: React.PropTypes.number.isRequired
}),
Immutable.fromJS({}),
'Required prop `key` was not specified in `testComponent`.'
'Required prop `testProp.key` was not specified in `testComponent`.'
);
});

it('should warn for invalid key types', function() {
typeCheckFail(PropTypes.mapContains({key: React.PropTypes.number}),
Immutable.fromJS({key: 'abc'}),
'Invalid prop `key` of type `string` supplied to `testComponent`, ' +
'Invalid prop `testProp.key` of type `string` supplied to `testComponent`, ' +
'expected `number`.'
);
});
Expand Down