Skip to content

Commit a33bfb1

Browse files
jomastiljharb
authored andcommitted
[New] Change allowed propWrapperFunctions setting values
This change is adapting the `propWrapperFunctions` setting to allow for using objects along side the already present strings. This will help facilitate adding extra attributes to these objects like for exact prop functions. Precursor to #1547.
1 parent 5877629 commit a33bfb1

9 files changed

+105
-17
lines changed

README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,12 @@ You should also specify settings that will be shared across all the plugin rules
4242
"version": "15.0", // React version, default to the latest React stable release
4343
"flowVersion": "0.53" // Flow version
4444
},
45-
"propWrapperFunctions": [ "forbidExtraProps" ] // The names of any functions used to wrap the
46-
// propTypes object, e.g. `forbidExtraProps`.
47-
// If this isn't set, any propTypes wrapped in
48-
// a function will be skipped.
45+
"propWrapperFunctions": [
46+
// The names of any function used to wrap propTypes, e.g. `forbidExtraProps`. If this isn't set, any propTypes wrapped in a function will be skipped.
47+
"forbidExtraProps",
48+
{"property": "freeze", "object": "Object"}
49+
{"property": "myFavoriteWrapper"}
50+
]
4951
}
5052
}
5153
```

lib/rules/boolean-prop-naming.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
const Components = require('../util/Components');
88
const propsUtil = require('../util/props');
99
const docsUrl = require('../util/docsUrl');
10+
const propWrapperUtil = require('../util/propWrapper');
1011

1112
// ------------------------------------------------------------------------------
1213
// Rule Definition
@@ -51,7 +52,6 @@ module.exports = {
5152
const config = context.options[0] || {};
5253
const rule = config.rule ? new RegExp(config.rule) : null;
5354
const propTypeNames = config.propTypeNames || ['bool'];
54-
const propWrapperFunctions = new Set(context.settings.propWrapperFunctions || []);
5555

5656
// Remembers all Flowtype object definitions
5757
const objectTypeAnnotations = new Map();
@@ -171,7 +171,7 @@ module.exports = {
171171
if (!rule || !propsUtil.isPropTypesDeclaration(node)) {
172172
return;
173173
}
174-
if (node.value && node.value.type === 'CallExpression' && propWrapperFunctions.has(sourceCode.getText(node.value.callee))) {
174+
if (node.value && node.value.type === 'CallExpression' && propWrapperUtil.isPropWrapperFunction(context, sourceCode.getText(node.value.callee))) {
175175
checkPropWrapperArguments(node, node.value.arguments);
176176
}
177177
if (node.value && node.value.properties) {
@@ -191,7 +191,7 @@ module.exports = {
191191
return;
192192
}
193193
const right = node.parent.right;
194-
if (right.type === 'CallExpression' && propWrapperFunctions.has(sourceCode.getText(right.callee))) {
194+
if (right.type === 'CallExpression' && propWrapperUtil.isPropWrapperFunction(context, sourceCode.getText(right.callee))) {
195195
checkPropWrapperArguments(component.node, right.arguments);
196196
return;
197197
}

lib/rules/forbid-prop-types.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const variableUtil = require('../util/variable');
77
const propsUtil = require('../util/props');
88
const astUtil = require('../util/ast');
99
const docsUrl = require('../util/docsUrl');
10+
const propWrapperUtil = require('../util/propWrapper');
1011

1112
// ------------------------------------------------------------------------------
1213
// Constants
@@ -48,7 +49,6 @@ module.exports = {
4849
},
4950

5051
create: function(context) {
51-
const propWrapperFunctions = new Set(context.settings.propWrapperFunctions || []);
5252
const configuration = context.options[0] || {};
5353
const checkContextTypes = configuration.checkContextTypes || false;
5454
const checkChildContextTypes = configuration.checkChildContextTypes || false;
@@ -125,7 +125,7 @@ module.exports = {
125125
break;
126126
case 'CallExpression':
127127
const innerNode = node.arguments && node.arguments[0];
128-
if (propWrapperFunctions.has(node.callee.name) && innerNode) {
128+
if (propWrapperUtil.isPropWrapperFunction(context, node.callee.name) && innerNode) {
129129
checkNode(innerNode);
130130
}
131131
break;

lib/rules/jsx-sort-default-props.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
const variableUtil = require('../util/variable');
88
const docsUrl = require('../util/docsUrl');
9+
const propWrapperUtil = require('../util/propWrapper');
910

1011
// ------------------------------------------------------------------------------
1112
// Rule Definition
@@ -35,7 +36,6 @@ module.exports = {
3536
const sourceCode = context.getSourceCode();
3637
const configuration = context.options[0] || {};
3738
const ignoreCase = configuration.ignoreCase || false;
38-
const propWrapperFunctions = new Set(context.settings.propWrapperFunctions || []);
3939

4040
/**
4141
* Get properties name
@@ -134,7 +134,7 @@ module.exports = {
134134
break;
135135
case 'CallExpression':
136136
const innerNode = node.arguments && node.arguments[0];
137-
if (propWrapperFunctions.has(node.callee.name) && innerNode) {
137+
if (propWrapperUtil.isPropWrapperFunction(context, node.callee.name) && innerNode) {
138138
checkNode(innerNode);
139139
}
140140
break;

lib/rules/sort-prop-types.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
const variableUtil = require('../util/variable');
77
const propsUtil = require('../util/props');
88
const docsUrl = require('../util/docsUrl');
9+
const propWrapperUtil = require('../util/propWrapper');
910

1011
// ------------------------------------------------------------------------------
1112
// Rule Definition
@@ -54,7 +55,6 @@ module.exports = {
5455
const ignoreCase = configuration.ignoreCase || false;
5556
const noSortAlphabetically = configuration.noSortAlphabetically || false;
5657
const sortShapeProp = configuration.sortShapeProp || false;
57-
const propWrapperFunctions = new Set(context.settings.propWrapperFunctions || []);
5858

5959
function getKey(node) {
6060
if (node.key && node.key.value) {
@@ -250,7 +250,7 @@ module.exports = {
250250
break;
251251
case 'CallExpression':
252252
const innerNode = node.arguments && node.arguments[0];
253-
if (propWrapperFunctions.has(node.callee.name) && innerNode) {
253+
if (propWrapperUtil.isPropWrapperFunction(context, node.callee.name) && innerNode) {
254254
checkNode(innerNode);
255255
}
256256
break;

lib/util/defaultProps.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ const fromEntries = require('object.fromentries');
77
const astUtil = require('./ast');
88
const propsUtil = require('./props');
99
const variableUtil = require('./variable');
10+
const propWrapperUtil = require('../util/propWrapper');
1011

1112
const QUOTES_REGEX = /^["']|["']$/g;
1213

1314
module.exports = function defaultPropsInstructions(context, components, utils) {
1415
const sourceCode = context.getSourceCode();
15-
const propWrapperFunctions = new Set(context.settings.propWrapperFunctions || []);
1616

1717
/**
1818
* Try to resolve the node passed in to a variable in the current scope. If the node passed in is not
@@ -26,7 +26,7 @@ module.exports = function defaultPropsInstructions(context, components, utils) {
2626
}
2727
if (
2828
node.type === 'CallExpression' &&
29-
propWrapperFunctions.has(node.callee.name) &&
29+
propWrapperUtil.isPropWrapperFunction(context, node.callee.name) &&
3030
node.arguments && node.arguments[0]
3131
) {
3232
return resolveNodeValue(node.arguments[0]);

lib/util/propTypes.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const annotations = require('./annotations');
77
const propsUtil = require('./props');
88
const variableUtil = require('./variable');
99
const versionUtil = require('./version');
10+
const propWrapperUtil = require('../util/propWrapper');
1011

1112
/**
1213
* Checks if we are declaring a props as a generic type in a flow-annotated class.
@@ -76,7 +77,6 @@ module.exports = function propTypesInstructions(context, components, utils) {
7677
const configuration = Object.assign({}, defaults, context.options[0] || {});
7778
const customValidators = configuration.customValidators;
7879
const sourceCode = context.getSourceCode();
79-
const propWrapperFunctions = new Set(context.settings.propWrapperFunctions);
8080

8181
/**
8282
* Returns the full scope.
@@ -522,7 +522,7 @@ module.exports = function propTypesInstructions(context, components, utils) {
522522
break;
523523
case 'CallExpression':
524524
if (
525-
propWrapperFunctions.has(sourceCode.getText(propTypes.callee)) &&
525+
propWrapperUtil.isPropWrapperFunction(context, sourceCode.getText(propTypes.callee)) &&
526526
propTypes.arguments && propTypes.arguments[0]
527527
) {
528528
markPropTypesAsDeclared(node, propTypes.arguments[0]);

lib/util/propWrapper.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/**
2+
* @fileoverview Utility functions for propWrapperFunctions setting
3+
*/
4+
'use strict';
5+
6+
function getPropWrapperFunctions(context) {
7+
return new Set(context.settings.propWrapperFunctions || []);
8+
}
9+
10+
function isPropWrapperFunction(context, name) {
11+
const propWrapperFunctions = getPropWrapperFunctions(context);
12+
const splitName = name.split('.');
13+
return Array.from(propWrapperFunctions).some(func => {
14+
if (splitName.length === 2 && func.object === splitName[0] && func.property === splitName[1]) {
15+
return true;
16+
}
17+
return name === func || func.property === name;
18+
});
19+
}
20+
21+
module.exports = {
22+
getPropWrapperFunctions: getPropWrapperFunctions,
23+
isPropWrapperFunction: isPropWrapperFunction
24+
};

tests/util/propWrapper.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/* eslint-env mocha */
2+
'use strict';
3+
4+
const assert = require('assert');
5+
const propWrapperUtil = require('../../lib/util/propWrapper');
6+
7+
describe('PropWrapperFunctions', () => {
8+
describe('getPropWrapperFunctions', () => {
9+
it('returns set of functions if setting exists', () => {
10+
const propWrapperFunctions = ['Object.freeze', {
11+
property: 'forbidExtraProps'
12+
}];
13+
const context = {
14+
settings: {
15+
propWrapperFunctions: propWrapperFunctions
16+
}
17+
};
18+
assert.deepStrictEqual(propWrapperUtil.getPropWrapperFunctions(context), new Set(propWrapperFunctions));
19+
});
20+
21+
it('returns empty array if no setting', () => {
22+
const context = {
23+
settings: {}
24+
};
25+
assert.deepStrictEqual(propWrapperUtil.getPropWrapperFunctions(context), new Set([]));
26+
});
27+
});
28+
29+
describe('isPropWrapperFunction', () => {
30+
it('with string', () => {
31+
const context = {
32+
settings: {
33+
propWrapperFunctions: ['Object.freeze']
34+
}
35+
};
36+
assert.equal(propWrapperUtil.isPropWrapperFunction(context, 'Object.freeze'), true);
37+
});
38+
39+
it('with Object with object and property keys', () => {
40+
const context = {
41+
settings: {
42+
propWrapperFunctions: [{
43+
property: 'freeze',
44+
object: 'Object'
45+
}]
46+
}
47+
};
48+
assert.equal(propWrapperUtil.isPropWrapperFunction(context, 'Object.freeze'), true);
49+
});
50+
51+
it('with Object with only property key', () => {
52+
const context = {
53+
settings: {
54+
propWrapperFunctions: [{
55+
property: 'forbidExtraProps'
56+
}]
57+
}
58+
};
59+
assert.equal(propWrapperUtil.isPropWrapperFunction(context, 'forbidExtraProps'), true);
60+
});
61+
});
62+
});

0 commit comments

Comments
 (0)