init source
This commit is contained in:
+121
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* @fileoverview Report missing `key` props in iterators/collection literals.
|
||||
* @author Ben Mosher
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const hasProp = require('jsx-ast-utils/hasProp');
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const pragmaUtil = require('../util/pragma');
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const defaultOptions = {
|
||||
checkFragmentShorthand: false
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Report missing `key` props in iterators/collection literals',
|
||||
category: 'Possible Errors',
|
||||
recommended: true,
|
||||
url: docsUrl('jsx-key')
|
||||
},
|
||||
schema: [{
|
||||
type: 'object',
|
||||
properties: {
|
||||
checkFragmentShorthand: {
|
||||
type: 'boolean',
|
||||
default: defaultOptions.checkFragmentShorthand
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}]
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const options = Object.assign({}, defaultOptions, context.options[0]);
|
||||
const checkFragmentShorthand = options.checkFragmentShorthand;
|
||||
const reactPragma = pragmaUtil.getFromContext(context);
|
||||
const fragmentPragma = pragmaUtil.getFragmentFromContext(context);
|
||||
|
||||
function checkIteratorElement(node) {
|
||||
if (node.type === 'JSXElement' && !hasProp(node.openingElement.attributes, 'key')) {
|
||||
context.report({
|
||||
node,
|
||||
message: 'Missing "key" prop for element in iterator'
|
||||
});
|
||||
} else if (checkFragmentShorthand && node.type === 'JSXFragment') {
|
||||
context.report({
|
||||
node,
|
||||
message: `Missing "key" prop for element in iterator. Shorthand fragment syntax does not support providing keys. Use ${reactPragma}.${fragmentPragma} instead`
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getReturnStatement(body) {
|
||||
return body.filter(item => item.type === 'ReturnStatement')[0];
|
||||
}
|
||||
|
||||
return {
|
||||
JSXElement(node) {
|
||||
if (hasProp(node.openingElement.attributes, 'key')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.parent.type === 'ArrayExpression') {
|
||||
context.report({
|
||||
node,
|
||||
message: 'Missing "key" prop for element in array'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
JSXFragment(node) {
|
||||
if (!checkFragmentShorthand) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.parent.type === 'ArrayExpression') {
|
||||
context.report({
|
||||
node,
|
||||
message: `Missing "key" prop for element in array. Shorthand fragment syntax does not support providing keys. Use ${reactPragma}.${fragmentPragma} instead`
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// Array.prototype.map
|
||||
CallExpression(node) {
|
||||
if (node.callee && node.callee.type !== 'MemberExpression') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.callee && node.callee.property && node.callee.property.name !== 'map') {
|
||||
return;
|
||||
}
|
||||
|
||||
const fn = node.arguments[0];
|
||||
const isFn = fn && fn.type === 'FunctionExpression';
|
||||
const isArrFn = fn && fn.type === 'ArrowFunctionExpression';
|
||||
|
||||
if (isArrFn && (fn.body.type === 'JSXElement' || fn.body.type === 'JSXFragment')) {
|
||||
checkIteratorElement(fn.body);
|
||||
}
|
||||
|
||||
if (isFn || isArrFn) {
|
||||
if (fn.body.type === 'BlockStatement') {
|
||||
const returnStatement = getReturnStatement(fn.body.body);
|
||||
if (returnStatement && returnStatement.argument) {
|
||||
checkIteratorElement(returnStatement.argument);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user