отчет
This commit is contained in:
3
Lab/node_modules/eslint-plugin-react/lib/rules/boolean-prop-naming.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/boolean-prop-naming.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=boolean-prop-naming.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/boolean-prop-naming.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/boolean-prop-naming.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"boolean-prop-naming.d.ts","sourceRoot":"","sources":["boolean-prop-naming.js"],"names":[],"mappings":"wBAyCW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
426
Lab/node_modules/eslint-plugin-react/lib/rules/boolean-prop-naming.js
generated
vendored
Normal file
426
Lab/node_modules/eslint-plugin-react/lib/rules/boolean-prop-naming.js
generated
vendored
Normal file
@@ -0,0 +1,426 @@
|
||||
/**
|
||||
* @fileoverview Enforces consistent naming for boolean props
|
||||
* @author Ev Haus
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const flatMap = require('array.prototype.flatmap');
|
||||
const values = require('object.values');
|
||||
|
||||
const Components = require('../util/Components');
|
||||
const propsUtil = require('../util/props');
|
||||
const astUtil = require('../util/ast');
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const propWrapperUtil = require('../util/propWrapper');
|
||||
const report = require('../util/report');
|
||||
const eslintUtil = require('../util/eslint');
|
||||
|
||||
const getSourceCode = eslintUtil.getSourceCode;
|
||||
const getText = eslintUtil.getText;
|
||||
|
||||
/**
|
||||
* Checks if prop is nested
|
||||
* @param {Object} prop Property object, single prop type declaration
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function nestedPropTypes(prop) {
|
||||
return (
|
||||
prop.type === 'Property'
|
||||
&& astUtil.isCallExpression(prop.value)
|
||||
);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const messages = {
|
||||
patternMismatch: 'Prop name `{{propName}}` doesn’t match rule `{{pattern}}`',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
category: 'Stylistic Issues',
|
||||
description: 'Enforces consistent naming for boolean props',
|
||||
recommended: false,
|
||||
url: docsUrl('boolean-prop-naming'),
|
||||
},
|
||||
|
||||
messages,
|
||||
|
||||
schema: [{
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
propTypeNames: {
|
||||
items: {
|
||||
type: 'string',
|
||||
},
|
||||
minItems: 1,
|
||||
type: 'array',
|
||||
uniqueItems: true,
|
||||
},
|
||||
rule: {
|
||||
default: '^(is|has)[A-Z]([A-Za-z0-9]?)+',
|
||||
minLength: 1,
|
||||
type: 'string',
|
||||
},
|
||||
message: {
|
||||
minLength: 1,
|
||||
type: 'string',
|
||||
},
|
||||
validateNested: {
|
||||
default: false,
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
type: 'object',
|
||||
}],
|
||||
},
|
||||
|
||||
create: Components.detect((context, components, utils) => {
|
||||
const config = context.options[0] || {};
|
||||
const rule = config.rule ? new RegExp(config.rule) : null;
|
||||
const propTypeNames = config.propTypeNames || ['bool'];
|
||||
|
||||
// Remembers all Flowtype object definitions
|
||||
const objectTypeAnnotations = new Map();
|
||||
|
||||
/**
|
||||
* Returns the prop key to ensure we handle the following cases:
|
||||
* propTypes: {
|
||||
* full: React.PropTypes.bool,
|
||||
* short: PropTypes.bool,
|
||||
* direct: bool,
|
||||
* required: PropTypes.bool.isRequired
|
||||
* }
|
||||
* @param {Object} node The node we're getting the name of
|
||||
* @returns {string | null}
|
||||
*/
|
||||
function getPropKey(node) {
|
||||
// Check for `ExperimentalSpreadProperty` (eslint 3/4) and `SpreadElement` (eslint 5)
|
||||
// so we can skip validation of those fields.
|
||||
// Otherwise it will look for `node.value.property` which doesn't exist and breaks eslint.
|
||||
if (node.type === 'ExperimentalSpreadProperty' || node.type === 'SpreadElement') {
|
||||
return null;
|
||||
}
|
||||
if (node.value && node.value.property) {
|
||||
const name = node.value.property.name;
|
||||
if (name === 'isRequired') {
|
||||
if (node.value.object && node.value.object.property) {
|
||||
return node.value.object.property.name;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
if (node.value && node.value.type === 'Identifier') {
|
||||
return node.value.name;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the given node (prop)
|
||||
* @param {Object} node The node we're getting the name of
|
||||
* @returns {string}
|
||||
*/
|
||||
function getPropName(node) {
|
||||
// Due to this bug https://github.com/babel/babel-eslint/issues/307
|
||||
// we can't get the name of the Flow object key name. So we have
|
||||
// to hack around it for now.
|
||||
if (node.type === 'ObjectTypeProperty') {
|
||||
return getSourceCode(context).getFirstToken(node).value;
|
||||
}
|
||||
|
||||
return node.key.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if prop is declared in flow way
|
||||
* @param {Object} prop Property object, single prop type declaration
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function flowCheck(prop) {
|
||||
return (
|
||||
prop.type === 'ObjectTypeProperty'
|
||||
&& prop.value.type === 'BooleanTypeAnnotation'
|
||||
&& rule.test(getPropName(prop)) === false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if prop is declared in regular way
|
||||
* @param {Object} prop Property object, single prop type declaration
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function regularCheck(prop) {
|
||||
const propKey = getPropKey(prop);
|
||||
return (
|
||||
propKey
|
||||
&& propTypeNames.indexOf(propKey) >= 0
|
||||
&& rule.test(getPropName(prop)) === false
|
||||
);
|
||||
}
|
||||
|
||||
function tsCheck(prop) {
|
||||
if (prop.type !== 'TSPropertySignature') return false;
|
||||
const typeAnnotation = (prop.typeAnnotation || {}).typeAnnotation;
|
||||
return (
|
||||
typeAnnotation
|
||||
&& typeAnnotation.type === 'TSBooleanKeyword'
|
||||
&& rule.test(getPropName(prop)) === false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs recursive check on all proptypes
|
||||
* @param {Array} proptypes A list of Property object (for each proptype defined)
|
||||
* @param {Function} addInvalidProp callback to run for each error
|
||||
*/
|
||||
function runCheck(proptypes, addInvalidProp) {
|
||||
if (proptypes) {
|
||||
proptypes.forEach((prop) => {
|
||||
if (config.validateNested && nestedPropTypes(prop)) {
|
||||
runCheck(prop.value.arguments[0].properties, addInvalidProp);
|
||||
return;
|
||||
}
|
||||
if (flowCheck(prop) || regularCheck(prop) || tsCheck(prop)) {
|
||||
addInvalidProp(prop);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks and mark props with invalid naming
|
||||
* @param {Object} node The component node we're testing
|
||||
* @param {Array} proptypes A list of Property object (for each proptype defined)
|
||||
*/
|
||||
function validatePropNaming(node, proptypes) {
|
||||
const component = components.get(node) || node;
|
||||
const invalidProps = component.invalidProps || [];
|
||||
|
||||
runCheck(proptypes, (prop) => {
|
||||
invalidProps.push(prop);
|
||||
});
|
||||
|
||||
components.set(node, {
|
||||
invalidProps,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports invalid prop naming
|
||||
* @param {Object} component The component to process
|
||||
*/
|
||||
function reportInvalidNaming(component) {
|
||||
component.invalidProps.forEach((propNode) => {
|
||||
const propName = getPropName(propNode);
|
||||
report(context, config.message || messages.patternMismatch, !config.message && 'patternMismatch', {
|
||||
node: propNode,
|
||||
data: {
|
||||
component: propName,
|
||||
propName,
|
||||
pattern: config.rule,
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function checkPropWrapperArguments(node, args) {
|
||||
if (!node || !Array.isArray(args)) {
|
||||
return;
|
||||
}
|
||||
args.filter((arg) => arg.type === 'ObjectExpression').forEach((object) => validatePropNaming(node, object.properties));
|
||||
}
|
||||
|
||||
function getComponentTypeAnnotation(component) {
|
||||
// If this is a functional component that uses a global type, check it
|
||||
if (
|
||||
(component.node.type === 'FunctionDeclaration' || component.node.type === 'ArrowFunctionExpression')
|
||||
&& component.node.params
|
||||
&& component.node.params.length > 0
|
||||
&& component.node.params[0].typeAnnotation
|
||||
) {
|
||||
return component.node.params[0].typeAnnotation.typeAnnotation;
|
||||
}
|
||||
|
||||
if (
|
||||
!component.node.parent
|
||||
|| component.node.parent.type !== 'VariableDeclarator'
|
||||
|| !component.node.parent.id
|
||||
|| component.node.parent.id.type !== 'Identifier'
|
||||
|| !component.node.parent.id.typeAnnotation
|
||||
|| !component.node.parent.id.typeAnnotation.typeAnnotation
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const annotationTypeArguments = propsUtil.getTypeArguments(
|
||||
component.node.parent.id.typeAnnotation.typeAnnotation
|
||||
);
|
||||
if (
|
||||
annotationTypeArguments && (
|
||||
annotationTypeArguments.type === 'TSTypeParameterInstantiation'
|
||||
|| annotationTypeArguments.type === 'TypeParameterInstantiation'
|
||||
)
|
||||
) {
|
||||
return annotationTypeArguments.params.find(
|
||||
(param) => param.type === 'TSTypeReference' || param.type === 'GenericTypeAnnotation'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function findAllTypeAnnotations(identifier, node) {
|
||||
if (node.type === 'TSTypeLiteral' || node.type === 'ObjectTypeAnnotation' || node.type === 'TSInterfaceBody') {
|
||||
const currentNode = [].concat(
|
||||
objectTypeAnnotations.get(identifier.name) || [],
|
||||
node
|
||||
);
|
||||
objectTypeAnnotations.set(identifier.name, currentNode);
|
||||
} else if (
|
||||
node.type === 'TSParenthesizedType'
|
||||
&& (
|
||||
node.typeAnnotation.type === 'TSIntersectionType'
|
||||
|| node.typeAnnotation.type === 'TSUnionType'
|
||||
)
|
||||
) {
|
||||
node.typeAnnotation.types.forEach((type) => {
|
||||
findAllTypeAnnotations(identifier, type);
|
||||
});
|
||||
} else if (
|
||||
node.type === 'TSIntersectionType'
|
||||
|| node.type === 'TSUnionType'
|
||||
|| node.type === 'IntersectionTypeAnnotation'
|
||||
|| node.type === 'UnionTypeAnnotation'
|
||||
) {
|
||||
node.types.forEach((type) => {
|
||||
findAllTypeAnnotations(identifier, type);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Public
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
'ClassProperty, PropertyDefinition'(node) {
|
||||
if (!rule || !propsUtil.isPropTypesDeclaration(node)) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
node.value
|
||||
&& astUtil.isCallExpression(node.value)
|
||||
&& propWrapperUtil.isPropWrapperFunction(
|
||||
context,
|
||||
getText(context, node.value.callee)
|
||||
)
|
||||
) {
|
||||
checkPropWrapperArguments(node, node.value.arguments);
|
||||
}
|
||||
if (node.value && node.value.properties) {
|
||||
validatePropNaming(node, node.value.properties);
|
||||
}
|
||||
if (node.typeAnnotation && node.typeAnnotation.typeAnnotation) {
|
||||
validatePropNaming(node, node.typeAnnotation.typeAnnotation.properties);
|
||||
}
|
||||
},
|
||||
|
||||
MemberExpression(node) {
|
||||
if (!rule || !propsUtil.isPropTypesDeclaration(node)) {
|
||||
return;
|
||||
}
|
||||
const component = utils.getRelatedComponent(node);
|
||||
if (!component || !node.parent.right) {
|
||||
return;
|
||||
}
|
||||
const right = node.parent.right;
|
||||
if (
|
||||
astUtil.isCallExpression(right)
|
||||
&& propWrapperUtil.isPropWrapperFunction(
|
||||
context,
|
||||
getText(context, right.callee)
|
||||
)
|
||||
) {
|
||||
checkPropWrapperArguments(component.node, right.arguments);
|
||||
return;
|
||||
}
|
||||
validatePropNaming(component.node, node.parent.right.properties);
|
||||
},
|
||||
|
||||
ObjectExpression(node) {
|
||||
if (!rule) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Search for the proptypes declaration
|
||||
node.properties.forEach((property) => {
|
||||
if (!propsUtil.isPropTypesDeclaration(property)) {
|
||||
return;
|
||||
}
|
||||
validatePropNaming(node, property.value.properties);
|
||||
});
|
||||
},
|
||||
|
||||
TypeAlias(node) {
|
||||
findAllTypeAnnotations(node.id, node.right);
|
||||
},
|
||||
|
||||
TSTypeAliasDeclaration(node) {
|
||||
findAllTypeAnnotations(node.id, node.typeAnnotation);
|
||||
},
|
||||
|
||||
TSInterfaceDeclaration(node) {
|
||||
findAllTypeAnnotations(node.id, node.body);
|
||||
},
|
||||
|
||||
// eslint-disable-next-line object-shorthand
|
||||
'Program:exit'() {
|
||||
if (!rule) {
|
||||
return;
|
||||
}
|
||||
|
||||
values(components.list()).forEach((component) => {
|
||||
const annotation = getComponentTypeAnnotation(component);
|
||||
|
||||
if (annotation) {
|
||||
let propType;
|
||||
if (annotation.type === 'GenericTypeAnnotation') {
|
||||
propType = objectTypeAnnotations.get(annotation.id.name);
|
||||
} else if (annotation.type === 'ObjectTypeAnnotation' || annotation.type === 'TSTypeLiteral') {
|
||||
propType = annotation;
|
||||
} else if (annotation.type === 'TSTypeReference') {
|
||||
propType = objectTypeAnnotations.get(annotation.typeName.name);
|
||||
} else if (annotation.type === 'TSIntersectionType') {
|
||||
propType = flatMap(annotation.types, (type) => (
|
||||
type.type === 'TSTypeReference'
|
||||
? objectTypeAnnotations.get(type.typeName.name)
|
||||
: type
|
||||
));
|
||||
}
|
||||
|
||||
if (propType) {
|
||||
[].concat(propType).filter(Boolean).forEach((prop) => {
|
||||
validatePropNaming(
|
||||
component.node,
|
||||
prop.properties || prop.members || prop.body
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (component.invalidProps && component.invalidProps.length > 0) {
|
||||
reportInvalidNaming(component);
|
||||
}
|
||||
});
|
||||
|
||||
// Reset cache
|
||||
objectTypeAnnotations.clear();
|
||||
},
|
||||
};
|
||||
}),
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/button-has-type.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/button-has-type.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=button-has-type.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/button-has-type.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/button-has-type.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"button-has-type.d.ts","sourceRoot":"","sources":["button-has-type.js"],"names":[],"mappings":"wBA8BW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
169
Lab/node_modules/eslint-plugin-react/lib/rules/button-has-type.js
generated
vendored
Normal file
169
Lab/node_modules/eslint-plugin-react/lib/rules/button-has-type.js
generated
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* @fileoverview Forbid "button" element without an explicit "type" attribute
|
||||
* @author Filipp Riabchun
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const getProp = require('jsx-ast-utils/getProp');
|
||||
const getLiteralPropValue = require('jsx-ast-utils/getLiteralPropValue');
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const isCreateElement = require('../util/isCreateElement');
|
||||
const report = require('../util/report');
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const optionDefaults = {
|
||||
button: true,
|
||||
submit: true,
|
||||
reset: true,
|
||||
};
|
||||
|
||||
const messages = {
|
||||
missingType: 'Missing an explicit type attribute for button',
|
||||
complexType: 'The button type attribute must be specified by a static string or a trivial ternary expression',
|
||||
invalidValue: '"{{value}}" is an invalid value for button type attribute',
|
||||
forbiddenValue: '"{{value}}" is an invalid value for button type attribute',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Disallow usage of `button` elements without an explicit `type` attribute',
|
||||
category: 'Possible Errors',
|
||||
recommended: false,
|
||||
url: docsUrl('button-has-type'),
|
||||
},
|
||||
|
||||
messages,
|
||||
|
||||
schema: [{
|
||||
type: 'object',
|
||||
properties: {
|
||||
button: {
|
||||
default: optionDefaults.button,
|
||||
type: 'boolean',
|
||||
},
|
||||
submit: {
|
||||
default: optionDefaults.submit,
|
||||
type: 'boolean',
|
||||
},
|
||||
reset: {
|
||||
default: optionDefaults.reset,
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
}],
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const configuration = Object.assign({}, optionDefaults, context.options[0]);
|
||||
|
||||
function reportMissing(node) {
|
||||
report(context, messages.missingType, 'missingType', {
|
||||
node,
|
||||
});
|
||||
}
|
||||
|
||||
function reportComplex(node) {
|
||||
report(context, messages.complexType, 'complexType', {
|
||||
node,
|
||||
});
|
||||
}
|
||||
|
||||
function checkValue(node, value) {
|
||||
if (!(value in configuration)) {
|
||||
report(context, messages.invalidValue, 'invalidValue', {
|
||||
node,
|
||||
data: {
|
||||
value,
|
||||
},
|
||||
});
|
||||
} else if (!configuration[value]) {
|
||||
report(context, messages.forbiddenValue, 'forbiddenValue', {
|
||||
node,
|
||||
data: {
|
||||
value,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function checkExpression(node, expression) {
|
||||
switch (expression.type) {
|
||||
case 'Literal':
|
||||
checkValue(node, expression.value);
|
||||
return;
|
||||
case 'TemplateLiteral':
|
||||
if (expression.expressions.length === 0) {
|
||||
checkValue(node, expression.quasis[0].value.raw);
|
||||
} else {
|
||||
reportComplex(expression);
|
||||
}
|
||||
return;
|
||||
case 'ConditionalExpression':
|
||||
checkExpression(node, expression.consequent);
|
||||
checkExpression(node, expression.alternate);
|
||||
return;
|
||||
default:
|
||||
reportComplex(expression);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
JSXElement(node) {
|
||||
if (node.openingElement.name.name !== 'button') {
|
||||
return;
|
||||
}
|
||||
|
||||
const typeProp = getProp(node.openingElement.attributes, 'type');
|
||||
|
||||
if (!typeProp) {
|
||||
reportMissing(node);
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeProp.value && typeProp.value.type === 'JSXExpressionContainer') {
|
||||
checkExpression(node, typeProp.value.expression);
|
||||
return;
|
||||
}
|
||||
|
||||
const propValue = getLiteralPropValue(typeProp);
|
||||
checkValue(node, propValue);
|
||||
},
|
||||
CallExpression(node) {
|
||||
if (!isCreateElement(context, node) || node.arguments.length < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.arguments[0].type !== 'Literal' || node.arguments[0].value !== 'button') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!node.arguments[1] || node.arguments[1].type !== 'ObjectExpression') {
|
||||
reportMissing(node);
|
||||
return;
|
||||
}
|
||||
|
||||
const props = node.arguments[1].properties;
|
||||
const typeProp = props.find((prop) => (
|
||||
'key' in prop
|
||||
&& prop.key
|
||||
&& 'name' in prop.key
|
||||
&& prop.key.name === 'type'
|
||||
));
|
||||
|
||||
if (!typeProp) {
|
||||
reportMissing(node);
|
||||
return;
|
||||
}
|
||||
|
||||
checkExpression(node, 'value' in typeProp ? typeProp.value : undefined);
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/checked-requires-onchange-or-readonly.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/checked-requires-onchange-or-readonly.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=checked-requires-onchange-or-readonly.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/checked-requires-onchange-or-readonly.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/checked-requires-onchange-or-readonly.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"checked-requires-onchange-or-readonly.d.ts","sourceRoot":"","sources":["checked-requires-onchange-or-readonly.js"],"names":[],"mappings":"wBA2CW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
142
Lab/node_modules/eslint-plugin-react/lib/rules/checked-requires-onchange-or-readonly.js
generated
vendored
Normal file
142
Lab/node_modules/eslint-plugin-react/lib/rules/checked-requires-onchange-or-readonly.js
generated
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
/**
|
||||
* @fileoverview Enforce the use of the 'onChange' or 'readonly' attribute when 'checked' is used'
|
||||
* @author Jaesoekjjang
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const ASTUtils = require('jsx-ast-utils');
|
||||
const flatMap = require('array.prototype.flatmap');
|
||||
const isCreateElement = require('../util/isCreateElement');
|
||||
const report = require('../util/report');
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
|
||||
const messages = {
|
||||
missingProperty: '`checked` should be used with either `onChange` or `readOnly`.',
|
||||
exclusiveCheckedAttribute: 'Use either `checked` or `defaultChecked`, but not both.',
|
||||
};
|
||||
|
||||
const targetPropSet = new Set(['checked', 'onChange', 'readOnly', 'defaultChecked']);
|
||||
|
||||
const defaultOptions = {
|
||||
ignoreMissingProperties: false,
|
||||
ignoreExclusiveCheckedAttribute: false,
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {object[]} properties
|
||||
* @param {string} keyName
|
||||
* @returns {Set<string>}
|
||||
*/
|
||||
function extractTargetProps(properties, keyName) {
|
||||
return new Set(
|
||||
flatMap(
|
||||
properties,
|
||||
(prop) => (
|
||||
prop[keyName] && targetPropSet.has(prop[keyName].name)
|
||||
? [prop[keyName].name]
|
||||
: []
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Enforce using `onChange` or `readonly` attribute when `checked` is used',
|
||||
category: 'Best Practices',
|
||||
recommended: false,
|
||||
url: docsUrl('checked-requires-onchange-or-readonly'),
|
||||
},
|
||||
messages,
|
||||
schema: [{
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
ignoreMissingProperties: {
|
||||
type: 'boolean',
|
||||
},
|
||||
ignoreExclusiveCheckedAttribute: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
}],
|
||||
},
|
||||
create(context) {
|
||||
const options = Object.assign({}, defaultOptions, context.options[0]);
|
||||
|
||||
function reportMissingProperty(node) {
|
||||
report(
|
||||
context,
|
||||
messages.missingProperty,
|
||||
'missingProperty',
|
||||
{ node }
|
||||
);
|
||||
}
|
||||
|
||||
function reportExclusiveCheckedAttribute(node) {
|
||||
report(
|
||||
context,
|
||||
messages.exclusiveCheckedAttribute,
|
||||
'exclusiveCheckedAttribute',
|
||||
{ node }
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ASTNode} node
|
||||
* @param {Set<string>} propSet
|
||||
* @returns {void}
|
||||
*/
|
||||
const checkAttributesAndReport = (node, propSet) => {
|
||||
if (!propSet.has('checked')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!options.ignoreExclusiveCheckedAttribute && propSet.has('defaultChecked')) {
|
||||
reportExclusiveCheckedAttribute(node);
|
||||
}
|
||||
|
||||
if (
|
||||
!options.ignoreMissingProperties
|
||||
&& !(propSet.has('onChange') || propSet.has('readOnly'))
|
||||
) {
|
||||
reportMissingProperty(node);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
JSXOpeningElement(node) {
|
||||
if (ASTUtils.elementType(node) !== 'input') {
|
||||
return;
|
||||
}
|
||||
|
||||
const propSet = extractTargetProps(node.attributes, 'name');
|
||||
checkAttributesAndReport(node, propSet);
|
||||
},
|
||||
CallExpression(node) {
|
||||
if (!isCreateElement(context, node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const firstArg = node.arguments[0];
|
||||
const secondArg = node.arguments[1];
|
||||
if (
|
||||
!firstArg
|
||||
|| firstArg.type !== 'Literal'
|
||||
|| firstArg.value !== 'input'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!secondArg || secondArg.type !== 'ObjectExpression') {
|
||||
return;
|
||||
}
|
||||
|
||||
const propSet = extractTargetProps(secondArg.properties, 'key');
|
||||
checkAttributesAndReport(node, propSet);
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/default-props-match-prop-types.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/default-props-match-prop-types.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=default-props-match-prop-types.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/default-props-match-prop-types.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/default-props-match-prop-types.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"default-props-match-prop-types.d.ts","sourceRoot":"","sources":["default-props-match-prop-types.js"],"names":[],"mappings":"wBAuBW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
109
Lab/node_modules/eslint-plugin-react/lib/rules/default-props-match-prop-types.js
generated
vendored
Normal file
109
Lab/node_modules/eslint-plugin-react/lib/rules/default-props-match-prop-types.js
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* @fileOverview Enforce all defaultProps are defined in propTypes
|
||||
* @author Vitor Balocco
|
||||
* @author Roy Sutton
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const values = require('object.values');
|
||||
|
||||
const Components = require('../util/Components');
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const report = require('../util/report');
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const messages = {
|
||||
requiredHasDefault: 'defaultProp "{{name}}" defined for isRequired propType.',
|
||||
defaultHasNoType: 'defaultProp "{{name}}" has no corresponding propTypes declaration.',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Enforce all defaultProps have a corresponding non-required PropType',
|
||||
category: 'Best Practices',
|
||||
url: docsUrl('default-props-match-prop-types'),
|
||||
},
|
||||
|
||||
messages,
|
||||
|
||||
schema: [{
|
||||
type: 'object',
|
||||
properties: {
|
||||
allowRequiredDefaults: {
|
||||
default: false,
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
}],
|
||||
},
|
||||
|
||||
create: Components.detect((context, components) => {
|
||||
const configuration = context.options[0] || {};
|
||||
const allowRequiredDefaults = configuration.allowRequiredDefaults || false;
|
||||
|
||||
/**
|
||||
* Reports all defaultProps passed in that don't have an appropriate propTypes counterpart.
|
||||
* @param {Object[]} propTypes Array of propTypes to check.
|
||||
* @param {Object} defaultProps Object of defaultProps to check. Keys are the props names.
|
||||
* @return {void}
|
||||
*/
|
||||
function reportInvalidDefaultProps(propTypes, defaultProps) {
|
||||
// If this defaultProps is "unresolved" or the propTypes is undefined, then we should ignore
|
||||
// this component and not report any errors for it, to avoid false-positives with e.g.
|
||||
// external defaultProps/propTypes declarations or spread operators.
|
||||
if (defaultProps === 'unresolved' || !propTypes || Object.keys(propTypes).length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object.keys(defaultProps).forEach((defaultPropName) => {
|
||||
const defaultProp = defaultProps[defaultPropName];
|
||||
const prop = propTypes[defaultPropName];
|
||||
|
||||
if (prop && (allowRequiredDefaults || !prop.isRequired)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (prop) {
|
||||
report(context, messages.requiredHasDefault, 'requiredHasDefault', {
|
||||
node: defaultProp.node,
|
||||
data: {
|
||||
name: defaultPropName,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
report(context, messages.defaultHasNoType, 'defaultHasNoType', {
|
||||
node: defaultProp.node,
|
||||
data: {
|
||||
name: defaultPropName,
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Public API
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
'Program:exit'() {
|
||||
// If no defaultProps could be found, we don't report anything.
|
||||
values(components.list())
|
||||
.filter((component) => component.defaultProps)
|
||||
.forEach((component) => {
|
||||
reportInvalidDefaultProps(
|
||||
component.declaredPropTypes,
|
||||
component.defaultProps || {}
|
||||
);
|
||||
});
|
||||
},
|
||||
};
|
||||
}),
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/destructuring-assignment.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/destructuring-assignment.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=destructuring-assignment.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/destructuring-assignment.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/destructuring-assignment.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"destructuring-assignment.d.ts","sourceRoot":"","sources":["destructuring-assignment.js"],"names":[],"mappings":"wBA2DW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
319
Lab/node_modules/eslint-plugin-react/lib/rules/destructuring-assignment.js
generated
vendored
Normal file
319
Lab/node_modules/eslint-plugin-react/lib/rules/destructuring-assignment.js
generated
vendored
Normal file
@@ -0,0 +1,319 @@
|
||||
/**
|
||||
* @fileoverview Enforce consistent usage of destructuring assignment of props, state, and context.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const Components = require('../util/Components');
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const eslintUtil = require('../util/eslint');
|
||||
const isAssignmentLHS = require('../util/ast').isAssignmentLHS;
|
||||
const report = require('../util/report');
|
||||
|
||||
const getScope = eslintUtil.getScope;
|
||||
const getText = eslintUtil.getText;
|
||||
|
||||
const DEFAULT_OPTION = 'always';
|
||||
|
||||
function createSFCParams() {
|
||||
const queue = [];
|
||||
|
||||
return {
|
||||
push(params) {
|
||||
queue.unshift(params);
|
||||
},
|
||||
pop() {
|
||||
queue.shift();
|
||||
},
|
||||
propsName() {
|
||||
const found = queue.find((params) => {
|
||||
const props = params[0];
|
||||
return props && !props.destructuring && props.name;
|
||||
});
|
||||
return found && found[0] && found[0].name;
|
||||
},
|
||||
contextName() {
|
||||
const found = queue.find((params) => {
|
||||
const context = params[1];
|
||||
return context && !context.destructuring && context.name;
|
||||
});
|
||||
return found && found[1] && found[1].name;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function evalParams(params) {
|
||||
return params.map((param) => ({
|
||||
destructuring: param.type === 'ObjectPattern',
|
||||
name: param.type === 'Identifier' && param.name,
|
||||
}));
|
||||
}
|
||||
|
||||
const messages = {
|
||||
noDestructPropsInSFCArg: 'Must never use destructuring props assignment in SFC argument',
|
||||
noDestructContextInSFCArg: 'Must never use destructuring context assignment in SFC argument',
|
||||
noDestructAssignment: 'Must never use destructuring {{type}} assignment',
|
||||
useDestructAssignment: 'Must use destructuring {{type}} assignment',
|
||||
destructureInSignature: 'Must destructure props in the function signature.',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Enforce consistent usage of destructuring assignment of props, state, and context',
|
||||
category: 'Stylistic Issues',
|
||||
recommended: false,
|
||||
url: docsUrl('destructuring-assignment'),
|
||||
},
|
||||
fixable: 'code',
|
||||
messages,
|
||||
|
||||
schema: [{
|
||||
type: 'string',
|
||||
enum: [
|
||||
'always',
|
||||
'never',
|
||||
],
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
ignoreClassFields: {
|
||||
type: 'boolean',
|
||||
},
|
||||
destructureInSignature: {
|
||||
type: 'string',
|
||||
enum: [
|
||||
'always',
|
||||
'ignore',
|
||||
],
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
}],
|
||||
},
|
||||
|
||||
create: Components.detect((context, components, utils) => {
|
||||
const configuration = context.options[0] || DEFAULT_OPTION;
|
||||
const ignoreClassFields = (context.options[1] && (context.options[1].ignoreClassFields === true)) || false;
|
||||
const destructureInSignature = (context.options[1] && context.options[1].destructureInSignature) || 'ignore';
|
||||
const sfcParams = createSFCParams();
|
||||
|
||||
/**
|
||||
* @param {ASTNode} node We expect either an ArrowFunctionExpression,
|
||||
* FunctionDeclaration, or FunctionExpression
|
||||
*/
|
||||
function handleStatelessComponent(node) {
|
||||
const params = evalParams(node.params);
|
||||
|
||||
const SFCComponent = components.get(getScope(context, node).block);
|
||||
if (!SFCComponent) {
|
||||
return;
|
||||
}
|
||||
sfcParams.push(params);
|
||||
|
||||
if (params[0] && params[0].destructuring && components.get(node) && configuration === 'never') {
|
||||
report(context, messages.noDestructPropsInSFCArg, 'noDestructPropsInSFCArg', {
|
||||
node,
|
||||
});
|
||||
} else if (params[1] && params[1].destructuring && components.get(node) && configuration === 'never') {
|
||||
report(context, messages.noDestructContextInSFCArg, 'noDestructContextInSFCArg', {
|
||||
node,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handleStatelessComponentExit(node) {
|
||||
const SFCComponent = components.get(getScope(context, node).block);
|
||||
if (SFCComponent) {
|
||||
sfcParams.pop();
|
||||
}
|
||||
}
|
||||
|
||||
function handleSFCUsage(node) {
|
||||
const propsName = sfcParams.propsName();
|
||||
const contextName = sfcParams.contextName();
|
||||
// props.aProp || context.aProp
|
||||
const isPropUsed = (
|
||||
(propsName && node.object.name === propsName)
|
||||
|| (contextName && node.object.name === contextName)
|
||||
)
|
||||
&& !isAssignmentLHS(node);
|
||||
if (isPropUsed && configuration === 'always' && !node.optional) {
|
||||
report(context, messages.useDestructAssignment, 'useDestructAssignment', {
|
||||
node,
|
||||
data: {
|
||||
type: node.object.name,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function isInClassProperty(node) {
|
||||
let curNode = node.parent;
|
||||
while (curNode) {
|
||||
if (curNode.type === 'ClassProperty' || curNode.type === 'PropertyDefinition') {
|
||||
return true;
|
||||
}
|
||||
curNode = curNode.parent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function handleClassUsage(node) {
|
||||
// this.props.Aprop || this.context.aProp || this.state.aState
|
||||
const isPropUsed = (
|
||||
node.object.type === 'MemberExpression' && node.object.object.type === 'ThisExpression'
|
||||
&& (node.object.property.name === 'props' || node.object.property.name === 'context' || node.object.property.name === 'state')
|
||||
&& !isAssignmentLHS(node)
|
||||
);
|
||||
|
||||
if (
|
||||
isPropUsed && configuration === 'always'
|
||||
&& !(ignoreClassFields && isInClassProperty(node))
|
||||
) {
|
||||
report(context, messages.useDestructAssignment, 'useDestructAssignment', {
|
||||
node,
|
||||
data: {
|
||||
type: node.object.property.name,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// valid-jsdoc cannot read function types
|
||||
// eslint-disable-next-line valid-jsdoc
|
||||
/**
|
||||
* Find a parent that satisfy the given predicate
|
||||
* @param {ASTNode} node
|
||||
* @param {(node: ASTNode) => boolean} predicate
|
||||
* @returns {ASTNode | undefined}
|
||||
*/
|
||||
function findParent(node, predicate) {
|
||||
let n = node;
|
||||
while (n) {
|
||||
if (predicate(n)) {
|
||||
return n;
|
||||
}
|
||||
n = n.parent;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
FunctionDeclaration: handleStatelessComponent,
|
||||
|
||||
ArrowFunctionExpression: handleStatelessComponent,
|
||||
|
||||
FunctionExpression: handleStatelessComponent,
|
||||
|
||||
'FunctionDeclaration:exit': handleStatelessComponentExit,
|
||||
|
||||
'ArrowFunctionExpression:exit': handleStatelessComponentExit,
|
||||
|
||||
'FunctionExpression:exit': handleStatelessComponentExit,
|
||||
|
||||
MemberExpression(node) {
|
||||
const SFCComponent = utils.getParentStatelessComponent(node);
|
||||
if (SFCComponent) {
|
||||
handleSFCUsage(node);
|
||||
}
|
||||
|
||||
const classComponent = utils.getParentComponent(node);
|
||||
if (classComponent) {
|
||||
handleClassUsage(node);
|
||||
}
|
||||
},
|
||||
|
||||
TSQualifiedName(node) {
|
||||
if (configuration !== 'always') {
|
||||
return;
|
||||
}
|
||||
// handle `typeof props.a.b`
|
||||
if (node.left.type === 'Identifier'
|
||||
&& node.left.name === sfcParams.propsName()
|
||||
&& findParent(node, (n) => n.type === 'TSTypeQuery')
|
||||
&& utils.getParentStatelessComponent(node)
|
||||
) {
|
||||
report(context, messages.useDestructAssignment, 'useDestructAssignment', {
|
||||
node,
|
||||
data: {
|
||||
type: 'props',
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
VariableDeclarator(node) {
|
||||
const classComponent = utils.getParentComponent(node);
|
||||
const SFCComponent = components.get(getScope(context, node).block);
|
||||
|
||||
const destructuring = (node.init && node.id && node.id.type === 'ObjectPattern');
|
||||
// let {foo} = props;
|
||||
const destructuringSFC = destructuring && (node.init.name === 'props' || node.init.name === 'context');
|
||||
// let {foo} = this.props;
|
||||
const destructuringClass = destructuring && node.init.object && node.init.object.type === 'ThisExpression' && (
|
||||
node.init.property.name === 'props' || node.init.property.name === 'context' || node.init.property.name === 'state'
|
||||
);
|
||||
|
||||
if (SFCComponent && destructuringSFC && configuration === 'never') {
|
||||
report(context, messages.noDestructAssignment, 'noDestructAssignment', {
|
||||
node,
|
||||
data: {
|
||||
type: node.init.name,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
classComponent && destructuringClass && configuration === 'never'
|
||||
&& !(ignoreClassFields && (node.parent.type === 'ClassProperty' || node.parent.type === 'PropertyDefinition'))
|
||||
) {
|
||||
report(context, messages.noDestructAssignment, 'noDestructAssignment', {
|
||||
node,
|
||||
data: {
|
||||
type: node.init.property.name,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
SFCComponent
|
||||
&& destructuringSFC
|
||||
&& configuration === 'always'
|
||||
&& destructureInSignature === 'always'
|
||||
&& node.init.name === 'props'
|
||||
) {
|
||||
const scopeSetProps = getScope(context, node).set.get('props');
|
||||
const propsRefs = scopeSetProps && scopeSetProps.references;
|
||||
if (!propsRefs) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip if props is used elsewhere
|
||||
if (propsRefs.length > 1) {
|
||||
return;
|
||||
}
|
||||
report(context, messages.destructureInSignature, 'destructureInSignature', {
|
||||
node,
|
||||
fix(fixer) {
|
||||
const param = SFCComponent.node.params[0];
|
||||
if (!param) {
|
||||
return;
|
||||
}
|
||||
const replaceRange = [
|
||||
param.range[0],
|
||||
param.typeAnnotation ? param.typeAnnotation.range[0] : param.range[1],
|
||||
];
|
||||
return [
|
||||
fixer.replaceTextRange(replaceRange, getText(context, node.id)),
|
||||
fixer.remove(node.parent),
|
||||
];
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
}),
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/display-name.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/display-name.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=display-name.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/display-name.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/display-name.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"display-name.d.ts","sourceRoot":"","sources":["display-name.js"],"names":[],"mappings":"wBA6BW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
285
Lab/node_modules/eslint-plugin-react/lib/rules/display-name.js
generated
vendored
Normal file
285
Lab/node_modules/eslint-plugin-react/lib/rules/display-name.js
generated
vendored
Normal file
@@ -0,0 +1,285 @@
|
||||
/**
|
||||
* @fileoverview Prevent missing displayName in a React component definition
|
||||
* @author Yannick Croissant
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const values = require('object.values');
|
||||
const filter = require('es-iterator-helpers/Iterator.prototype.filter');
|
||||
const forEach = require('es-iterator-helpers/Iterator.prototype.forEach');
|
||||
|
||||
const Components = require('../util/Components');
|
||||
const isCreateContext = require('../util/isCreateContext');
|
||||
const astUtil = require('../util/ast');
|
||||
const componentUtil = require('../util/componentUtil');
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const testReactVersion = require('../util/version').testReactVersion;
|
||||
const propsUtil = require('../util/props');
|
||||
const report = require('../util/report');
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const messages = {
|
||||
noDisplayName: 'Component definition is missing display name',
|
||||
noContextDisplayName: 'Context definition is missing display name',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Disallow missing displayName in a React component definition',
|
||||
category: 'Best Practices',
|
||||
recommended: true,
|
||||
url: docsUrl('display-name'),
|
||||
},
|
||||
|
||||
messages,
|
||||
|
||||
schema: [{
|
||||
type: 'object',
|
||||
properties: {
|
||||
ignoreTranspilerName: {
|
||||
type: 'boolean',
|
||||
},
|
||||
checkContextObjects: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
}],
|
||||
},
|
||||
|
||||
create: Components.detect((context, components, utils) => {
|
||||
const config = context.options[0] || {};
|
||||
const ignoreTranspilerName = config.ignoreTranspilerName || false;
|
||||
const checkContextObjects = (config.checkContextObjects || false) && testReactVersion(context, '>= 16.3.0');
|
||||
|
||||
const contextObjects = new Map();
|
||||
|
||||
/**
|
||||
* Mark a prop type as declared
|
||||
* @param {ASTNode} node The AST node being checked.
|
||||
*/
|
||||
function markDisplayNameAsDeclared(node) {
|
||||
components.set(node, {
|
||||
hasDisplayName: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if React.forwardRef is nested inside React.memo
|
||||
* @param {ASTNode} node The AST node being checked.
|
||||
* @returns {boolean} True if React.forwardRef is nested inside React.memo, false if not.
|
||||
*/
|
||||
function isNestedMemo(node) {
|
||||
return astUtil.isCallExpression(node)
|
||||
&& node.arguments
|
||||
&& astUtil.isCallExpression(node.arguments[0])
|
||||
&& utils.isPragmaComponentWrapper(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports missing display name for a given component
|
||||
* @param {Object} component The component to process
|
||||
*/
|
||||
function reportMissingDisplayName(component) {
|
||||
if (
|
||||
testReactVersion(context, '^0.14.10 || ^15.7.0 || >= 16.12.0')
|
||||
&& isNestedMemo(component.node)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
report(context, messages.noDisplayName, 'noDisplayName', {
|
||||
node: component.node,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports missing display name for a given context object
|
||||
* @param {Object} contextObj The context object to process
|
||||
*/
|
||||
function reportMissingContextDisplayName(contextObj) {
|
||||
report(context, messages.noContextDisplayName, 'noContextDisplayName', {
|
||||
node: contextObj.node,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the component have a name set by the transpiler
|
||||
* @param {ASTNode} node The AST node being checked.
|
||||
* @returns {boolean} True if component has a name, false if not.
|
||||
*/
|
||||
function hasTranspilerName(node) {
|
||||
const namedObjectAssignment = (
|
||||
node.type === 'ObjectExpression'
|
||||
&& node.parent
|
||||
&& node.parent.parent
|
||||
&& node.parent.parent.type === 'AssignmentExpression'
|
||||
&& (
|
||||
!node.parent.parent.left.object
|
||||
|| node.parent.parent.left.object.name !== 'module'
|
||||
|| node.parent.parent.left.property.name !== 'exports'
|
||||
)
|
||||
);
|
||||
const namedObjectDeclaration = (
|
||||
node.type === 'ObjectExpression'
|
||||
&& node.parent
|
||||
&& node.parent.parent
|
||||
&& node.parent.parent.type === 'VariableDeclarator'
|
||||
);
|
||||
const namedClass = (
|
||||
(node.type === 'ClassDeclaration' || node.type === 'ClassExpression')
|
||||
&& node.id
|
||||
&& !!node.id.name
|
||||
);
|
||||
|
||||
const namedFunctionDeclaration = (
|
||||
(node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression')
|
||||
&& node.id
|
||||
&& !!node.id.name
|
||||
);
|
||||
|
||||
const namedFunctionExpression = (
|
||||
astUtil.isFunctionLikeExpression(node)
|
||||
&& node.parent
|
||||
&& (node.parent.type === 'VariableDeclarator' || node.parent.type === 'Property' || node.parent.method === true)
|
||||
&& (!node.parent.parent || !componentUtil.isES5Component(node.parent.parent, context))
|
||||
);
|
||||
|
||||
if (
|
||||
namedObjectAssignment || namedObjectDeclaration
|
||||
|| namedClass
|
||||
|| namedFunctionDeclaration || namedFunctionExpression
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Public
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
ExpressionStatement(node) {
|
||||
if (checkContextObjects && isCreateContext(node)) {
|
||||
contextObjects.set(node.expression.left.name, { node, hasDisplayName: false });
|
||||
}
|
||||
},
|
||||
VariableDeclarator(node) {
|
||||
if (checkContextObjects && isCreateContext(node)) {
|
||||
contextObjects.set(node.id.name, { node, hasDisplayName: false });
|
||||
}
|
||||
},
|
||||
'ClassProperty, PropertyDefinition'(node) {
|
||||
if (!propsUtil.isDisplayNameDeclaration(node)) {
|
||||
return;
|
||||
}
|
||||
markDisplayNameAsDeclared(node);
|
||||
},
|
||||
|
||||
MemberExpression(node) {
|
||||
if (!propsUtil.isDisplayNameDeclaration(node.property)) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
checkContextObjects
|
||||
&& node.object
|
||||
&& node.object.name
|
||||
&& contextObjects.has(node.object.name)
|
||||
) {
|
||||
contextObjects.get(node.object.name).hasDisplayName = true;
|
||||
}
|
||||
const component = utils.getRelatedComponent(node);
|
||||
if (!component) {
|
||||
return;
|
||||
}
|
||||
markDisplayNameAsDeclared(astUtil.unwrapTSAsExpression(component.node));
|
||||
},
|
||||
|
||||
'FunctionExpression, FunctionDeclaration, ArrowFunctionExpression'(node) {
|
||||
if (ignoreTranspilerName || !hasTranspilerName(node)) {
|
||||
return;
|
||||
}
|
||||
if (components.get(node)) {
|
||||
markDisplayNameAsDeclared(node);
|
||||
}
|
||||
},
|
||||
|
||||
MethodDefinition(node) {
|
||||
if (!propsUtil.isDisplayNameDeclaration(node.key)) {
|
||||
return;
|
||||
}
|
||||
markDisplayNameAsDeclared(node);
|
||||
},
|
||||
|
||||
'ClassExpression, ClassDeclaration'(node) {
|
||||
if (ignoreTranspilerName || !hasTranspilerName(node)) {
|
||||
return;
|
||||
}
|
||||
markDisplayNameAsDeclared(node);
|
||||
},
|
||||
|
||||
ObjectExpression(node) {
|
||||
if (!componentUtil.isES5Component(node, context)) {
|
||||
return;
|
||||
}
|
||||
if (ignoreTranspilerName || !hasTranspilerName(node)) {
|
||||
// Search for the displayName declaration
|
||||
node.properties.forEach((property) => {
|
||||
if (!property.key || !propsUtil.isDisplayNameDeclaration(property.key)) {
|
||||
return;
|
||||
}
|
||||
markDisplayNameAsDeclared(node);
|
||||
});
|
||||
return;
|
||||
}
|
||||
markDisplayNameAsDeclared(node);
|
||||
},
|
||||
|
||||
CallExpression(node) {
|
||||
if (!utils.isPragmaComponentWrapper(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.arguments.length > 0 && astUtil.isFunctionLikeExpression(node.arguments[0])) {
|
||||
// Skip over React.forwardRef declarations that are embedded within
|
||||
// a React.memo i.e. React.memo(React.forwardRef(/* ... */))
|
||||
// This means that we raise a single error for the call to React.memo
|
||||
// instead of one for React.memo and one for React.forwardRef
|
||||
const isWrappedInAnotherPragma = utils.getPragmaComponentWrapper(node);
|
||||
if (
|
||||
!isWrappedInAnotherPragma
|
||||
&& (ignoreTranspilerName || !hasTranspilerName(node.arguments[0]))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (components.get(node)) {
|
||||
markDisplayNameAsDeclared(node);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
'Program:exit'() {
|
||||
const list = components.list();
|
||||
// Report missing display name for all components
|
||||
values(list).filter((component) => !component.hasDisplayName).forEach((component) => {
|
||||
reportMissingDisplayName(component);
|
||||
});
|
||||
if (checkContextObjects) {
|
||||
// Report missing display name for all context objects
|
||||
forEach(
|
||||
filter(contextObjects.values(), (v) => !v.hasDisplayName),
|
||||
(contextObj) => reportMissingContextDisplayName(contextObj)
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
}),
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-component-props.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-component-props.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=forbid-component-props.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-component-props.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-component-props.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"forbid-component-props.d.ts","sourceRoot":"","sources":["forbid-component-props.js"],"names":[],"mappings":"wBAyBW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
239
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-component-props.js
generated
vendored
Normal file
239
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-component-props.js
generated
vendored
Normal file
@@ -0,0 +1,239 @@
|
||||
/**
|
||||
* @fileoverview Forbid certain props on components
|
||||
* @author Joe Lencioni
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const minimatch = require('minimatch');
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const report = require('../util/report');
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Constants
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const DEFAULTS = ['className', 'style'];
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const messages = {
|
||||
propIsForbidden: 'Prop "{{prop}}" is forbidden on Components',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Disallow certain props on components',
|
||||
category: 'Best Practices',
|
||||
recommended: false,
|
||||
url: docsUrl('forbid-component-props'),
|
||||
},
|
||||
|
||||
messages,
|
||||
|
||||
schema: [{
|
||||
type: 'object',
|
||||
properties: {
|
||||
forbid: {
|
||||
type: 'array',
|
||||
items: {
|
||||
anyOf: [
|
||||
{ type: 'string' },
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
propName: { type: 'string' },
|
||||
allowedFor: {
|
||||
type: 'array',
|
||||
uniqueItems: true,
|
||||
items: { type: 'string' },
|
||||
},
|
||||
allowedForPatterns: {
|
||||
type: 'array',
|
||||
uniqueItems: true,
|
||||
items: { type: 'string' },
|
||||
},
|
||||
message: { type: 'string' },
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
propName: { type: 'string' },
|
||||
disallowedFor: {
|
||||
type: 'array',
|
||||
uniqueItems: true,
|
||||
minItems: 1,
|
||||
items: { type: 'string' },
|
||||
},
|
||||
disallowedForPatterns: {
|
||||
type: 'array',
|
||||
uniqueItems: true,
|
||||
minItems: 1,
|
||||
items: { type: 'string' },
|
||||
},
|
||||
message: { type: 'string' },
|
||||
},
|
||||
anyOf: [
|
||||
{ required: ['disallowedFor'] },
|
||||
{ required: ['disallowedForPatterns'] },
|
||||
],
|
||||
additionalProperties: false,
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
propNamePattern: { type: 'string' },
|
||||
allowedFor: {
|
||||
type: 'array',
|
||||
uniqueItems: true,
|
||||
items: { type: 'string' },
|
||||
},
|
||||
allowedForPatterns: {
|
||||
type: 'array',
|
||||
uniqueItems: true,
|
||||
items: { type: 'string' },
|
||||
},
|
||||
message: { type: 'string' },
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
propNamePattern: { type: 'string' },
|
||||
disallowedFor: {
|
||||
type: 'array',
|
||||
uniqueItems: true,
|
||||
minItems: 1,
|
||||
items: { type: 'string' },
|
||||
},
|
||||
disallowedForPatterns: {
|
||||
type: 'array',
|
||||
uniqueItems: true,
|
||||
minItems: 1,
|
||||
items: { type: 'string' },
|
||||
},
|
||||
message: { type: 'string' },
|
||||
},
|
||||
anyOf: [
|
||||
{ required: ['disallowedFor'] },
|
||||
{ required: ['disallowedForPatterns'] },
|
||||
],
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
}],
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const configuration = context.options[0] || {};
|
||||
const forbid = new Map((configuration.forbid || DEFAULTS).map((value) => {
|
||||
const propName = typeof value === 'string' ? value : value.propName;
|
||||
const propPattern = value.propNamePattern;
|
||||
const prop = propName || propPattern;
|
||||
const options = {
|
||||
allowList: [].concat(value.allowedFor || []),
|
||||
allowPatternList: [].concat(value.allowedForPatterns || []),
|
||||
disallowList: [].concat(value.disallowedFor || []),
|
||||
disallowPatternList: [].concat(value.disallowedForPatterns || []),
|
||||
message: typeof value === 'string' ? null : value.message,
|
||||
isPattern: !!value.propNamePattern,
|
||||
};
|
||||
return [prop, options];
|
||||
}));
|
||||
|
||||
function getPropOptions(prop) {
|
||||
// Get config options having pattern
|
||||
const propNamePatternArray = Array.from(forbid.entries()).filter((propEntry) => propEntry[1].isPattern);
|
||||
// Match current prop with pattern options, return if matched
|
||||
const propNamePattern = propNamePatternArray.find((propPatternVal) => minimatch(prop, propPatternVal[0]));
|
||||
// Get options for matched propNamePattern
|
||||
const propNamePatternOptions = propNamePattern && propNamePattern[1];
|
||||
|
||||
const options = forbid.get(prop) || propNamePatternOptions;
|
||||
return options;
|
||||
}
|
||||
|
||||
function isForbidden(prop, tagName) {
|
||||
const options = getPropOptions(prop);
|
||||
if (!options) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function checkIsTagForbiddenByAllowOptions() {
|
||||
if (options.allowList.indexOf(tagName) !== -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (options.allowPatternList.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return options.allowPatternList.every(
|
||||
(pattern) => !minimatch(tagName, pattern)
|
||||
);
|
||||
}
|
||||
|
||||
function checkIsTagForbiddenByDisallowOptions() {
|
||||
if (options.disallowList.indexOf(tagName) !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (options.disallowPatternList.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return options.disallowPatternList.some(
|
||||
(pattern) => minimatch(tagName, pattern)
|
||||
);
|
||||
}
|
||||
|
||||
const hasDisallowOptions = options.disallowList.length > 0 || options.disallowPatternList.length > 0;
|
||||
|
||||
// disallowList should have a least one item (schema configuration)
|
||||
const isTagForbidden = hasDisallowOptions
|
||||
? checkIsTagForbiddenByDisallowOptions()
|
||||
: checkIsTagForbiddenByAllowOptions();
|
||||
|
||||
// if the tagName is undefined (`<this.something>`), we assume it's a forbidden element
|
||||
return typeof tagName === 'undefined' || isTagForbidden;
|
||||
}
|
||||
|
||||
return {
|
||||
JSXAttribute(node) {
|
||||
const parentName = node.parent.name;
|
||||
// Extract a component name when using a "namespace", e.g. `<AntdLayout.Content />`.
|
||||
const tag = parentName.name || `${parentName.object.name}.${parentName.property.name}`;
|
||||
const componentName = parentName.name || parentName.property.name;
|
||||
if (componentName && typeof componentName[0] === 'string' && componentName[0] !== componentName[0].toUpperCase()) {
|
||||
// This is a DOM node, not a Component, so exit.
|
||||
return;
|
||||
}
|
||||
|
||||
const prop = node.name.name;
|
||||
|
||||
if (!isForbidden(prop, tag)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const customMessage = getPropOptions(prop).message;
|
||||
|
||||
report(context, customMessage || messages.propIsForbidden, !customMessage && 'propIsForbidden', {
|
||||
node,
|
||||
data: {
|
||||
prop,
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-dom-props.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-dom-props.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=forbid-dom-props.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-dom-props.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-dom-props.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"forbid-dom-props.d.ts","sourceRoot":"","sources":["forbid-dom-props.js"],"names":[],"mappings":"wBAuCW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
122
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-dom-props.js
generated
vendored
Normal file
122
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-dom-props.js
generated
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* @fileoverview Forbid certain props on DOM Nodes
|
||||
* @author David Vázquez
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const report = require('../util/report');
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Constants
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const DEFAULTS = [];
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @param {Map<string, object>} forbidMap // { disallowList: null | string[], message: null | string }
|
||||
* @param {string} prop
|
||||
* @param {string} tagName
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isForbidden(forbidMap, prop, tagName) {
|
||||
const options = forbidMap.get(prop);
|
||||
return options && (
|
||||
typeof tagName === 'undefined'
|
||||
|| !options.disallowList
|
||||
|| options.disallowList.indexOf(tagName) !== -1
|
||||
);
|
||||
}
|
||||
|
||||
const messages = {
|
||||
propIsForbidden: 'Prop "{{prop}}" is forbidden on DOM Nodes',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Disallow certain props on DOM Nodes',
|
||||
category: 'Best Practices',
|
||||
recommended: false,
|
||||
url: docsUrl('forbid-dom-props'),
|
||||
},
|
||||
|
||||
messages,
|
||||
|
||||
schema: [{
|
||||
type: 'object',
|
||||
properties: {
|
||||
forbid: {
|
||||
type: 'array',
|
||||
items: {
|
||||
anyOf: [{
|
||||
type: 'string',
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
propName: {
|
||||
type: 'string',
|
||||
},
|
||||
disallowedFor: {
|
||||
type: 'array',
|
||||
uniqueItems: true,
|
||||
items: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
message: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
}],
|
||||
minLength: 1,
|
||||
},
|
||||
uniqueItems: true,
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
}],
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const configuration = context.options[0] || {};
|
||||
const forbid = new Map((configuration.forbid || DEFAULTS).map((value) => {
|
||||
const propName = typeof value === 'string' ? value : value.propName;
|
||||
return [propName, {
|
||||
disallowList: typeof value === 'string' ? null : (value.disallowedFor || null),
|
||||
message: typeof value === 'string' ? null : value.message,
|
||||
}];
|
||||
}));
|
||||
|
||||
return {
|
||||
JSXAttribute(node) {
|
||||
const tag = node.parent.name.name;
|
||||
if (!(tag && typeof tag === 'string' && tag[0] !== tag[0].toUpperCase())) {
|
||||
// This is a Component, not a DOM node, so exit.
|
||||
return;
|
||||
}
|
||||
|
||||
const prop = node.name.name;
|
||||
|
||||
if (!isForbidden(forbid, prop, tag)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const customMessage = forbid.get(prop).message;
|
||||
|
||||
report(context, customMessage || messages.propIsForbidden, !customMessage && 'propIsForbidden', {
|
||||
node,
|
||||
data: {
|
||||
prop,
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-elements.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-elements.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=forbid-elements.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-elements.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-elements.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"forbid-elements.d.ts","sourceRoot":"","sources":["forbid-elements.js"],"names":[],"mappings":"wBAsBW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
119
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-elements.js
generated
vendored
Normal file
119
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-elements.js
generated
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* @fileoverview Forbid certain elements
|
||||
* @author Kenneth Chung
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const has = require('hasown');
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const getText = require('../util/eslint').getText;
|
||||
const isCreateElement = require('../util/isCreateElement');
|
||||
const report = require('../util/report');
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const messages = {
|
||||
forbiddenElement: '<{{element}}> is forbidden',
|
||||
forbiddenElement_message: '<{{element}}> is forbidden, {{message}}',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Disallow certain elements',
|
||||
category: 'Best Practices',
|
||||
recommended: false,
|
||||
url: docsUrl('forbid-elements'),
|
||||
},
|
||||
|
||||
messages,
|
||||
|
||||
schema: [{
|
||||
type: 'object',
|
||||
properties: {
|
||||
forbid: {
|
||||
type: 'array',
|
||||
items: {
|
||||
anyOf: [
|
||||
{ type: 'string' },
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
element: { type: 'string' },
|
||||
message: { type: 'string' },
|
||||
},
|
||||
required: ['element'],
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
}],
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const configuration = context.options[0] || {};
|
||||
const forbidConfiguration = configuration.forbid || [];
|
||||
|
||||
/** @type {Record<string, { element: string, message?: string }>} */
|
||||
const indexedForbidConfigs = {};
|
||||
|
||||
forbidConfiguration.forEach((item) => {
|
||||
if (typeof item === 'string') {
|
||||
indexedForbidConfigs[item] = { element: item };
|
||||
} else {
|
||||
indexedForbidConfigs[item.element] = item;
|
||||
}
|
||||
});
|
||||
|
||||
function reportIfForbidden(element, node) {
|
||||
if (has(indexedForbidConfigs, element)) {
|
||||
const message = indexedForbidConfigs[element].message;
|
||||
|
||||
report(
|
||||
context,
|
||||
message ? messages.forbiddenElement_message : messages.forbiddenElement,
|
||||
message ? 'forbiddenElement_message' : 'forbiddenElement',
|
||||
{
|
||||
node,
|
||||
data: {
|
||||
element,
|
||||
message,
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
JSXOpeningElement(node) {
|
||||
reportIfForbidden(getText(context, node.name), node.name);
|
||||
},
|
||||
|
||||
CallExpression(node) {
|
||||
if (!isCreateElement(context, node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const argument = node.arguments[0];
|
||||
if (!argument) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (argument.type === 'Identifier' && /^[A-Z_]/.test(argument.name)) {
|
||||
reportIfForbidden(argument.name, argument);
|
||||
} else if (argument.type === 'Literal' && /^[a-z][^.]*$/.test(String(argument.value))) {
|
||||
reportIfForbidden(argument.value, argument);
|
||||
} else if (argument.type === 'MemberExpression') {
|
||||
reportIfForbidden(getText(context, argument), argument);
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-foreign-prop-types.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-foreign-prop-types.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=forbid-foreign-prop-types.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-foreign-prop-types.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-foreign-prop-types.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"forbid-foreign-prop-types.d.ts","sourceRoot":"","sources":["forbid-foreign-prop-types.js"],"names":[],"mappings":"wBAeW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
141
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-foreign-prop-types.js
generated
vendored
Normal file
141
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-foreign-prop-types.js
generated
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
* @fileoverview Forbid using another component's propTypes
|
||||
* @author Ian Christian Myers
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const ast = require('../util/ast');
|
||||
const report = require('../util/report');
|
||||
|
||||
const messages = {
|
||||
forbiddenPropType: 'Using propTypes from another component is not safe because they may be removed in production builds',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Disallow using another component\'s propTypes',
|
||||
category: 'Best Practices',
|
||||
recommended: false,
|
||||
url: docsUrl('forbid-foreign-prop-types'),
|
||||
},
|
||||
|
||||
messages,
|
||||
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
allowInPropTypes: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const config = context.options[0] || {};
|
||||
const allowInPropTypes = config.allowInPropTypes || false;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
function findParentAssignmentExpression(node) {
|
||||
let parent = node.parent;
|
||||
|
||||
while (parent && parent.type !== 'Program') {
|
||||
if (parent.type === 'AssignmentExpression') {
|
||||
return parent;
|
||||
}
|
||||
parent = parent.parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function findParentClassProperty(node) {
|
||||
let parent = node.parent;
|
||||
|
||||
while (parent && parent.type !== 'Program') {
|
||||
if (parent.type === 'ClassProperty' || parent.type === 'PropertyDefinition') {
|
||||
return parent;
|
||||
}
|
||||
parent = parent.parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function isAllowedAssignment(node) {
|
||||
if (!allowInPropTypes) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const assignmentExpression = findParentAssignmentExpression(node);
|
||||
|
||||
if (
|
||||
assignmentExpression
|
||||
&& assignmentExpression.left
|
||||
&& assignmentExpression.left.property
|
||||
&& assignmentExpression.left.property.name === 'propTypes'
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const classProperty = findParentClassProperty(node);
|
||||
|
||||
if (
|
||||
classProperty
|
||||
&& classProperty.key
|
||||
&& classProperty.key.name === 'propTypes'
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return {
|
||||
MemberExpression(node) {
|
||||
if (
|
||||
(node.property
|
||||
&& (
|
||||
!node.computed
|
||||
&& node.property.type === 'Identifier'
|
||||
&& node.property.name === 'propTypes'
|
||||
&& !ast.isAssignmentLHS(node)
|
||||
&& !isAllowedAssignment(node)
|
||||
)) || (
|
||||
// @ts-expect-error: The JSXText type is not present in the estree type definitions
|
||||
(node.property.type === 'Literal' || node.property.type === 'JSXText')
|
||||
&& 'value' in node.property
|
||||
&& node.property.value === 'propTypes'
|
||||
&& !ast.isAssignmentLHS(node)
|
||||
&& !isAllowedAssignment(node)
|
||||
)
|
||||
) {
|
||||
report(context, messages.forbiddenPropType, 'forbiddenPropType', {
|
||||
node: node.property,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
ObjectPattern(node) {
|
||||
const propTypesNode = node.properties.find((property) => (
|
||||
property.type === 'Property'
|
||||
&& 'name' in property.key
|
||||
&& property.key.name === 'propTypes'
|
||||
));
|
||||
|
||||
if (propTypesNode) {
|
||||
report(context, messages.forbiddenPropType, 'forbiddenPropType', {
|
||||
node: propTypesNode,
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-prop-types.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-prop-types.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=forbid-prop-types.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-prop-types.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-prop-types.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"forbid-prop-types.d.ts","sourceRoot":"","sources":["forbid-prop-types.js"],"names":[],"mappings":"wBA4BW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
298
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-prop-types.js
generated
vendored
Normal file
298
Lab/node_modules/eslint-plugin-react/lib/rules/forbid-prop-types.js
generated
vendored
Normal file
@@ -0,0 +1,298 @@
|
||||
/**
|
||||
* @fileoverview Forbid certain propTypes
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const variableUtil = require('../util/variable');
|
||||
const propsUtil = require('../util/props');
|
||||
const astUtil = require('../util/ast');
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const propWrapperUtil = require('../util/propWrapper');
|
||||
const report = require('../util/report');
|
||||
const getText = require('../util/eslint').getText;
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Constants
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const DEFAULTS = ['any', 'array', 'object'];
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const messages = {
|
||||
forbiddenPropType: 'Prop type "{{target}}" is forbidden',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Disallow certain propTypes',
|
||||
category: 'Best Practices',
|
||||
recommended: false,
|
||||
url: docsUrl('forbid-prop-types'),
|
||||
},
|
||||
|
||||
messages,
|
||||
|
||||
schema: [{
|
||||
type: 'object',
|
||||
properties: {
|
||||
forbid: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
checkContextTypes: {
|
||||
type: 'boolean',
|
||||
},
|
||||
checkChildContextTypes: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
additionalProperties: true,
|
||||
}],
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const configuration = context.options[0] || {};
|
||||
const checkContextTypes = configuration.checkContextTypes || false;
|
||||
const checkChildContextTypes = configuration.checkChildContextTypes || false;
|
||||
let propTypesPackageName = null;
|
||||
let reactPackageName = null;
|
||||
let isForeignPropTypesPackage = false;
|
||||
|
||||
function isPropTypesPackage(node) {
|
||||
return (
|
||||
node.type === 'Identifier'
|
||||
&& (
|
||||
node.name === null
|
||||
|| node.name === propTypesPackageName
|
||||
|| !isForeignPropTypesPackage
|
||||
)
|
||||
) || (
|
||||
node.type === 'MemberExpression'
|
||||
&& (
|
||||
node.object.name === null
|
||||
|| node.object.name === reactPackageName
|
||||
|| !isForeignPropTypesPackage
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function isForbidden(type) {
|
||||
const forbid = configuration.forbid || DEFAULTS;
|
||||
return forbid.indexOf(type) >= 0;
|
||||
}
|
||||
|
||||
function reportIfForbidden(type, declaration, target) {
|
||||
if (isForbidden(type)) {
|
||||
report(context, messages.forbiddenPropType, 'forbiddenPropType', {
|
||||
node: declaration,
|
||||
data: {
|
||||
target,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function shouldCheckContextTypes(node) {
|
||||
if (checkContextTypes && propsUtil.isContextTypesDeclaration(node)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function shouldCheckChildContextTypes(node) {
|
||||
if (checkChildContextTypes && propsUtil.isChildContextTypesDeclaration(node)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if propTypes declarations are forbidden
|
||||
* @param {Array} declarations The array of AST nodes being checked.
|
||||
* @returns {void}
|
||||
*/
|
||||
function checkProperties(declarations) {
|
||||
if (declarations) {
|
||||
declarations.forEach((declaration) => {
|
||||
if (declaration.type !== 'Property') {
|
||||
return;
|
||||
}
|
||||
let target;
|
||||
let value = declaration.value;
|
||||
if (
|
||||
value.type === 'MemberExpression'
|
||||
&& value.property
|
||||
&& value.property.name
|
||||
&& value.property.name === 'isRequired'
|
||||
) {
|
||||
value = value.object;
|
||||
}
|
||||
if (astUtil.isCallExpression(value)) {
|
||||
if (!isPropTypesPackage(value.callee)) {
|
||||
return;
|
||||
}
|
||||
value.arguments.forEach((arg) => {
|
||||
const name = arg.type === 'MemberExpression' ? arg.property.name : arg.name;
|
||||
reportIfForbidden(name, declaration, name);
|
||||
});
|
||||
value = value.callee;
|
||||
}
|
||||
if (!isPropTypesPackage(value)) {
|
||||
return;
|
||||
}
|
||||
if (value.property) {
|
||||
target = value.property.name;
|
||||
} else if (value.type === 'Identifier') {
|
||||
target = value.name;
|
||||
}
|
||||
reportIfForbidden(target, declaration, target);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function checkNode(node) {
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.type === 'ObjectExpression') {
|
||||
checkProperties(node.properties);
|
||||
} else if (node.type === 'Identifier') {
|
||||
const propTypesObject = variableUtil.findVariableByName(context, node, node.name);
|
||||
if (propTypesObject && propTypesObject.properties) {
|
||||
checkProperties(propTypesObject.properties);
|
||||
}
|
||||
} else if (astUtil.isCallExpression(node)) {
|
||||
const innerNode = node.arguments && node.arguments[0];
|
||||
if (
|
||||
propWrapperUtil.isPropWrapperFunction(context, getText(context, node.callee))
|
||||
&& innerNode
|
||||
) {
|
||||
checkNode(innerNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
ImportDeclaration(node) {
|
||||
if (node.source && node.source.value === 'prop-types') { // import PropType from "prop-types"
|
||||
if (node.specifiers.length > 0) {
|
||||
propTypesPackageName = node.specifiers[0].local.name;
|
||||
}
|
||||
} else if (node.source && node.source.value === 'react') { // import { PropTypes } from "react"
|
||||
if (node.specifiers.length > 0) {
|
||||
reactPackageName = node.specifiers[0].local.name; // guard against accidental anonymous `import "react"`
|
||||
}
|
||||
if (node.specifiers.length >= 1) {
|
||||
const propTypesSpecifier = node.specifiers.find((specifier) => (
|
||||
'imported' in specifier
|
||||
&& specifier.imported
|
||||
&& 'name' in specifier.imported
|
||||
&& specifier.imported.name === 'PropTypes'
|
||||
));
|
||||
if (propTypesSpecifier) {
|
||||
propTypesPackageName = propTypesSpecifier.local.name;
|
||||
}
|
||||
}
|
||||
} else { // package is not imported from "react" or "prop-types"
|
||||
// eslint-disable-next-line no-lonely-if
|
||||
if (node.specifiers.some((x) => x.local.name === 'PropTypes')) { // assert: node.specifiers.length > 1
|
||||
isForeignPropTypesPackage = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
'ClassProperty, PropertyDefinition'(node) {
|
||||
if (
|
||||
!propsUtil.isPropTypesDeclaration(node)
|
||||
&& !isPropTypesPackage(node)
|
||||
&& !shouldCheckContextTypes(node)
|
||||
&& !shouldCheckChildContextTypes(node)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
checkNode(node.value);
|
||||
},
|
||||
|
||||
MemberExpression(node) {
|
||||
if (
|
||||
!propsUtil.isPropTypesDeclaration(node)
|
||||
&& !isPropTypesPackage(node)
|
||||
&& !shouldCheckContextTypes(node)
|
||||
&& !shouldCheckChildContextTypes(node)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
checkNode('right' in node.parent && node.parent.right);
|
||||
},
|
||||
|
||||
CallExpression(node) {
|
||||
if (
|
||||
node.callee.type === 'MemberExpression'
|
||||
&& node.callee.object
|
||||
&& !isPropTypesPackage(node.callee.object)
|
||||
&& !propsUtil.isPropTypesDeclaration(node.callee)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
node.arguments.length > 0
|
||||
&& (
|
||||
('name' in node.callee && node.callee.name === 'shape')
|
||||
|| astUtil.getPropertyName(node.callee) === 'shape'
|
||||
)
|
||||
) {
|
||||
checkProperties('properties' in node.arguments[0] && node.arguments[0].properties);
|
||||
}
|
||||
},
|
||||
|
||||
MethodDefinition(node) {
|
||||
if (
|
||||
!propsUtil.isPropTypesDeclaration(node)
|
||||
&& !isPropTypesPackage(node)
|
||||
&& !shouldCheckContextTypes(node)
|
||||
&& !shouldCheckChildContextTypes(node)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const returnStatement = astUtil.findReturnStatement(node);
|
||||
|
||||
if (returnStatement && returnStatement.argument) {
|
||||
checkNode(returnStatement.argument);
|
||||
}
|
||||
},
|
||||
|
||||
ObjectExpression(node) {
|
||||
node.properties.forEach((property) => {
|
||||
if (!('key' in property) || !property.key) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
!propsUtil.isPropTypesDeclaration(property)
|
||||
&& !isPropTypesPackage(property)
|
||||
&& !shouldCheckContextTypes(property)
|
||||
&& !shouldCheckChildContextTypes(property)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (property.value.type === 'ObjectExpression') {
|
||||
checkProperties(property.value.properties);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
};
|
||||
},
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/forward-ref-uses-ref.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/forward-ref-uses-ref.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=forward-ref-uses-ref.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/forward-ref-uses-ref.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/forward-ref-uses-ref.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"forward-ref-uses-ref.d.ts","sourceRoot":"","sources":["forward-ref-uses-ref.js"],"names":[],"mappings":"wBA2CW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
100
Lab/node_modules/eslint-plugin-react/lib/rules/forward-ref-uses-ref.js
generated
vendored
Normal file
100
Lab/node_modules/eslint-plugin-react/lib/rules/forward-ref-uses-ref.js
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* @fileoverview Require all forwardRef components include a ref parameter
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const isParenthesized = require('../util/ast').isParenthesized;
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const report = require('../util/report');
|
||||
const getMessageData = require('../util/message');
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @param {ASTNode} node
|
||||
* @returns {boolean} If the node represents the identifier `forwardRef`.
|
||||
*/
|
||||
function isForwardRefIdentifier(node) {
|
||||
return node.type === 'Identifier' && node.name === 'forwardRef';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ASTNode} node
|
||||
* @returns {boolean} If the node represents a function call `forwardRef()` or `React.forwardRef()`.
|
||||
*/
|
||||
function isForwardRefCall(node) {
|
||||
return (
|
||||
node.type === 'CallExpression'
|
||||
&& (
|
||||
isForwardRefIdentifier(node.callee)
|
||||
|| (node.callee.type === 'MemberExpression' && isForwardRefIdentifier(node.callee.property))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const messages = {
|
||||
missingRefParameter: 'forwardRef is used with this component but no ref parameter is set',
|
||||
addRefParameter: 'Add a ref parameter',
|
||||
removeForwardRef: 'Remove forwardRef wrapper',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Require all forwardRef components include a ref parameter',
|
||||
category: 'Possible Errors',
|
||||
recommended: false,
|
||||
url: docsUrl('forward-ref-uses-ref'),
|
||||
},
|
||||
messages,
|
||||
schema: [],
|
||||
type: 'suggestion',
|
||||
hasSuggestions: true,
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const sourceCode = context.getSourceCode();
|
||||
|
||||
return {
|
||||
'FunctionExpression, ArrowFunctionExpression'(node) {
|
||||
if (!isForwardRefCall(node.parent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.params.length === 1) {
|
||||
report(context, messages.missingRefParameter, 'missingRefParameter', {
|
||||
node,
|
||||
suggest: [
|
||||
Object.assign(
|
||||
getMessageData('addRefParameter', messages.addRefParameter),
|
||||
{
|
||||
fix(fixer) {
|
||||
const param = node.params[0];
|
||||
// If using shorthand arrow function syntax, add parentheses around the new parameter pair
|
||||
const shouldAddParentheses = node.type === 'ArrowFunctionExpression' && !isParenthesized(context, param);
|
||||
return [].concat(
|
||||
shouldAddParentheses ? fixer.insertTextBefore(param, '(') : [],
|
||||
fixer.insertTextAfter(param, `, ref${shouldAddParentheses ? ')' : ''}`)
|
||||
);
|
||||
},
|
||||
}
|
||||
),
|
||||
Object.assign(
|
||||
getMessageData('removeForwardRef', messages.removeForwardRef),
|
||||
{
|
||||
fix(fixer) {
|
||||
return fixer.replaceText(node.parent, sourceCode.getText(node));
|
||||
},
|
||||
}
|
||||
),
|
||||
],
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/function-component-definition.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/function-component-definition.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=function-component-definition.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/function-component-definition.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/function-component-definition.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"function-component-definition.d.ts","sourceRoot":"","sources":["function-component-definition.js"],"names":[],"mappings":"wBAqHW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
285
Lab/node_modules/eslint-plugin-react/lib/rules/function-component-definition.js
generated
vendored
Normal file
285
Lab/node_modules/eslint-plugin-react/lib/rules/function-component-definition.js
generated
vendored
Normal file
@@ -0,0 +1,285 @@
|
||||
/**
|
||||
* @fileoverview Standardize the way function component get defined
|
||||
* @author Stefan Wullems
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const arrayIncludes = require('array-includes');
|
||||
const Components = require('../util/Components');
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const reportC = require('../util/report');
|
||||
const getText = require('../util/eslint').getText;
|
||||
const propsUtil = require('../util/props');
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
function buildFunction(template, parts) {
|
||||
return Object.keys(parts).reduce(
|
||||
(acc, key) => acc.replace(`{${key}}`, () => parts[key] || ''),
|
||||
template
|
||||
);
|
||||
}
|
||||
|
||||
const NAMED_FUNCTION_TEMPLATES = {
|
||||
'function-declaration': 'function {name}{typeParams}({params}){returnType} {body}',
|
||||
'arrow-function': '{varType} {name}{typeAnnotation} = {typeParams}({params}){returnType} => {body}',
|
||||
'function-expression': '{varType} {name}{typeAnnotation} = function{typeParams}({params}){returnType} {body}',
|
||||
};
|
||||
|
||||
const UNNAMED_FUNCTION_TEMPLATES = {
|
||||
'function-expression': 'function{typeParams}({params}){returnType} {body}',
|
||||
'arrow-function': '{typeParams}({params}){returnType} => {body}',
|
||||
};
|
||||
|
||||
function hasOneUnconstrainedTypeParam(node) {
|
||||
const nodeTypeArguments = propsUtil.getTypeArguments(node);
|
||||
|
||||
return nodeTypeArguments
|
||||
&& nodeTypeArguments.params
|
||||
&& nodeTypeArguments.params.length === 1
|
||||
&& !nodeTypeArguments.params[0].constraint;
|
||||
}
|
||||
|
||||
function hasName(node) {
|
||||
return (
|
||||
node.type === 'FunctionDeclaration'
|
||||
|| node.parent.type === 'VariableDeclarator'
|
||||
);
|
||||
}
|
||||
|
||||
function getNodeText(prop, source) {
|
||||
if (!prop) return null;
|
||||
return source.slice(prop.range[0], prop.range[1]);
|
||||
}
|
||||
|
||||
function getName(node) {
|
||||
if (node.type === 'FunctionDeclaration') {
|
||||
return node.id.name;
|
||||
}
|
||||
|
||||
if (
|
||||
node.type === 'ArrowFunctionExpression'
|
||||
|| node.type === 'FunctionExpression'
|
||||
) {
|
||||
return hasName(node) && node.parent.id.name;
|
||||
}
|
||||
}
|
||||
|
||||
function getParams(node, source) {
|
||||
if (node.params.length === 0) return null;
|
||||
return source.slice(
|
||||
node.params[0].range[0],
|
||||
node.params[node.params.length - 1].range[1]
|
||||
);
|
||||
}
|
||||
|
||||
function getBody(node, source) {
|
||||
const range = node.body.range;
|
||||
|
||||
if (node.body.type !== 'BlockStatement') {
|
||||
return ['{', ` return ${source.slice(range[0], range[1])}`, '}'].join('\n');
|
||||
}
|
||||
|
||||
return source.slice(range[0], range[1]);
|
||||
}
|
||||
|
||||
function getTypeAnnotation(node, source) {
|
||||
if (!hasName(node) || node.type === 'FunctionDeclaration') return;
|
||||
|
||||
if (
|
||||
node.type === 'ArrowFunctionExpression'
|
||||
|| node.type === 'FunctionExpression'
|
||||
) {
|
||||
return getNodeText(node.parent.id.typeAnnotation, source);
|
||||
}
|
||||
}
|
||||
|
||||
function isUnfixableBecauseOfExport(node) {
|
||||
return (
|
||||
node.type === 'FunctionDeclaration'
|
||||
&& node.parent
|
||||
&& node.parent.type === 'ExportDefaultDeclaration'
|
||||
);
|
||||
}
|
||||
|
||||
function isFunctionExpressionWithName(node) {
|
||||
return node.type === 'FunctionExpression' && node.id && node.id.name;
|
||||
}
|
||||
|
||||
const messages = {
|
||||
'function-declaration': 'Function component is not a function declaration',
|
||||
'function-expression': 'Function component is not a function expression',
|
||||
'arrow-function': 'Function component is not an arrow function',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Enforce a specific function type for function components',
|
||||
category: 'Stylistic Issues',
|
||||
recommended: false,
|
||||
url: docsUrl('function-component-definition'),
|
||||
},
|
||||
fixable: 'code',
|
||||
|
||||
messages,
|
||||
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
namedComponents: {
|
||||
anyOf: [
|
||||
{
|
||||
enum: [
|
||||
'function-declaration',
|
||||
'arrow-function',
|
||||
'function-expression',
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string',
|
||||
enum: [
|
||||
'function-declaration',
|
||||
'arrow-function',
|
||||
'function-expression',
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
unnamedComponents: {
|
||||
anyOf: [
|
||||
{ enum: ['arrow-function', 'function-expression'] },
|
||||
{
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string',
|
||||
enum: ['arrow-function', 'function-expression'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
create: Components.detect((context, components) => {
|
||||
const configuration = context.options[0] || {};
|
||||
let fileVarType = 'var';
|
||||
|
||||
const namedConfig = [].concat(
|
||||
configuration.namedComponents || 'function-declaration'
|
||||
);
|
||||
const unnamedConfig = [].concat(
|
||||
configuration.unnamedComponents || 'function-expression'
|
||||
);
|
||||
|
||||
function getFixer(node, options) {
|
||||
const source = getText(context);
|
||||
|
||||
const typeAnnotation = getTypeAnnotation(node, source);
|
||||
|
||||
if (options.type === 'function-declaration' && typeAnnotation) {
|
||||
return;
|
||||
}
|
||||
if (options.type === 'arrow-function' && hasOneUnconstrainedTypeParam(node)) {
|
||||
return;
|
||||
}
|
||||
if (isUnfixableBecauseOfExport(node)) return;
|
||||
if (isFunctionExpressionWithName(node)) return;
|
||||
let varType = fileVarType;
|
||||
if (
|
||||
(node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression')
|
||||
&& node.parent.type === 'VariableDeclarator'
|
||||
) {
|
||||
varType = node.parent.parent.kind;
|
||||
}
|
||||
|
||||
const nodeTypeArguments = propsUtil.getTypeArguments(node);
|
||||
return (fixer) => fixer.replaceTextRange(
|
||||
options.range,
|
||||
buildFunction(options.template, {
|
||||
typeAnnotation,
|
||||
typeParams: getNodeText(nodeTypeArguments, source),
|
||||
params: getParams(node, source),
|
||||
returnType: getNodeText(node.returnType, source),
|
||||
body: getBody(node, source),
|
||||
name: getName(node),
|
||||
varType,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function report(node, options) {
|
||||
reportC(context, messages[options.messageId], options.messageId, {
|
||||
node,
|
||||
fix: getFixer(node, options.fixerOptions),
|
||||
});
|
||||
}
|
||||
|
||||
function validate(node, functionType) {
|
||||
if (!components.get(node)) return;
|
||||
|
||||
if (node.parent && node.parent.type === 'Property') return;
|
||||
|
||||
if (hasName(node) && !arrayIncludes(namedConfig, functionType)) {
|
||||
report(node, {
|
||||
messageId: namedConfig[0],
|
||||
fixerOptions: {
|
||||
type: namedConfig[0],
|
||||
template: NAMED_FUNCTION_TEMPLATES[namedConfig[0]],
|
||||
range:
|
||||
node.type === 'FunctionDeclaration'
|
||||
? node.range
|
||||
: node.parent.parent.range,
|
||||
},
|
||||
});
|
||||
}
|
||||
if (!hasName(node) && !arrayIncludes(unnamedConfig, functionType)) {
|
||||
report(node, {
|
||||
messageId: unnamedConfig[0],
|
||||
fixerOptions: {
|
||||
type: unnamedConfig[0],
|
||||
template: UNNAMED_FUNCTION_TEMPLATES[unnamedConfig[0]],
|
||||
range: node.range,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Public
|
||||
// --------------------------------------------------------------------------
|
||||
const validatePairs = [];
|
||||
let hasES6OrJsx = false;
|
||||
return {
|
||||
FunctionDeclaration(node) {
|
||||
validatePairs.push([node, 'function-declaration']);
|
||||
},
|
||||
ArrowFunctionExpression(node) {
|
||||
validatePairs.push([node, 'arrow-function']);
|
||||
},
|
||||
FunctionExpression(node) {
|
||||
validatePairs.push([node, 'function-expression']);
|
||||
},
|
||||
VariableDeclaration(node) {
|
||||
hasES6OrJsx = hasES6OrJsx || node.kind === 'const' || node.kind === 'let';
|
||||
},
|
||||
'Program:exit'() {
|
||||
if (hasES6OrJsx) fileVarType = 'const';
|
||||
validatePairs.forEach((pair) => validate(pair[0], pair[1]));
|
||||
},
|
||||
'ImportDeclaration, ExportNamedDeclaration, ExportDefaultDeclaration, ExportAllDeclaration, ExportSpecifier, ExportDefaultSpecifier, JSXElement, TSExportAssignment, TSImportEqualsDeclaration'() {
|
||||
hasES6OrJsx = true;
|
||||
},
|
||||
};
|
||||
}),
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/hook-use-state.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/hook-use-state.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=hook-use-state.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/hook-use-state.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/hook-use-state.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"hook-use-state.d.ts","sourceRoot":"","sources":["hook-use-state.js"],"names":[],"mappings":"wBA4BW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
205
Lab/node_modules/eslint-plugin-react/lib/rules/hook-use-state.js
generated
vendored
Normal file
205
Lab/node_modules/eslint-plugin-react/lib/rules/hook-use-state.js
generated
vendored
Normal file
@@ -0,0 +1,205 @@
|
||||
/**
|
||||
* @fileoverview Ensure symmetric naming of useState hook value and setter variables
|
||||
* @author Duncan Beevers
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const Components = require('../util/Components');
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const report = require('../util/report');
|
||||
const getMessageData = require('../util/message');
|
||||
const getText = require('../util/eslint').getText;
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
function isNodeDestructuring(node) {
|
||||
return node && (node.type === 'ArrayPattern' || node.type === 'ObjectPattern');
|
||||
}
|
||||
|
||||
const messages = {
|
||||
useStateErrorMessage: 'useState call is not destructured into value + setter pair',
|
||||
useStateErrorMessageOrAddOption: 'useState call is not destructured into value + setter pair (you can allow destructuring by enabling "allowDestructuredState" option)',
|
||||
suggestPair: 'Destructure useState call into value + setter pair',
|
||||
suggestMemo: 'Replace useState call with useMemo',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Ensure destructuring and symmetric naming of useState hook value and setter variables',
|
||||
category: 'Best Practices',
|
||||
recommended: false,
|
||||
url: docsUrl('hook-use-state'),
|
||||
},
|
||||
messages,
|
||||
schema: [{
|
||||
type: 'object',
|
||||
properties: {
|
||||
allowDestructuredState: {
|
||||
default: false,
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
}],
|
||||
type: 'suggestion',
|
||||
hasSuggestions: true,
|
||||
},
|
||||
|
||||
create: Components.detect((context, components, util) => {
|
||||
const configuration = context.options[0] || {};
|
||||
const allowDestructuredState = configuration.allowDestructuredState || false;
|
||||
|
||||
return {
|
||||
CallExpression(node) {
|
||||
const isImmediateReturn = node.parent
|
||||
&& node.parent.type === 'ReturnStatement';
|
||||
|
||||
if (isImmediateReturn || !util.isReactHookCall(node, ['useState'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isDestructuringDeclarator = node.parent
|
||||
&& node.parent.type === 'VariableDeclarator'
|
||||
&& node.parent.id.type === 'ArrayPattern';
|
||||
|
||||
if (!isDestructuringDeclarator) {
|
||||
report(
|
||||
context,
|
||||
messages.useStateErrorMessage,
|
||||
'useStateErrorMessage',
|
||||
{
|
||||
node,
|
||||
suggest: false,
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const variableNodes = node.parent.id.elements;
|
||||
const valueVariable = variableNodes[0];
|
||||
const setterVariable = variableNodes[1];
|
||||
const isOnlyValueDestructuring = isNodeDestructuring(valueVariable) && !isNodeDestructuring(setterVariable);
|
||||
|
||||
if (allowDestructuredState && isOnlyValueDestructuring) {
|
||||
return;
|
||||
}
|
||||
|
||||
const valueVariableName = valueVariable
|
||||
? valueVariable.name
|
||||
: undefined;
|
||||
|
||||
const setterVariableName = setterVariable
|
||||
? setterVariable.name
|
||||
: undefined;
|
||||
|
||||
const caseCandidateMatch = valueVariableName ? valueVariableName.match(/(^[a-z]+)(.*)/) : undefined;
|
||||
const upperCaseCandidatePrefix = caseCandidateMatch ? caseCandidateMatch[1] : undefined;
|
||||
const caseCandidateSuffix = caseCandidateMatch ? caseCandidateMatch[2] : undefined;
|
||||
const expectedSetterVariableNames = upperCaseCandidatePrefix ? [
|
||||
`set${upperCaseCandidatePrefix.charAt(0).toUpperCase()}${upperCaseCandidatePrefix.slice(1)}${caseCandidateSuffix}`,
|
||||
`set${upperCaseCandidatePrefix.toUpperCase()}${caseCandidateSuffix}`,
|
||||
] : [];
|
||||
|
||||
const isSymmetricGetterSetterPair = valueVariable
|
||||
&& setterVariable
|
||||
&& expectedSetterVariableNames.indexOf(setterVariableName) !== -1
|
||||
&& variableNodes.length === 2;
|
||||
|
||||
if (!isSymmetricGetterSetterPair) {
|
||||
const suggestions = [
|
||||
Object.assign(
|
||||
getMessageData('suggestPair', messages.suggestPair),
|
||||
{
|
||||
fix(fixer) {
|
||||
if (expectedSetterVariableNames.length > 0) {
|
||||
return fixer.replaceTextRange(
|
||||
node.parent.id.range,
|
||||
`[${valueVariableName}, ${expectedSetterVariableNames[0]}]`
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
),
|
||||
];
|
||||
|
||||
const defaultReactImports = components.getDefaultReactImports();
|
||||
const defaultReactImportSpecifier = defaultReactImports
|
||||
? defaultReactImports[0]
|
||||
: undefined;
|
||||
|
||||
const defaultReactImportName = defaultReactImportSpecifier
|
||||
? defaultReactImportSpecifier.local.name
|
||||
: undefined;
|
||||
|
||||
const namedReactImports = components.getNamedReactImports();
|
||||
const useStateReactImportSpecifier = namedReactImports
|
||||
? namedReactImports.find((specifier) => specifier.imported.name === 'useState')
|
||||
: undefined;
|
||||
|
||||
const isSingleGetter = valueVariable && variableNodes.length === 1;
|
||||
const isUseStateCalledWithSingleArgument = node.arguments.length === 1;
|
||||
if (isSingleGetter && isUseStateCalledWithSingleArgument) {
|
||||
const useMemoReactImportSpecifier = namedReactImports
|
||||
&& namedReactImports.find((specifier) => specifier.imported.name === 'useMemo');
|
||||
|
||||
let useMemoCode;
|
||||
if (useMemoReactImportSpecifier) {
|
||||
useMemoCode = useMemoReactImportSpecifier.local.name;
|
||||
} else if (defaultReactImportName) {
|
||||
useMemoCode = `${defaultReactImportName}.useMemo`;
|
||||
} else {
|
||||
useMemoCode = 'useMemo';
|
||||
}
|
||||
|
||||
suggestions.unshift(Object.assign(
|
||||
getMessageData('suggestMemo', messages.suggestMemo),
|
||||
{
|
||||
fix: (fixer) => [
|
||||
// Add useMemo import, if necessary
|
||||
useStateReactImportSpecifier
|
||||
&& (!useMemoReactImportSpecifier || defaultReactImportName)
|
||||
&& fixer.insertTextAfter(useStateReactImportSpecifier, ', useMemo'),
|
||||
// Convert single-value destructure to simple assignment
|
||||
fixer.replaceTextRange(node.parent.id.range, valueVariableName),
|
||||
// Convert useState call to useMemo + arrow function + dependency array
|
||||
fixer.replaceTextRange(
|
||||
node.range,
|
||||
`${useMemoCode}(() => ${getText(context, node.arguments[0])}, [])`
|
||||
),
|
||||
].filter(Boolean),
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
if (isOnlyValueDestructuring) {
|
||||
report(
|
||||
context,
|
||||
messages.useStateErrorMessageOrAddOption,
|
||||
'useStateErrorMessageOrAddOption',
|
||||
{
|
||||
node: node.parent.id,
|
||||
suggest: false,
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
report(
|
||||
context,
|
||||
messages.useStateErrorMessage,
|
||||
'useStateErrorMessage',
|
||||
{
|
||||
node: node.parent.id,
|
||||
suggest: suggestions,
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
}),
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/iframe-missing-sandbox.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/iframe-missing-sandbox.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=iframe-missing-sandbox.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/iframe-missing-sandbox.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/iframe-missing-sandbox.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"iframe-missing-sandbox.d.ts","sourceRoot":"","sources":["iframe-missing-sandbox.js"],"names":[],"mappings":"wBA+GW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
143
Lab/node_modules/eslint-plugin-react/lib/rules/iframe-missing-sandbox.js
generated
vendored
Normal file
143
Lab/node_modules/eslint-plugin-react/lib/rules/iframe-missing-sandbox.js
generated
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* @fileoverview TBD
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const isCreateElement = require('../util/isCreateElement');
|
||||
const report = require('../util/report');
|
||||
|
||||
const messages = {
|
||||
attributeMissing: 'An iframe element is missing a sandbox attribute',
|
||||
invalidValue: 'An iframe element defines a sandbox attribute with invalid value "{{ value }}"',
|
||||
invalidCombination: 'An iframe element defines a sandbox attribute with both allow-scripts and allow-same-origin which is invalid',
|
||||
};
|
||||
|
||||
const ALLOWED_VALUES = [
|
||||
// From https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-sandbox
|
||||
'',
|
||||
'allow-downloads-without-user-activation',
|
||||
'allow-downloads',
|
||||
'allow-forms',
|
||||
'allow-modals',
|
||||
'allow-orientation-lock',
|
||||
'allow-pointer-lock',
|
||||
'allow-popups',
|
||||
'allow-popups-to-escape-sandbox',
|
||||
'allow-presentation',
|
||||
'allow-same-origin',
|
||||
'allow-scripts',
|
||||
'allow-storage-access-by-user-activation',
|
||||
'allow-top-navigation',
|
||||
'allow-top-navigation-by-user-activation',
|
||||
];
|
||||
|
||||
function validateSandboxAttribute(context, node, attribute) {
|
||||
if (typeof attribute !== 'string') {
|
||||
// Only string literals are supported for now
|
||||
return;
|
||||
}
|
||||
const values = attribute.split(' ');
|
||||
let allowScripts = false;
|
||||
let allowSameOrigin = false;
|
||||
values.forEach((attributeValue) => {
|
||||
const trimmedAttributeValue = attributeValue.trim();
|
||||
if (ALLOWED_VALUES.indexOf(trimmedAttributeValue) === -1) {
|
||||
report(context, messages.invalidValue, 'invalidValue', {
|
||||
node,
|
||||
data: {
|
||||
value: trimmedAttributeValue,
|
||||
},
|
||||
});
|
||||
}
|
||||
if (trimmedAttributeValue === 'allow-scripts') {
|
||||
allowScripts = true;
|
||||
}
|
||||
if (trimmedAttributeValue === 'allow-same-origin') {
|
||||
allowSameOrigin = true;
|
||||
}
|
||||
});
|
||||
if (allowScripts && allowSameOrigin) {
|
||||
report(context, messages.invalidCombination, 'invalidCombination', {
|
||||
node,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function checkAttributes(context, node) {
|
||||
let sandboxAttributeFound = false;
|
||||
node.attributes.forEach((attribute) => {
|
||||
if (attribute.type === 'JSXAttribute'
|
||||
&& attribute.name
|
||||
&& attribute.name.type === 'JSXIdentifier'
|
||||
&& attribute.name.name === 'sandbox'
|
||||
) {
|
||||
sandboxAttributeFound = true;
|
||||
if (
|
||||
attribute.value
|
||||
&& attribute.value.type === 'Literal'
|
||||
&& attribute.value.value
|
||||
) {
|
||||
validateSandboxAttribute(context, node, attribute.value.value);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (!sandboxAttributeFound) {
|
||||
report(context, messages.attributeMissing, 'attributeMissing', {
|
||||
node,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function checkProps(context, node) {
|
||||
let sandboxAttributeFound = false;
|
||||
if (node.arguments.length > 1) {
|
||||
const props = node.arguments[1];
|
||||
const sandboxProp = props.properties && props.properties.find((x) => x.type === 'Property' && x.key.name === 'sandbox');
|
||||
if (sandboxProp) {
|
||||
sandboxAttributeFound = true;
|
||||
if (sandboxProp.value && sandboxProp.value.type === 'Literal' && sandboxProp.value.value) {
|
||||
validateSandboxAttribute(context, node, sandboxProp.value.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!sandboxAttributeFound) {
|
||||
report(context, messages.attributeMissing, 'attributeMissing', {
|
||||
node,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Enforce sandbox attribute on iframe elements',
|
||||
category: 'Best Practices',
|
||||
recommended: false,
|
||||
url: docsUrl('iframe-missing-sandbox'),
|
||||
},
|
||||
|
||||
schema: [],
|
||||
|
||||
messages,
|
||||
},
|
||||
|
||||
create(context) {
|
||||
return {
|
||||
'JSXOpeningElement[name.name="iframe"]'(node) {
|
||||
checkAttributes(context, node);
|
||||
},
|
||||
|
||||
CallExpression(node) {
|
||||
if (isCreateElement(context, node) && node.arguments && node.arguments.length > 0) {
|
||||
const tag = node.arguments[0];
|
||||
if (tag.type === 'Literal' && tag.value === 'iframe') {
|
||||
checkProps(context, node);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
108
Lab/node_modules/eslint-plugin-react/lib/rules/index.d.ts
generated
vendored
Normal file
108
Lab/node_modules/eslint-plugin-react/lib/rules/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
export = rules;
|
||||
/** @satisfies {Record<string, import('eslint').Rule.RuleModule>} */
|
||||
declare const rules: {
|
||||
'boolean-prop-naming': import("eslint").Rule.RuleModule;
|
||||
'button-has-type': import("eslint").Rule.RuleModule;
|
||||
'checked-requires-onchange-or-readonly': import("eslint").Rule.RuleModule;
|
||||
'default-props-match-prop-types': import("eslint").Rule.RuleModule;
|
||||
'destructuring-assignment': import("eslint").Rule.RuleModule;
|
||||
'display-name': import("eslint").Rule.RuleModule;
|
||||
'forbid-component-props': import("eslint").Rule.RuleModule;
|
||||
'forbid-dom-props': import("eslint").Rule.RuleModule;
|
||||
'forbid-elements': import("eslint").Rule.RuleModule;
|
||||
'forbid-foreign-prop-types': import("eslint").Rule.RuleModule;
|
||||
'forbid-prop-types': import("eslint").Rule.RuleModule;
|
||||
'forward-ref-uses-ref': import("eslint").Rule.RuleModule;
|
||||
'function-component-definition': import("eslint").Rule.RuleModule;
|
||||
'hook-use-state': import("eslint").Rule.RuleModule;
|
||||
'iframe-missing-sandbox': import("eslint").Rule.RuleModule;
|
||||
'jsx-boolean-value': import("eslint").Rule.RuleModule;
|
||||
'jsx-child-element-spacing': import("eslint").Rule.RuleModule;
|
||||
'jsx-closing-bracket-location': import("eslint").Rule.RuleModule;
|
||||
'jsx-closing-tag-location': import("eslint").Rule.RuleModule;
|
||||
'jsx-curly-spacing': import("eslint").Rule.RuleModule;
|
||||
'jsx-curly-newline': import("eslint").Rule.RuleModule;
|
||||
'jsx-equals-spacing': import("eslint").Rule.RuleModule;
|
||||
'jsx-filename-extension': import("eslint").Rule.RuleModule;
|
||||
'jsx-first-prop-new-line': import("eslint").Rule.RuleModule;
|
||||
'jsx-handler-names': import("eslint").Rule.RuleModule;
|
||||
'jsx-indent': import("eslint").Rule.RuleModule;
|
||||
'jsx-indent-props': import("eslint").Rule.RuleModule;
|
||||
'jsx-key': import("eslint").Rule.RuleModule;
|
||||
'jsx-max-depth': import("eslint").Rule.RuleModule;
|
||||
'jsx-max-props-per-line': import("eslint").Rule.RuleModule;
|
||||
'jsx-newline': import("eslint").Rule.RuleModule;
|
||||
'jsx-no-bind': import("eslint").Rule.RuleModule;
|
||||
'jsx-no-comment-textnodes': import("eslint").Rule.RuleModule;
|
||||
'jsx-no-constructed-context-values': import("eslint").Rule.RuleModule;
|
||||
'jsx-no-duplicate-props': import("eslint").Rule.RuleModule;
|
||||
'jsx-no-leaked-render': import("eslint").Rule.RuleModule;
|
||||
'jsx-no-literals': import("eslint").Rule.RuleModule;
|
||||
'jsx-no-script-url': import("eslint").Rule.RuleModule;
|
||||
'jsx-no-target-blank': import("eslint").Rule.RuleModule;
|
||||
'jsx-no-useless-fragment': import("eslint").Rule.RuleModule;
|
||||
'jsx-one-expression-per-line': import("eslint").Rule.RuleModule;
|
||||
'jsx-no-undef': import("eslint").Rule.RuleModule;
|
||||
'jsx-curly-brace-presence': import("eslint").Rule.RuleModule;
|
||||
'jsx-pascal-case': import("eslint").Rule.RuleModule;
|
||||
'jsx-fragments': import("eslint").Rule.RuleModule;
|
||||
'jsx-props-no-multi-spaces': import("eslint").Rule.RuleModule;
|
||||
'jsx-props-no-spreading': import("eslint").Rule.RuleModule;
|
||||
'jsx-props-no-spread-multi': import("eslint").Rule.RuleModule;
|
||||
'jsx-sort-default-props': import("eslint").Rule.RuleModule;
|
||||
'jsx-sort-props': import("eslint").Rule.RuleModule;
|
||||
'jsx-space-before-closing': import("eslint").Rule.RuleModule;
|
||||
'jsx-tag-spacing': import("eslint").Rule.RuleModule;
|
||||
'jsx-uses-react': import("eslint").Rule.RuleModule;
|
||||
'jsx-uses-vars': import("eslint").Rule.RuleModule;
|
||||
'jsx-wrap-multilines': import("eslint").Rule.RuleModule;
|
||||
'no-invalid-html-attribute': import("eslint").Rule.RuleModule;
|
||||
'no-access-state-in-setstate': import("eslint").Rule.RuleModule;
|
||||
'no-adjacent-inline-elements': import("eslint").Rule.RuleModule;
|
||||
'no-array-index-key': import("eslint").Rule.RuleModule;
|
||||
'no-arrow-function-lifecycle': import("eslint").Rule.RuleModule;
|
||||
'no-children-prop': import("eslint").Rule.RuleModule;
|
||||
'no-danger': import("eslint").Rule.RuleModule;
|
||||
'no-danger-with-children': import("eslint").Rule.RuleModule;
|
||||
'no-deprecated': import("eslint").Rule.RuleModule;
|
||||
'no-did-mount-set-state': import("eslint").Rule.RuleModule;
|
||||
'no-did-update-set-state': import("eslint").Rule.RuleModule;
|
||||
'no-direct-mutation-state': import("eslint").Rule.RuleModule;
|
||||
'no-find-dom-node': import("eslint").Rule.RuleModule;
|
||||
'no-is-mounted': import("eslint").Rule.RuleModule;
|
||||
'no-multi-comp': import("eslint").Rule.RuleModule;
|
||||
'no-namespace': import("eslint").Rule.RuleModule;
|
||||
'no-set-state': import("eslint").Rule.RuleModule;
|
||||
'no-string-refs': import("eslint").Rule.RuleModule;
|
||||
'no-redundant-should-component-update': import("eslint").Rule.RuleModule;
|
||||
'no-render-return-value': import("eslint").Rule.RuleModule;
|
||||
'no-this-in-sfc': import("eslint").Rule.RuleModule;
|
||||
'no-typos': import("eslint").Rule.RuleModule;
|
||||
'no-unescaped-entities': import("eslint").Rule.RuleModule;
|
||||
'no-unknown-property': import("eslint").Rule.RuleModule;
|
||||
'no-unsafe': import("eslint").Rule.RuleModule;
|
||||
'no-unstable-nested-components': import("eslint").Rule.RuleModule;
|
||||
'no-unused-class-component-methods': import("eslint").Rule.RuleModule;
|
||||
'no-unused-prop-types': import("eslint").Rule.RuleModule;
|
||||
'no-unused-state': import("eslint").Rule.RuleModule;
|
||||
'no-object-type-as-default-prop': import("eslint").Rule.RuleModule;
|
||||
'no-will-update-set-state': import("eslint").Rule.RuleModule;
|
||||
'prefer-es6-class': import("eslint").Rule.RuleModule;
|
||||
'prefer-exact-props': import("eslint").Rule.RuleModule;
|
||||
'prefer-read-only-props': import("eslint").Rule.RuleModule;
|
||||
'prefer-stateless-function': import("eslint").Rule.RuleModule;
|
||||
'prop-types': import("eslint").Rule.RuleModule;
|
||||
'react-in-jsx-scope': import("eslint").Rule.RuleModule;
|
||||
'require-default-props': import("eslint").Rule.RuleModule;
|
||||
'require-optimization': import("eslint").Rule.RuleModule;
|
||||
'require-render-return': import("eslint").Rule.RuleModule;
|
||||
'self-closing-comp': import("eslint").Rule.RuleModule;
|
||||
'sort-comp': import("eslint").Rule.RuleModule;
|
||||
'sort-default-props': import("eslint").Rule.RuleModule;
|
||||
'sort-prop-types': import("eslint").Rule.RuleModule;
|
||||
'state-in-constructor': import("eslint").Rule.RuleModule;
|
||||
'static-property-placement': import("eslint").Rule.RuleModule;
|
||||
'style-prop-object': import("eslint").Rule.RuleModule;
|
||||
'void-dom-elements-no-children': import("eslint").Rule.RuleModule;
|
||||
};
|
||||
//# sourceMappingURL=index.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/index.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/index.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.js"],"names":[],"mappings":";AAIA,oEAAoE;AACpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwGE"}
|
||||
112
Lab/node_modules/eslint-plugin-react/lib/rules/index.js
generated
vendored
Normal file
112
Lab/node_modules/eslint-plugin-react/lib/rules/index.js
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
'use strict';
|
||||
|
||||
/* eslint global-require: 0 */
|
||||
|
||||
/** @satisfies {Record<string, import('eslint').Rule.RuleModule>} */
|
||||
const rules = {
|
||||
'boolean-prop-naming': require('./boolean-prop-naming'),
|
||||
'button-has-type': require('./button-has-type'),
|
||||
'checked-requires-onchange-or-readonly': require('./checked-requires-onchange-or-readonly'),
|
||||
'default-props-match-prop-types': require('./default-props-match-prop-types'),
|
||||
'destructuring-assignment': require('./destructuring-assignment'),
|
||||
'display-name': require('./display-name'),
|
||||
'forbid-component-props': require('./forbid-component-props'),
|
||||
'forbid-dom-props': require('./forbid-dom-props'),
|
||||
'forbid-elements': require('./forbid-elements'),
|
||||
'forbid-foreign-prop-types': require('./forbid-foreign-prop-types'),
|
||||
'forbid-prop-types': require('./forbid-prop-types'),
|
||||
'forward-ref-uses-ref': require('./forward-ref-uses-ref'),
|
||||
'function-component-definition': require('./function-component-definition'),
|
||||
'hook-use-state': require('./hook-use-state'),
|
||||
'iframe-missing-sandbox': require('./iframe-missing-sandbox'),
|
||||
'jsx-boolean-value': require('./jsx-boolean-value'),
|
||||
'jsx-child-element-spacing': require('./jsx-child-element-spacing'),
|
||||
'jsx-closing-bracket-location': require('./jsx-closing-bracket-location'),
|
||||
'jsx-closing-tag-location': require('./jsx-closing-tag-location'),
|
||||
'jsx-curly-spacing': require('./jsx-curly-spacing'),
|
||||
'jsx-curly-newline': require('./jsx-curly-newline'),
|
||||
'jsx-equals-spacing': require('./jsx-equals-spacing'),
|
||||
'jsx-filename-extension': require('./jsx-filename-extension'),
|
||||
'jsx-first-prop-new-line': require('./jsx-first-prop-new-line'),
|
||||
'jsx-handler-names': require('./jsx-handler-names'),
|
||||
'jsx-indent': require('./jsx-indent'),
|
||||
'jsx-indent-props': require('./jsx-indent-props'),
|
||||
'jsx-key': require('./jsx-key'),
|
||||
'jsx-max-depth': require('./jsx-max-depth'),
|
||||
'jsx-max-props-per-line': require('./jsx-max-props-per-line'),
|
||||
'jsx-newline': require('./jsx-newline'),
|
||||
'jsx-no-bind': require('./jsx-no-bind'),
|
||||
'jsx-no-comment-textnodes': require('./jsx-no-comment-textnodes'),
|
||||
'jsx-no-constructed-context-values': require('./jsx-no-constructed-context-values'),
|
||||
'jsx-no-duplicate-props': require('./jsx-no-duplicate-props'),
|
||||
'jsx-no-leaked-render': require('./jsx-no-leaked-render'),
|
||||
'jsx-no-literals': require('./jsx-no-literals'),
|
||||
'jsx-no-script-url': require('./jsx-no-script-url'),
|
||||
'jsx-no-target-blank': require('./jsx-no-target-blank'),
|
||||
'jsx-no-useless-fragment': require('./jsx-no-useless-fragment'),
|
||||
'jsx-one-expression-per-line': require('./jsx-one-expression-per-line'),
|
||||
'jsx-no-undef': require('./jsx-no-undef'),
|
||||
'jsx-curly-brace-presence': require('./jsx-curly-brace-presence'),
|
||||
'jsx-pascal-case': require('./jsx-pascal-case'),
|
||||
'jsx-fragments': require('./jsx-fragments'),
|
||||
'jsx-props-no-multi-spaces': require('./jsx-props-no-multi-spaces'),
|
||||
'jsx-props-no-spreading': require('./jsx-props-no-spreading'),
|
||||
'jsx-props-no-spread-multi': require('./jsx-props-no-spread-multi'),
|
||||
'jsx-sort-default-props': require('./jsx-sort-default-props'),
|
||||
'jsx-sort-props': require('./jsx-sort-props'),
|
||||
'jsx-space-before-closing': require('./jsx-space-before-closing'),
|
||||
'jsx-tag-spacing': require('./jsx-tag-spacing'),
|
||||
'jsx-uses-react': require('./jsx-uses-react'),
|
||||
'jsx-uses-vars': require('./jsx-uses-vars'),
|
||||
'jsx-wrap-multilines': require('./jsx-wrap-multilines'),
|
||||
'no-invalid-html-attribute': require('./no-invalid-html-attribute'),
|
||||
'no-access-state-in-setstate': require('./no-access-state-in-setstate'),
|
||||
'no-adjacent-inline-elements': require('./no-adjacent-inline-elements'),
|
||||
'no-array-index-key': require('./no-array-index-key'),
|
||||
'no-arrow-function-lifecycle': require('./no-arrow-function-lifecycle'),
|
||||
'no-children-prop': require('./no-children-prop'),
|
||||
'no-danger': require('./no-danger'),
|
||||
'no-danger-with-children': require('./no-danger-with-children'),
|
||||
'no-deprecated': require('./no-deprecated'),
|
||||
'no-did-mount-set-state': require('./no-did-mount-set-state'),
|
||||
'no-did-update-set-state': require('./no-did-update-set-state'),
|
||||
'no-direct-mutation-state': require('./no-direct-mutation-state'),
|
||||
'no-find-dom-node': require('./no-find-dom-node'),
|
||||
'no-is-mounted': require('./no-is-mounted'),
|
||||
'no-multi-comp': require('./no-multi-comp'),
|
||||
'no-namespace': require('./no-namespace'),
|
||||
'no-set-state': require('./no-set-state'),
|
||||
'no-string-refs': require('./no-string-refs'),
|
||||
'no-redundant-should-component-update': require('./no-redundant-should-component-update'),
|
||||
'no-render-return-value': require('./no-render-return-value'),
|
||||
'no-this-in-sfc': require('./no-this-in-sfc'),
|
||||
'no-typos': require('./no-typos'),
|
||||
'no-unescaped-entities': require('./no-unescaped-entities'),
|
||||
'no-unknown-property': require('./no-unknown-property'),
|
||||
'no-unsafe': require('./no-unsafe'),
|
||||
'no-unstable-nested-components': require('./no-unstable-nested-components'),
|
||||
'no-unused-class-component-methods': require('./no-unused-class-component-methods'),
|
||||
'no-unused-prop-types': require('./no-unused-prop-types'),
|
||||
'no-unused-state': require('./no-unused-state'),
|
||||
'no-object-type-as-default-prop': require('./no-object-type-as-default-prop'),
|
||||
'no-will-update-set-state': require('./no-will-update-set-state'),
|
||||
'prefer-es6-class': require('./prefer-es6-class'),
|
||||
'prefer-exact-props': require('./prefer-exact-props'),
|
||||
'prefer-read-only-props': require('./prefer-read-only-props'),
|
||||
'prefer-stateless-function': require('./prefer-stateless-function'),
|
||||
'prop-types': require('./prop-types'),
|
||||
'react-in-jsx-scope': require('./react-in-jsx-scope'),
|
||||
'require-default-props': require('./require-default-props'),
|
||||
'require-optimization': require('./require-optimization'),
|
||||
'require-render-return': require('./require-render-return'),
|
||||
'self-closing-comp': require('./self-closing-comp'),
|
||||
'sort-comp': require('./sort-comp'),
|
||||
'sort-default-props': require('./sort-default-props'),
|
||||
'sort-prop-types': require('./sort-prop-types'),
|
||||
'state-in-constructor': require('./state-in-constructor'),
|
||||
'static-property-placement': require('./static-property-placement'),
|
||||
'style-prop-object': require('./style-prop-object'),
|
||||
'void-dom-elements-no-children': require('./void-dom-elements-no-children'),
|
||||
};
|
||||
|
||||
module.exports = rules;
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-boolean-value.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-boolean-value.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=jsx-boolean-value.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-boolean-value.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-boolean-value.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"jsx-boolean-value.d.ts","sourceRoot":"","sources":["jsx-boolean-value.js"],"names":[],"mappings":"wBAwDW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
169
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-boolean-value.js
generated
vendored
Normal file
169
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-boolean-value.js
generated
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* @fileoverview Enforce boolean attributes notation in JSX
|
||||
* @author Yannick Croissant
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const report = require('../util/report');
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const exceptionsSchema = {
|
||||
type: 'array',
|
||||
items: { type: 'string', minLength: 1 },
|
||||
uniqueItems: true,
|
||||
};
|
||||
|
||||
const ALWAYS = 'always';
|
||||
const NEVER = 'never';
|
||||
|
||||
/**
|
||||
* @param {string} configuration
|
||||
* @param {Set<string>} exceptions
|
||||
* @param {string} propName
|
||||
* @returns {boolean} propName
|
||||
*/
|
||||
function isAlways(configuration, exceptions, propName) {
|
||||
const isException = exceptions.has(propName);
|
||||
if (configuration === ALWAYS) {
|
||||
return !isException;
|
||||
}
|
||||
return isException;
|
||||
}
|
||||
/**
|
||||
* @param {string} configuration
|
||||
* @param {Set<string>} exceptions
|
||||
* @param {string} propName
|
||||
* @returns {boolean} propName
|
||||
*/
|
||||
function isNever(configuration, exceptions, propName) {
|
||||
const isException = exceptions.has(propName);
|
||||
if (configuration === NEVER) {
|
||||
return !isException;
|
||||
}
|
||||
return isException;
|
||||
}
|
||||
|
||||
const messages = {
|
||||
omitBoolean: 'Value must be omitted for boolean attribute `{{propName}}`',
|
||||
setBoolean: 'Value must be set for boolean attribute `{{propName}}`',
|
||||
omitPropAndBoolean: 'Value must be omitted for `false` attribute: `{{propName}}`',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Enforce boolean attributes notation in JSX',
|
||||
category: 'Stylistic Issues',
|
||||
recommended: false,
|
||||
url: docsUrl('jsx-boolean-value'),
|
||||
},
|
||||
fixable: 'code',
|
||||
|
||||
messages,
|
||||
|
||||
schema: {
|
||||
anyOf: [{
|
||||
type: 'array',
|
||||
items: [{ enum: [ALWAYS, NEVER] }],
|
||||
additionalItems: false,
|
||||
}, {
|
||||
type: 'array',
|
||||
items: [{
|
||||
enum: [ALWAYS],
|
||||
}, {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
[NEVER]: exceptionsSchema,
|
||||
assumeUndefinedIsFalse: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
}],
|
||||
additionalItems: false,
|
||||
}, {
|
||||
type: 'array',
|
||||
items: [{
|
||||
enum: [NEVER],
|
||||
}, {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
[ALWAYS]: exceptionsSchema,
|
||||
assumeUndefinedIsFalse: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
}],
|
||||
additionalItems: false,
|
||||
}],
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const configuration = context.options[0] || NEVER;
|
||||
const configObject = context.options[1] || {};
|
||||
const exceptions = new Set((configuration === ALWAYS ? configObject[NEVER] : configObject[ALWAYS]) || []);
|
||||
|
||||
return {
|
||||
JSXAttribute(node) {
|
||||
const propName = node.name && node.name.name;
|
||||
const value = node.value;
|
||||
|
||||
if (
|
||||
isAlways(configuration, exceptions, propName)
|
||||
&& value === null
|
||||
) {
|
||||
const messageId = 'setBoolean';
|
||||
const data = { propName };
|
||||
report(context, messages[messageId], messageId, {
|
||||
node,
|
||||
data,
|
||||
fix(fixer) {
|
||||
return fixer.insertTextAfter(node, '={true}');
|
||||
},
|
||||
});
|
||||
}
|
||||
if (
|
||||
isNever(configuration, exceptions, propName)
|
||||
&& value
|
||||
&& value.type === 'JSXExpressionContainer'
|
||||
&& value.expression.value === true
|
||||
) {
|
||||
const messageId = 'omitBoolean';
|
||||
const data = { propName };
|
||||
report(context, messages[messageId], messageId, {
|
||||
node,
|
||||
data,
|
||||
fix(fixer) {
|
||||
return fixer.removeRange([node.name.range[1], value.range[1]]);
|
||||
},
|
||||
});
|
||||
}
|
||||
if (
|
||||
isNever(configuration, exceptions, propName)
|
||||
&& configObject.assumeUndefinedIsFalse
|
||||
&& value
|
||||
&& value.type === 'JSXExpressionContainer'
|
||||
&& value.expression.value === false
|
||||
) {
|
||||
const messageId = 'omitPropAndBoolean';
|
||||
const data = { propName };
|
||||
report(context, messages[messageId], messageId, {
|
||||
node,
|
||||
data,
|
||||
fix(fixer) {
|
||||
return fixer.removeRange([node.name.range[0], value.range[1]]);
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-child-element-spacing.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-child-element-spacing.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=jsx-child-element-spacing.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-child-element-spacing.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-child-element-spacing.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"jsx-child-element-spacing.d.ts","sourceRoot":"","sources":["jsx-child-element-spacing.js"],"names":[],"mappings":"wBA8CW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
117
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-child-element-spacing.js
generated
vendored
Normal file
117
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-child-element-spacing.js
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
'use strict';
|
||||
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const report = require('../util/report');
|
||||
|
||||
// This list is taken from https://developer.mozilla.org/en-US/docs/Web/HTML/Inline_elements
|
||||
|
||||
// Note: 'br' is not included because whitespace around br tags is inconsequential to the rendered output
|
||||
const INLINE_ELEMENTS = new Set([
|
||||
'a',
|
||||
'abbr',
|
||||
'acronym',
|
||||
'b',
|
||||
'bdo',
|
||||
'big',
|
||||
'button',
|
||||
'cite',
|
||||
'code',
|
||||
'dfn',
|
||||
'em',
|
||||
'i',
|
||||
'img',
|
||||
'input',
|
||||
'kbd',
|
||||
'label',
|
||||
'map',
|
||||
'object',
|
||||
'q',
|
||||
'samp',
|
||||
'script',
|
||||
'select',
|
||||
'small',
|
||||
'span',
|
||||
'strong',
|
||||
'sub',
|
||||
'sup',
|
||||
'textarea',
|
||||
'tt',
|
||||
'var',
|
||||
]);
|
||||
|
||||
const messages = {
|
||||
spacingAfterPrev: 'Ambiguous spacing after previous element {{element}}',
|
||||
spacingBeforeNext: 'Ambiguous spacing before next element {{element}}',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Enforce or disallow spaces inside of curly braces in JSX attributes and expressions',
|
||||
category: 'Stylistic Issues',
|
||||
recommended: false,
|
||||
url: docsUrl('jsx-child-element-spacing'),
|
||||
},
|
||||
fixable: null,
|
||||
|
||||
messages,
|
||||
|
||||
schema: [],
|
||||
},
|
||||
create(context) {
|
||||
const TEXT_FOLLOWING_ELEMENT_PATTERN = /^\s*\n\s*\S/;
|
||||
const TEXT_PRECEDING_ELEMENT_PATTERN = /\S\s*\n\s*$/;
|
||||
|
||||
const elementName = (node) => (
|
||||
node.openingElement
|
||||
&& node.openingElement.name
|
||||
&& node.openingElement.name.type === 'JSXIdentifier'
|
||||
&& node.openingElement.name.name
|
||||
);
|
||||
|
||||
const isInlineElement = (node) => (
|
||||
node.type === 'JSXElement'
|
||||
&& INLINE_ELEMENTS.has(elementName(node))
|
||||
);
|
||||
|
||||
const handleJSX = (node) => {
|
||||
let lastChild = null;
|
||||
let child = null;
|
||||
(node.children.concat([null])).forEach((nextChild) => {
|
||||
if (
|
||||
(lastChild || nextChild)
|
||||
&& (!lastChild || isInlineElement(lastChild))
|
||||
&& (child && (child.type === 'Literal' || child.type === 'JSXText'))
|
||||
&& (!nextChild || isInlineElement(nextChild))
|
||||
&& true
|
||||
) {
|
||||
if (lastChild && child.value.match(TEXT_FOLLOWING_ELEMENT_PATTERN)) {
|
||||
report(context, messages.spacingAfterPrev, 'spacingAfterPrev', {
|
||||
node: lastChild,
|
||||
loc: lastChild.loc.end,
|
||||
data: {
|
||||
element: elementName(lastChild),
|
||||
},
|
||||
});
|
||||
} else if (nextChild && child.value.match(TEXT_PRECEDING_ELEMENT_PATTERN)) {
|
||||
report(context, messages.spacingBeforeNext, 'spacingBeforeNext', {
|
||||
node: nextChild,
|
||||
loc: nextChild.loc.start,
|
||||
data: {
|
||||
element: elementName(nextChild),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
lastChild = child;
|
||||
child = nextChild;
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
JSXElement: handleJSX,
|
||||
JSXFragment: handleJSX,
|
||||
};
|
||||
},
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-closing-bracket-location.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-closing-bracket-location.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=jsx-closing-bracket-location.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-closing-bracket-location.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-closing-bracket-location.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"jsx-closing-bracket-location.d.ts","sourceRoot":"","sources":["jsx-closing-bracket-location.js"],"names":[],"mappings":"wBAsBW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
315
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-closing-bracket-location.js
generated
vendored
Normal file
315
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-closing-bracket-location.js
generated
vendored
Normal file
@@ -0,0 +1,315 @@
|
||||
/**
|
||||
* @fileoverview Validate closing bracket location in JSX
|
||||
* @author Yannick Croissant
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const has = require('hasown');
|
||||
const repeat = require('string.prototype.repeat');
|
||||
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const getSourceCode = require('../util/eslint').getSourceCode;
|
||||
const report = require('../util/report');
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const messages = {
|
||||
bracketLocation: 'The closing bracket must be {{location}}{{details}}',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Enforce closing bracket location in JSX',
|
||||
category: 'Stylistic Issues',
|
||||
recommended: false,
|
||||
url: docsUrl('jsx-closing-bracket-location'),
|
||||
},
|
||||
fixable: 'code',
|
||||
|
||||
messages,
|
||||
|
||||
schema: [{
|
||||
anyOf: [
|
||||
{
|
||||
enum: ['after-props', 'props-aligned', 'tag-aligned', 'line-aligned'],
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
location: {
|
||||
enum: ['after-props', 'props-aligned', 'tag-aligned', 'line-aligned'],
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
nonEmpty: {
|
||||
enum: ['after-props', 'props-aligned', 'tag-aligned', 'line-aligned', false],
|
||||
},
|
||||
selfClosing: {
|
||||
enum: ['after-props', 'props-aligned', 'tag-aligned', 'line-aligned', false],
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
}],
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const MESSAGE_LOCATION = {
|
||||
'after-props': 'placed after the last prop',
|
||||
'after-tag': 'placed after the opening tag',
|
||||
'props-aligned': 'aligned with the last prop',
|
||||
'tag-aligned': 'aligned with the opening tag',
|
||||
'line-aligned': 'aligned with the line containing the opening tag',
|
||||
};
|
||||
const DEFAULT_LOCATION = 'tag-aligned';
|
||||
|
||||
const config = context.options[0];
|
||||
const options = {
|
||||
nonEmpty: DEFAULT_LOCATION,
|
||||
selfClosing: DEFAULT_LOCATION,
|
||||
};
|
||||
|
||||
if (typeof config === 'string') {
|
||||
// simple shorthand [1, 'something']
|
||||
options.nonEmpty = config;
|
||||
options.selfClosing = config;
|
||||
} else if (typeof config === 'object') {
|
||||
// [1, {location: 'something'}] (back-compat)
|
||||
if (has(config, 'location')) {
|
||||
options.nonEmpty = config.location;
|
||||
options.selfClosing = config.location;
|
||||
}
|
||||
// [1, {nonEmpty: 'something'}]
|
||||
if (has(config, 'nonEmpty')) {
|
||||
options.nonEmpty = config.nonEmpty;
|
||||
}
|
||||
// [1, {selfClosing: 'something'}]
|
||||
if (has(config, 'selfClosing')) {
|
||||
options.selfClosing = config.selfClosing;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get expected location for the closing bracket
|
||||
* @param {Object} tokens Locations of the opening bracket, closing bracket and last prop
|
||||
* @return {string} Expected location for the closing bracket
|
||||
*/
|
||||
function getExpectedLocation(tokens) {
|
||||
let location;
|
||||
// Is always after the opening tag if there is no props
|
||||
if (typeof tokens.lastProp === 'undefined') {
|
||||
location = 'after-tag';
|
||||
// Is always after the last prop if this one is on the same line as the opening bracket
|
||||
} else if (tokens.opening.line === tokens.lastProp.lastLine) {
|
||||
location = 'after-props';
|
||||
// Else use configuration dependent on selfClosing property
|
||||
} else {
|
||||
location = tokens.selfClosing ? options.selfClosing : options.nonEmpty;
|
||||
}
|
||||
return location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the correct 0-indexed column for the closing bracket, given the
|
||||
* expected location.
|
||||
* @param {Object} tokens Locations of the opening bracket, closing bracket and last prop
|
||||
* @param {string} expectedLocation Expected location for the closing bracket
|
||||
* @return {?Number} The correct column for the closing bracket, or null
|
||||
*/
|
||||
function getCorrectColumn(tokens, expectedLocation) {
|
||||
switch (expectedLocation) {
|
||||
case 'props-aligned':
|
||||
return tokens.lastProp.column;
|
||||
case 'tag-aligned':
|
||||
return tokens.opening.column;
|
||||
case 'line-aligned':
|
||||
return tokens.openingStartOfLine.column;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the closing bracket is correctly located
|
||||
* @param {Object} tokens Locations of the opening bracket, closing bracket and last prop
|
||||
* @param {string} expectedLocation Expected location for the closing bracket
|
||||
* @return {boolean} True if the closing bracket is correctly located, false if not
|
||||
*/
|
||||
function hasCorrectLocation(tokens, expectedLocation) {
|
||||
switch (expectedLocation) {
|
||||
case 'after-tag':
|
||||
return tokens.tag.line === tokens.closing.line;
|
||||
case 'after-props':
|
||||
return tokens.lastProp.lastLine === tokens.closing.line;
|
||||
case 'props-aligned':
|
||||
case 'tag-aligned':
|
||||
case 'line-aligned': {
|
||||
const correctColumn = getCorrectColumn(tokens, expectedLocation);
|
||||
return correctColumn === tokens.closing.column;
|
||||
}
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the characters used for indentation on the line to be matched
|
||||
* @param {Object} tokens Locations of the opening bracket, closing bracket and last prop
|
||||
* @param {string} expectedLocation Expected location for the closing bracket
|
||||
* @param {number} [correctColumn] Expected column for the closing bracket. Default to 0
|
||||
* @return {string} The characters used for indentation
|
||||
*/
|
||||
function getIndentation(tokens, expectedLocation, correctColumn) {
|
||||
const newColumn = correctColumn || 0;
|
||||
let indentation;
|
||||
let spaces = '';
|
||||
switch (expectedLocation) {
|
||||
case 'props-aligned':
|
||||
indentation = /^\s*/.exec(getSourceCode(context).lines[tokens.lastProp.firstLine - 1])[0];
|
||||
break;
|
||||
case 'tag-aligned':
|
||||
case 'line-aligned':
|
||||
indentation = /^\s*/.exec(getSourceCode(context).lines[tokens.opening.line - 1])[0];
|
||||
break;
|
||||
default:
|
||||
indentation = '';
|
||||
}
|
||||
if (indentation.length + 1 < newColumn) {
|
||||
// Non-whitespace characters were included in the column offset
|
||||
spaces = repeat(' ', +correctColumn - indentation.length);
|
||||
}
|
||||
return indentation + spaces;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the locations of the opening bracket, closing bracket, last prop, and
|
||||
* start of opening line.
|
||||
* @param {ASTNode} node The node to check
|
||||
* @return {Object} Locations of the opening bracket, closing bracket, last
|
||||
* prop and start of opening line.
|
||||
*/
|
||||
function getTokensLocations(node) {
|
||||
const sourceCode = getSourceCode(context);
|
||||
const opening = sourceCode.getFirstToken(node).loc.start;
|
||||
const closing = sourceCode.getLastTokens(node, node.selfClosing ? 2 : 1)[0].loc.start;
|
||||
const tag = sourceCode.getFirstToken(node.name).loc.start;
|
||||
let lastProp;
|
||||
if (node.attributes.length) {
|
||||
lastProp = node.attributes[node.attributes.length - 1];
|
||||
lastProp = {
|
||||
column: sourceCode.getFirstToken(lastProp).loc.start.column,
|
||||
firstLine: sourceCode.getFirstToken(lastProp).loc.start.line,
|
||||
lastLine: sourceCode.getLastToken(lastProp).loc.end.line,
|
||||
};
|
||||
}
|
||||
const openingLine = sourceCode.lines[opening.line - 1];
|
||||
const closingLine = sourceCode.lines[closing.line - 1];
|
||||
const isTab = {
|
||||
openTab: /^\t/.test(openingLine),
|
||||
closeTab: /^\t/.test(closingLine),
|
||||
};
|
||||
const openingStartOfLine = {
|
||||
column: /^\s*/.exec(openingLine)[0].length,
|
||||
line: opening.line,
|
||||
};
|
||||
return {
|
||||
isTab,
|
||||
tag,
|
||||
opening,
|
||||
closing,
|
||||
lastProp,
|
||||
selfClosing: node.selfClosing,
|
||||
openingStartOfLine,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an unique ID for a given JSXOpeningElement
|
||||
*
|
||||
* @param {ASTNode} node The AST node being checked.
|
||||
* @returns {string} Unique ID (based on its range)
|
||||
*/
|
||||
function getOpeningElementId(node) {
|
||||
return node.range.join(':');
|
||||
}
|
||||
|
||||
const lastAttributeNode = {};
|
||||
|
||||
return {
|
||||
JSXAttribute(node) {
|
||||
lastAttributeNode[getOpeningElementId(node.parent)] = node;
|
||||
},
|
||||
|
||||
JSXSpreadAttribute(node) {
|
||||
lastAttributeNode[getOpeningElementId(node.parent)] = node;
|
||||
},
|
||||
|
||||
'JSXOpeningElement:exit'(node) {
|
||||
const attributeNode = lastAttributeNode[getOpeningElementId(node)];
|
||||
const cachedLastAttributeEndPos = attributeNode ? attributeNode.range[1] : null;
|
||||
|
||||
let expectedNextLine;
|
||||
const tokens = getTokensLocations(node);
|
||||
const expectedLocation = getExpectedLocation(tokens);
|
||||
let usingSameIndentation = true;
|
||||
|
||||
if (expectedLocation === 'tag-aligned') {
|
||||
usingSameIndentation = tokens.isTab.openTab === tokens.isTab.closeTab;
|
||||
}
|
||||
|
||||
if (hasCorrectLocation(tokens, expectedLocation) && usingSameIndentation) {
|
||||
return;
|
||||
}
|
||||
|
||||
const data = {
|
||||
location: MESSAGE_LOCATION[expectedLocation],
|
||||
details: '',
|
||||
};
|
||||
const correctColumn = getCorrectColumn(tokens, expectedLocation);
|
||||
|
||||
if (correctColumn !== null) {
|
||||
expectedNextLine = tokens.lastProp
|
||||
&& (tokens.lastProp.lastLine === tokens.closing.line);
|
||||
data.details = ` (expected column ${correctColumn + 1}${expectedNextLine ? ' on the next line)' : ')'}`;
|
||||
}
|
||||
|
||||
report(context, messages.bracketLocation, 'bracketLocation', {
|
||||
node,
|
||||
loc: tokens.closing,
|
||||
data,
|
||||
fix(fixer) {
|
||||
const closingTag = tokens.selfClosing ? '/>' : '>';
|
||||
switch (expectedLocation) {
|
||||
case 'after-tag':
|
||||
if (cachedLastAttributeEndPos) {
|
||||
return fixer.replaceTextRange([cachedLastAttributeEndPos, node.range[1]],
|
||||
(expectedNextLine ? '\n' : '') + closingTag);
|
||||
}
|
||||
return fixer.replaceTextRange([node.name.range[1], node.range[1]],
|
||||
(expectedNextLine ? '\n' : ' ') + closingTag);
|
||||
case 'after-props':
|
||||
return fixer.replaceTextRange([cachedLastAttributeEndPos, node.range[1]],
|
||||
(expectedNextLine ? '\n' : '') + closingTag);
|
||||
case 'props-aligned':
|
||||
case 'tag-aligned':
|
||||
case 'line-aligned':
|
||||
return fixer.replaceTextRange([cachedLastAttributeEndPos, node.range[1]],
|
||||
`\n${getIndentation(tokens, expectedLocation, correctColumn)}${closingTag}`);
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-closing-tag-location.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-closing-tag-location.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=jsx-closing-tag-location.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-closing-tag-location.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-closing-tag-location.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"jsx-closing-tag-location.d.ts","sourceRoot":"","sources":["jsx-closing-tag-location.js"],"names":[],"mappings":"wBAgCW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
142
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-closing-tag-location.js
generated
vendored
Normal file
142
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-closing-tag-location.js
generated
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
/**
|
||||
* @fileoverview Validate closing tag location in JSX
|
||||
* @author Ross Solomon
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const repeat = require('string.prototype.repeat');
|
||||
const has = require('hasown');
|
||||
|
||||
const astUtil = require('../util/ast');
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const getSourceCode = require('../util/eslint').getSourceCode;
|
||||
const report = require('../util/report');
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const messages = {
|
||||
onOwnLine: 'Closing tag of a multiline JSX expression must be on its own line.',
|
||||
matchIndent: 'Expected closing tag to match indentation of opening.',
|
||||
alignWithOpening: 'Expected closing tag to be aligned with the line containing the opening tag',
|
||||
};
|
||||
|
||||
const defaultOption = 'tag-aligned';
|
||||
|
||||
const optionMessageMap = {
|
||||
'tag-aligned': 'matchIndent',
|
||||
'line-aligned': 'alignWithOpening',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Enforce closing tag location for multiline JSX',
|
||||
category: 'Stylistic Issues',
|
||||
recommended: false,
|
||||
url: docsUrl('jsx-closing-tag-location'),
|
||||
},
|
||||
fixable: 'whitespace',
|
||||
messages,
|
||||
schema: [{
|
||||
anyOf: [
|
||||
{
|
||||
enum: ['tag-aligned', 'line-aligned'],
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
location: {
|
||||
enum: ['tag-aligned', 'line-aligned'],
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
}],
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const config = context.options[0];
|
||||
let option = defaultOption;
|
||||
|
||||
if (typeof config === 'string') {
|
||||
option = config;
|
||||
} else if (typeof config === 'object') {
|
||||
if (has(config, 'location')) {
|
||||
option = config.location;
|
||||
}
|
||||
}
|
||||
|
||||
function getIndentation(openingStartOfLine, opening) {
|
||||
if (option === 'line-aligned') return openingStartOfLine.column;
|
||||
if (option === 'tag-aligned') return opening.loc.start.column;
|
||||
}
|
||||
|
||||
function handleClosingElement(node) {
|
||||
if (!node.parent) {
|
||||
return;
|
||||
}
|
||||
const sourceCode = getSourceCode(context);
|
||||
|
||||
const opening = node.parent.openingElement || node.parent.openingFragment;
|
||||
const openingLoc = sourceCode.getFirstToken(opening).loc.start;
|
||||
const openingLine = sourceCode.lines[openingLoc.line - 1];
|
||||
|
||||
const openingStartOfLine = {
|
||||
column: /^\s*/.exec(openingLine)[0].length,
|
||||
line: openingLoc.line,
|
||||
};
|
||||
|
||||
if (opening.loc.start.line === node.loc.start.line) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
opening.loc.start.column === node.loc.start.column
|
||||
&& option === 'tag-aligned'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
openingStartOfLine.column === node.loc.start.column
|
||||
&& option === 'line-aligned'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const messageId = astUtil.isNodeFirstInLine(context, node)
|
||||
? optionMessageMap[option]
|
||||
: 'onOwnLine';
|
||||
|
||||
report(context, messages[messageId], messageId, {
|
||||
node,
|
||||
loc: node.loc,
|
||||
fix(fixer) {
|
||||
const indent = repeat(
|
||||
' ',
|
||||
getIndentation(openingStartOfLine, opening)
|
||||
);
|
||||
|
||||
if (astUtil.isNodeFirstInLine(context, node)) {
|
||||
return fixer.replaceTextRange(
|
||||
[node.range[0] - node.loc.start.column, node.range[0]],
|
||||
indent
|
||||
);
|
||||
}
|
||||
|
||||
return fixer.insertTextBefore(node, `\n${indent}`);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
JSXClosingElement: handleClosingElement,
|
||||
JSXClosingFragment: handleClosingElement,
|
||||
};
|
||||
},
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-curly-brace-presence.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-curly-brace-presence.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=jsx-curly-brace-presence.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-curly-brace-presence.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-curly-brace-presence.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"jsx-curly-brace-presence.d.ts","sourceRoot":"","sources":["jsx-curly-brace-presence.js"],"names":[],"mappings":"wBAgJW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
421
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-curly-brace-presence.js
generated
vendored
Normal file
421
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-curly-brace-presence.js
generated
vendored
Normal file
@@ -0,0 +1,421 @@
|
||||
/**
|
||||
* @fileoverview Enforce curly braces or disallow unnecessary curly brace in JSX
|
||||
* @author Jacky Ho
|
||||
* @author Simon Lydell
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const arrayIncludes = require('array-includes');
|
||||
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const jsxUtil = require('../util/jsx');
|
||||
const report = require('../util/report');
|
||||
const eslintUtil = require('../util/eslint');
|
||||
|
||||
const getSourceCode = eslintUtil.getSourceCode;
|
||||
const getText = eslintUtil.getText;
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Constants
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const OPTION_ALWAYS = 'always';
|
||||
const OPTION_NEVER = 'never';
|
||||
const OPTION_IGNORE = 'ignore';
|
||||
|
||||
const OPTION_VALUES = [
|
||||
OPTION_ALWAYS,
|
||||
OPTION_NEVER,
|
||||
OPTION_IGNORE,
|
||||
];
|
||||
const DEFAULT_CONFIG = { props: OPTION_NEVER, children: OPTION_NEVER, propElementValues: OPTION_IGNORE };
|
||||
|
||||
const HTML_ENTITY_REGEX = () => /&[A-Za-z\d#]+;/g;
|
||||
|
||||
function containsLineTerminators(rawStringValue) {
|
||||
return /[\n\r\u2028\u2029]/.test(rawStringValue);
|
||||
}
|
||||
|
||||
function containsBackslash(rawStringValue) {
|
||||
return arrayIncludes(rawStringValue, '\\');
|
||||
}
|
||||
|
||||
function containsHTMLEntity(rawStringValue) {
|
||||
return HTML_ENTITY_REGEX().test(rawStringValue);
|
||||
}
|
||||
|
||||
function containsOnlyHtmlEntities(rawStringValue) {
|
||||
return rawStringValue.replace(HTML_ENTITY_REGEX(), '').trim() === '';
|
||||
}
|
||||
|
||||
function containsDisallowedJSXTextChars(rawStringValue) {
|
||||
return /[{<>}]/.test(rawStringValue);
|
||||
}
|
||||
|
||||
function containsQuoteCharacters(value) {
|
||||
return /['"]/.test(value);
|
||||
}
|
||||
|
||||
function containsMultilineComment(value) {
|
||||
return /\/\*/.test(value);
|
||||
}
|
||||
|
||||
function escapeDoubleQuotes(rawStringValue) {
|
||||
return rawStringValue.replace(/\\"/g, '"').replace(/"/g, '\\"');
|
||||
}
|
||||
|
||||
function escapeBackslashes(rawStringValue) {
|
||||
return rawStringValue.replace(/\\/g, '\\\\');
|
||||
}
|
||||
|
||||
function needToEscapeCharacterForJSX(raw, node) {
|
||||
return (
|
||||
containsBackslash(raw)
|
||||
|| containsHTMLEntity(raw)
|
||||
|| (node.parent.type !== 'JSXAttribute' && containsDisallowedJSXTextChars(raw))
|
||||
);
|
||||
}
|
||||
|
||||
function containsWhitespaceExpression(child) {
|
||||
if (child.type === 'JSXExpressionContainer') {
|
||||
const value = child.expression.value;
|
||||
return value ? jsxUtil.isWhiteSpaces(value) : false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isLineBreak(text) {
|
||||
return containsLineTerminators(text) && text.trim() === '';
|
||||
}
|
||||
|
||||
function wrapNonHTMLEntities(text) {
|
||||
const HTML_ENTITY = '<HTML_ENTITY>';
|
||||
const withCurlyBraces = text.split(HTML_ENTITY_REGEX()).map((word) => (
|
||||
word === '' ? '' : `{${JSON.stringify(word)}}`
|
||||
)).join(HTML_ENTITY);
|
||||
|
||||
const htmlEntities = text.match(HTML_ENTITY_REGEX());
|
||||
return htmlEntities.reduce((acc, htmlEntity) => (
|
||||
acc.replace(HTML_ENTITY, htmlEntity)
|
||||
), withCurlyBraces);
|
||||
}
|
||||
|
||||
function wrapWithCurlyBraces(rawText) {
|
||||
if (!containsLineTerminators(rawText)) {
|
||||
return `{${JSON.stringify(rawText)}}`;
|
||||
}
|
||||
|
||||
return rawText.split('\n').map((line) => {
|
||||
if (line.trim() === '') {
|
||||
return line;
|
||||
}
|
||||
const firstCharIndex = line.search(/[^\s]/);
|
||||
const leftWhitespace = line.slice(0, firstCharIndex);
|
||||
const text = line.slice(firstCharIndex);
|
||||
|
||||
if (containsHTMLEntity(line)) {
|
||||
return `${leftWhitespace}${wrapNonHTMLEntities(text)}`;
|
||||
}
|
||||
return `${leftWhitespace}{${JSON.stringify(text)}}`;
|
||||
}).join('\n');
|
||||
}
|
||||
|
||||
function isWhiteSpaceLiteral(node) {
|
||||
return node.type && node.type === 'Literal' && node.value && jsxUtil.isWhiteSpaces(node.value);
|
||||
}
|
||||
|
||||
function isStringWithTrailingWhiteSpaces(value) {
|
||||
return /^\s|\s$/.test(value);
|
||||
}
|
||||
|
||||
function isLiteralWithTrailingWhiteSpaces(node) {
|
||||
return node.type && node.type === 'Literal' && node.value && isStringWithTrailingWhiteSpaces(node.value);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const messages = {
|
||||
unnecessaryCurly: 'Curly braces are unnecessary here.',
|
||||
missingCurly: 'Need to wrap this literal in a JSX expression.',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Disallow unnecessary JSX expressions when literals alone are sufficient or enforce JSX expressions on literals in JSX children or attributes',
|
||||
category: 'Stylistic Issues',
|
||||
recommended: false,
|
||||
url: docsUrl('jsx-curly-brace-presence'),
|
||||
},
|
||||
fixable: 'code',
|
||||
|
||||
messages,
|
||||
|
||||
schema: [
|
||||
{
|
||||
anyOf: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
props: { enum: OPTION_VALUES },
|
||||
children: { enum: OPTION_VALUES },
|
||||
propElementValues: { enum: OPTION_VALUES },
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
{
|
||||
enum: OPTION_VALUES,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const ruleOptions = context.options[0];
|
||||
const userConfig = typeof ruleOptions === 'string'
|
||||
? { props: ruleOptions, children: ruleOptions, propElementValues: OPTION_IGNORE }
|
||||
: Object.assign({}, DEFAULT_CONFIG, ruleOptions);
|
||||
|
||||
/**
|
||||
* Report and fix an unnecessary curly brace violation on a node
|
||||
* @param {ASTNode} JSXExpressionNode - The AST node with an unnecessary JSX expression
|
||||
*/
|
||||
function reportUnnecessaryCurly(JSXExpressionNode) {
|
||||
report(context, messages.unnecessaryCurly, 'unnecessaryCurly', {
|
||||
node: JSXExpressionNode,
|
||||
fix(fixer) {
|
||||
const expression = JSXExpressionNode.expression;
|
||||
|
||||
let textToReplace;
|
||||
if (jsxUtil.isJSX(expression)) {
|
||||
textToReplace = getText(context, expression);
|
||||
} else {
|
||||
const expressionType = expression && expression.type;
|
||||
const parentType = JSXExpressionNode.parent.type;
|
||||
|
||||
if (parentType === 'JSXAttribute') {
|
||||
if (expressionType !== 'TemplateLiteral' && /["]/.test(expression.raw.slice(1, -1))) {
|
||||
textToReplace = expression.raw;
|
||||
} else {
|
||||
textToReplace = `"${expressionType === 'TemplateLiteral'
|
||||
? expression.quasis[0].value.raw
|
||||
: expression.raw.slice(1, -1)
|
||||
}"`;
|
||||
}
|
||||
} else if (jsxUtil.isJSX(expression)) {
|
||||
textToReplace = getText(context, expression);
|
||||
} else {
|
||||
textToReplace = expressionType === 'TemplateLiteral'
|
||||
? expression.quasis[0].value.cooked : expression.value;
|
||||
}
|
||||
}
|
||||
|
||||
return fixer.replaceText(JSXExpressionNode, textToReplace);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function reportMissingCurly(literalNode) {
|
||||
report(context, messages.missingCurly, 'missingCurly', {
|
||||
node: literalNode,
|
||||
fix(fixer) {
|
||||
if (jsxUtil.isJSX(literalNode)) {
|
||||
return fixer.replaceText(literalNode, `{${getText(context, literalNode)}}`);
|
||||
}
|
||||
|
||||
// If a HTML entity name is found, bail out because it can be fixed
|
||||
// by either using the real character or the unicode equivalent.
|
||||
// If it contains any line terminator character, bail out as well.
|
||||
if (
|
||||
containsOnlyHtmlEntities(literalNode.raw)
|
||||
|| (literalNode.parent.type === 'JSXAttribute' && containsLineTerminators(literalNode.raw))
|
||||
|| isLineBreak(literalNode.raw)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const expression = literalNode.parent.type === 'JSXAttribute'
|
||||
? `{"${escapeDoubleQuotes(escapeBackslashes(
|
||||
literalNode.raw.slice(1, -1)
|
||||
))}"}`
|
||||
: wrapWithCurlyBraces(literalNode.raw);
|
||||
|
||||
return fixer.replaceText(literalNode, expression);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Bail out if there is any character that needs to be escaped in JSX
|
||||
// because escaping decreases readability and the original code may be more
|
||||
// readable anyway or intentional for other specific reasons
|
||||
function lintUnnecessaryCurly(JSXExpressionNode) {
|
||||
const expression = JSXExpressionNode.expression;
|
||||
const expressionType = expression.type;
|
||||
|
||||
const sourceCode = getSourceCode(context);
|
||||
// Curly braces containing comments are necessary
|
||||
if (sourceCode.getCommentsInside && sourceCode.getCommentsInside(JSXExpressionNode).length > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
(expressionType === 'Literal' || expressionType === 'JSXText')
|
||||
&& typeof expression.value === 'string'
|
||||
&& (
|
||||
(JSXExpressionNode.parent.type === 'JSXAttribute' && !isWhiteSpaceLiteral(expression))
|
||||
|| !isLiteralWithTrailingWhiteSpaces(expression)
|
||||
)
|
||||
&& !containsMultilineComment(expression.value)
|
||||
&& !needToEscapeCharacterForJSX(expression.raw, JSXExpressionNode) && (
|
||||
jsxUtil.isJSX(JSXExpressionNode.parent)
|
||||
|| (!containsQuoteCharacters(expression.value) || typeof expression.value === 'string')
|
||||
)
|
||||
) {
|
||||
reportUnnecessaryCurly(JSXExpressionNode);
|
||||
} else if (
|
||||
expressionType === 'TemplateLiteral'
|
||||
&& expression.expressions.length === 0
|
||||
&& expression.quasis[0].value.raw.indexOf('\n') === -1
|
||||
&& !isStringWithTrailingWhiteSpaces(expression.quasis[0].value.raw)
|
||||
&& !needToEscapeCharacterForJSX(expression.quasis[0].value.raw, JSXExpressionNode)
|
||||
&& !containsQuoteCharacters(expression.quasis[0].value.cooked)
|
||||
) {
|
||||
reportUnnecessaryCurly(JSXExpressionNode);
|
||||
} else if (jsxUtil.isJSX(expression)) {
|
||||
reportUnnecessaryCurly(JSXExpressionNode);
|
||||
}
|
||||
}
|
||||
|
||||
function areRuleConditionsSatisfied(parent, config, ruleCondition) {
|
||||
return (
|
||||
parent.type === 'JSXAttribute'
|
||||
&& typeof config.props === 'string'
|
||||
&& config.props === ruleCondition
|
||||
) || (
|
||||
jsxUtil.isJSX(parent)
|
||||
&& typeof config.children === 'string'
|
||||
&& config.children === ruleCondition
|
||||
);
|
||||
}
|
||||
|
||||
function getAdjacentSiblings(node, children) {
|
||||
for (let i = 1; i < children.length - 1; i++) {
|
||||
const child = children[i];
|
||||
if (node === child) {
|
||||
return [children[i - 1], children[i + 1]];
|
||||
}
|
||||
}
|
||||
if (node === children[0] && children[1]) {
|
||||
return [children[1]];
|
||||
}
|
||||
if (node === children[children.length - 1] && children[children.length - 2]) {
|
||||
return [children[children.length - 2]];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
function hasAdjacentJsxExpressionContainers(node, children) {
|
||||
if (!children) {
|
||||
return false;
|
||||
}
|
||||
const childrenExcludingWhitespaceLiteral = children.filter((child) => !isWhiteSpaceLiteral(child));
|
||||
const adjSiblings = getAdjacentSiblings(node, childrenExcludingWhitespaceLiteral);
|
||||
|
||||
return adjSiblings.some((x) => x.type && x.type === 'JSXExpressionContainer');
|
||||
}
|
||||
function hasAdjacentJsx(node, children) {
|
||||
if (!children) {
|
||||
return false;
|
||||
}
|
||||
const childrenExcludingWhitespaceLiteral = children.filter((child) => !isWhiteSpaceLiteral(child));
|
||||
const adjSiblings = getAdjacentSiblings(node, childrenExcludingWhitespaceLiteral);
|
||||
|
||||
return adjSiblings.some((x) => x.type && arrayIncludes(['JSXExpressionContainer', 'JSXElement'], x.type));
|
||||
}
|
||||
function shouldCheckForUnnecessaryCurly(node, config) {
|
||||
const parent = node.parent;
|
||||
// Bail out if the parent is a JSXAttribute & its contents aren't
|
||||
// StringLiteral or TemplateLiteral since e.g
|
||||
// <App prop1={<CustomEl />} prop2={<CustomEl>...</CustomEl>} />
|
||||
|
||||
if (
|
||||
parent.type && parent.type === 'JSXAttribute'
|
||||
&& (node.expression && node.expression.type
|
||||
&& node.expression.type !== 'Literal'
|
||||
&& node.expression.type !== 'StringLiteral'
|
||||
&& node.expression.type !== 'TemplateLiteral')
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If there are adjacent `JsxExpressionContainer` then there is no need,
|
||||
// to check for unnecessary curly braces.
|
||||
if (jsxUtil.isJSX(parent) && hasAdjacentJsxExpressionContainers(node, parent.children)) {
|
||||
return false;
|
||||
}
|
||||
if (containsWhitespaceExpression(node) && hasAdjacentJsx(node, parent.children)) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
parent.children
|
||||
&& parent.children.length === 1
|
||||
&& containsWhitespaceExpression(node)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return areRuleConditionsSatisfied(parent, config, OPTION_NEVER);
|
||||
}
|
||||
|
||||
function shouldCheckForMissingCurly(node, config) {
|
||||
if (jsxUtil.isJSX(node)) {
|
||||
return config.propElementValues !== OPTION_IGNORE;
|
||||
}
|
||||
if (
|
||||
isLineBreak(node.raw)
|
||||
|| containsOnlyHtmlEntities(node.raw)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
const parent = node.parent;
|
||||
if (
|
||||
parent.children
|
||||
&& parent.children.length === 1
|
||||
&& containsWhitespaceExpression(parent.children[0])
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return areRuleConditionsSatisfied(parent, config, OPTION_ALWAYS);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Public
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
'JSXAttribute > JSXExpressionContainer > JSXElement'(node) {
|
||||
if (userConfig.propElementValues === OPTION_NEVER) {
|
||||
reportUnnecessaryCurly(node.parent);
|
||||
}
|
||||
},
|
||||
|
||||
JSXExpressionContainer(node) {
|
||||
if (shouldCheckForUnnecessaryCurly(node, userConfig)) {
|
||||
lintUnnecessaryCurly(node);
|
||||
}
|
||||
},
|
||||
|
||||
'JSXAttribute > JSXElement, Literal, JSXText'(node) {
|
||||
if (shouldCheckForMissingCurly(node, userConfig)) {
|
||||
reportMissingCurly(node);
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-curly-newline.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-curly-newline.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=jsx-curly-newline.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-curly-newline.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-curly-newline.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"jsx-curly-newline.d.ts","sourceRoot":"","sources":["jsx-curly-newline.js"],"names":[],"mappings":"wBA+CW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
187
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-curly-newline.js
generated
vendored
Normal file
187
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-curly-newline.js
generated
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
/**
|
||||
* @fileoverview enforce consistent line breaks inside jsx curly
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const eslintUtil = require('../util/eslint');
|
||||
const report = require('../util/report');
|
||||
|
||||
const getSourceCode = eslintUtil.getSourceCode;
|
||||
const getText = eslintUtil.getText;
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
function getNormalizedOption(context) {
|
||||
const rawOption = context.options[0] || 'consistent';
|
||||
|
||||
if (rawOption === 'consistent') {
|
||||
return {
|
||||
multiline: 'consistent',
|
||||
singleline: 'consistent',
|
||||
};
|
||||
}
|
||||
|
||||
if (rawOption === 'never') {
|
||||
return {
|
||||
multiline: 'forbid',
|
||||
singleline: 'forbid',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
multiline: rawOption.multiline || 'consistent',
|
||||
singleline: rawOption.singleline || 'consistent',
|
||||
};
|
||||
}
|
||||
|
||||
const messages = {
|
||||
expectedBefore: 'Expected newline before \'}\'.',
|
||||
expectedAfter: 'Expected newline after \'{\'.',
|
||||
unexpectedBefore: 'Unexpected newline before \'}\'.',
|
||||
unexpectedAfter: 'Unexpected newline after \'{\'.',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'layout',
|
||||
|
||||
docs: {
|
||||
description: 'Enforce consistent linebreaks in curly braces in JSX attributes and expressions',
|
||||
category: 'Stylistic Issues',
|
||||
recommended: false,
|
||||
url: docsUrl('jsx-curly-newline'),
|
||||
},
|
||||
|
||||
fixable: 'whitespace',
|
||||
|
||||
schema: [
|
||||
{
|
||||
anyOf: [
|
||||
{
|
||||
enum: ['consistent', 'never'],
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
singleline: { enum: ['consistent', 'require', 'forbid'] },
|
||||
multiline: { enum: ['consistent', 'require', 'forbid'] },
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
messages,
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const sourceCode = getSourceCode(context);
|
||||
const option = getNormalizedOption(context);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Determines whether two adjacent tokens are on the same line.
|
||||
* @param {Object} left - The left token object.
|
||||
* @param {Object} right - The right token object.
|
||||
* @returns {boolean} Whether or not the tokens are on the same line.
|
||||
*/
|
||||
function isTokenOnSameLine(left, right) {
|
||||
return left.loc.end.line === right.loc.start.line;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether there should be newlines inside curlys
|
||||
* @param {ASTNode} expression The expression contained in the curlys
|
||||
* @param {boolean} hasLeftNewline `true` if the left curly has a newline in the current code.
|
||||
* @returns {boolean} `true` if there should be newlines inside the function curlys
|
||||
*/
|
||||
function shouldHaveNewlines(expression, hasLeftNewline) {
|
||||
const isMultiline = expression.loc.start.line !== expression.loc.end.line;
|
||||
|
||||
switch (isMultiline ? option.multiline : option.singleline) {
|
||||
case 'forbid': return false;
|
||||
case 'require': return true;
|
||||
case 'consistent':
|
||||
default: return hasLeftNewline;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates curlys
|
||||
* @param {Object} curlys An object with keys `leftParen` for the left paren token, and `rightParen` for the right paren token
|
||||
* @param {ASTNode} expression The expression inside the curly
|
||||
* @returns {void}
|
||||
*/
|
||||
function validateCurlys(curlys, expression) {
|
||||
const leftCurly = curlys.leftCurly;
|
||||
const rightCurly = curlys.rightCurly;
|
||||
const tokenAfterLeftCurly = sourceCode.getTokenAfter(leftCurly);
|
||||
const tokenBeforeRightCurly = sourceCode.getTokenBefore(rightCurly);
|
||||
const hasLeftNewline = !isTokenOnSameLine(leftCurly, tokenAfterLeftCurly);
|
||||
const hasRightNewline = !isTokenOnSameLine(tokenBeforeRightCurly, rightCurly);
|
||||
const needsNewlines = shouldHaveNewlines(expression, hasLeftNewline);
|
||||
|
||||
if (hasLeftNewline && !needsNewlines) {
|
||||
report(context, messages.unexpectedAfter, 'unexpectedAfter', {
|
||||
node: leftCurly,
|
||||
fix(fixer) {
|
||||
return getText(context)
|
||||
.slice(leftCurly.range[1], tokenAfterLeftCurly.range[0])
|
||||
.trim()
|
||||
? null // If there is a comment between the { and the first element, don't do a fix.
|
||||
: fixer.removeRange([leftCurly.range[1], tokenAfterLeftCurly.range[0]]);
|
||||
},
|
||||
});
|
||||
} else if (!hasLeftNewline && needsNewlines) {
|
||||
report(context, messages.expectedAfter, 'expectedAfter', {
|
||||
node: leftCurly,
|
||||
fix: (fixer) => fixer.insertTextAfter(leftCurly, '\n'),
|
||||
});
|
||||
}
|
||||
|
||||
if (hasRightNewline && !needsNewlines) {
|
||||
report(context, messages.unexpectedBefore, 'unexpectedBefore', {
|
||||
node: rightCurly,
|
||||
fix(fixer) {
|
||||
return getText(context)
|
||||
.slice(tokenBeforeRightCurly.range[1], rightCurly.range[0])
|
||||
.trim()
|
||||
? null // If there is a comment between the last element and the }, don't do a fix.
|
||||
: fixer.removeRange([
|
||||
tokenBeforeRightCurly.range[1],
|
||||
rightCurly.range[0],
|
||||
]);
|
||||
},
|
||||
});
|
||||
} else if (!hasRightNewline && needsNewlines) {
|
||||
report(context, messages.expectedBefore, 'expectedBefore', {
|
||||
node: rightCurly,
|
||||
fix: (fixer) => fixer.insertTextBefore(rightCurly, '\n'),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Public
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
JSXExpressionContainer(node) {
|
||||
const curlyTokens = {
|
||||
leftCurly: sourceCode.getFirstToken(node),
|
||||
rightCurly: sourceCode.getLastToken(node),
|
||||
};
|
||||
validateCurlys(curlyTokens, node.expression);
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-curly-spacing.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-curly-spacing.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=jsx-curly-spacing.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-curly-spacing.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-curly-spacing.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"jsx-curly-spacing.d.ts","sourceRoot":"","sources":["jsx-curly-spacing.js"],"names":[],"mappings":"wBAqCW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
432
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-curly-spacing.js
generated
vendored
Normal file
432
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-curly-spacing.js
generated
vendored
Normal file
@@ -0,0 +1,432 @@
|
||||
/**
|
||||
* @fileoverview Enforce or disallow spaces inside of curly braces in JSX attributes.
|
||||
* @author Jamund Ferguson
|
||||
* @author Brandyn Bennett
|
||||
* @author Michael Ficarra
|
||||
* @author Vignesh Anand
|
||||
* @author Jamund Ferguson
|
||||
* @author Yannick Croissant
|
||||
* @author Erik Wendel
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const has = require('hasown');
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const getSourceCode = require('../util/eslint').getSourceCode;
|
||||
const report = require('../util/report');
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const SPACING = {
|
||||
always: 'always',
|
||||
never: 'never',
|
||||
};
|
||||
const SPACING_VALUES = [SPACING.always, SPACING.never];
|
||||
|
||||
const messages = {
|
||||
noNewlineAfter: 'There should be no newline after \'{{token}}\'',
|
||||
noNewlineBefore: 'There should be no newline before \'{{token}}\'',
|
||||
noSpaceAfter: 'There should be no space after \'{{token}}\'',
|
||||
noSpaceBefore: 'There should be no space before \'{{token}}\'',
|
||||
spaceNeededAfter: 'A space is required after \'{{token}}\'',
|
||||
spaceNeededBefore: 'A space is required before \'{{token}}\'',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Enforce or disallow spaces inside of curly braces in JSX attributes and expressions',
|
||||
category: 'Stylistic Issues',
|
||||
recommended: false,
|
||||
url: docsUrl('jsx-curly-spacing'),
|
||||
},
|
||||
fixable: 'code',
|
||||
|
||||
messages,
|
||||
|
||||
schema: {
|
||||
definitions: {
|
||||
basicConfig: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
when: {
|
||||
enum: SPACING_VALUES,
|
||||
},
|
||||
allowMultiline: {
|
||||
type: 'boolean',
|
||||
},
|
||||
spacing: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
objectLiterals: {
|
||||
enum: SPACING_VALUES,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
basicConfigOrBoolean: {
|
||||
anyOf: [{
|
||||
$ref: '#/definitions/basicConfig',
|
||||
}, {
|
||||
type: 'boolean',
|
||||
}],
|
||||
},
|
||||
},
|
||||
type: 'array',
|
||||
items: [{
|
||||
anyOf: [{
|
||||
allOf: [{
|
||||
$ref: '#/definitions/basicConfig',
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
attributes: {
|
||||
$ref: '#/definitions/basicConfigOrBoolean',
|
||||
},
|
||||
children: {
|
||||
$ref: '#/definitions/basicConfigOrBoolean',
|
||||
},
|
||||
},
|
||||
}],
|
||||
}, {
|
||||
enum: SPACING_VALUES,
|
||||
}],
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
allowMultiline: {
|
||||
type: 'boolean',
|
||||
},
|
||||
spacing: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
objectLiterals: {
|
||||
enum: SPACING_VALUES,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
}],
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
function normalizeConfig(configOrTrue, defaults, lastPass) {
|
||||
const config = configOrTrue === true ? {} : configOrTrue;
|
||||
const when = config.when || defaults.when;
|
||||
const allowMultiline = has(config, 'allowMultiline') ? config.allowMultiline : defaults.allowMultiline;
|
||||
const spacing = config.spacing || {};
|
||||
let objectLiteralSpaces = spacing.objectLiterals || defaults.objectLiteralSpaces;
|
||||
if (lastPass) {
|
||||
// On the final pass assign the values that should be derived from others if they are still undefined
|
||||
objectLiteralSpaces = objectLiteralSpaces || when;
|
||||
}
|
||||
|
||||
return {
|
||||
when,
|
||||
allowMultiline,
|
||||
objectLiteralSpaces,
|
||||
};
|
||||
}
|
||||
|
||||
const DEFAULT_WHEN = SPACING.never;
|
||||
const DEFAULT_ALLOW_MULTILINE = true;
|
||||
const DEFAULT_ATTRIBUTES = true;
|
||||
const DEFAULT_CHILDREN = false;
|
||||
|
||||
let originalConfig = context.options[0] || {};
|
||||
if (SPACING_VALUES.indexOf(originalConfig) !== -1) {
|
||||
originalConfig = Object.assign({ when: context.options[0] }, context.options[1]);
|
||||
}
|
||||
const defaultConfig = normalizeConfig(originalConfig, {
|
||||
when: DEFAULT_WHEN,
|
||||
allowMultiline: DEFAULT_ALLOW_MULTILINE,
|
||||
});
|
||||
const attributes = has(originalConfig, 'attributes') ? originalConfig.attributes : DEFAULT_ATTRIBUTES;
|
||||
const attributesConfig = attributes ? normalizeConfig(attributes, defaultConfig, true) : null;
|
||||
const children = has(originalConfig, 'children') ? originalConfig.children : DEFAULT_CHILDREN;
|
||||
const childrenConfig = children ? normalizeConfig(children, defaultConfig, true) : null;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Determines whether two adjacent tokens have a newline between them.
|
||||
* @param {Object} left - The left token object.
|
||||
* @param {Object} right - The right token object.
|
||||
* @returns {boolean} Whether or not there is a newline between the tokens.
|
||||
*/
|
||||
function isMultiline(left, right) {
|
||||
return left.loc.end.line !== right.loc.start.line;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims text of whitespace between two ranges
|
||||
* @param {Fixer} fixer - the eslint fixer object
|
||||
* @param {number} fromLoc - the start location
|
||||
* @param {number} toLoc - the end location
|
||||
* @param {string} mode - either 'start' or 'end'
|
||||
* @param {string=} spacing - a spacing value that will optionally add a space to the removed text
|
||||
* @returns {Object|*|{range, text}}
|
||||
*/
|
||||
function fixByTrimmingWhitespace(fixer, fromLoc, toLoc, mode, spacing) {
|
||||
let replacementText = getSourceCode(context).text.slice(fromLoc, toLoc);
|
||||
if (mode === 'start') {
|
||||
replacementText = replacementText.replace(/^\s+/gm, '');
|
||||
} else {
|
||||
replacementText = replacementText.replace(/\s+$/gm, '');
|
||||
}
|
||||
if (spacing === SPACING.always) {
|
||||
if (mode === 'start') {
|
||||
replacementText += ' ';
|
||||
} else {
|
||||
replacementText = ` ${replacementText}`;
|
||||
}
|
||||
}
|
||||
return fixer.replaceTextRange([fromLoc, toLoc], replacementText);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports that there shouldn't be a newline after the first token
|
||||
* @param {ASTNode} node - The node to report in the event of an error.
|
||||
* @param {Token} token - The token to use for the report.
|
||||
* @param {string} spacing
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportNoBeginningNewline(node, token, spacing) {
|
||||
report(context, messages.noNewlineAfter, 'noNewlineAfter', {
|
||||
node,
|
||||
loc: token.loc.start,
|
||||
data: {
|
||||
token: token.value,
|
||||
},
|
||||
fix(fixer) {
|
||||
const nextToken = getSourceCode(context).getTokenAfter(token);
|
||||
return fixByTrimmingWhitespace(fixer, token.range[1], nextToken.range[0], 'start', spacing);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports that there shouldn't be a newline before the last token
|
||||
* @param {ASTNode} node - The node to report in the event of an error.
|
||||
* @param {Token} token - The token to use for the report.
|
||||
* @param {string} spacing
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportNoEndingNewline(node, token, spacing) {
|
||||
report(context, messages.noNewlineBefore, 'noNewlineBefore', {
|
||||
node,
|
||||
loc: token.loc.start,
|
||||
data: {
|
||||
token: token.value,
|
||||
},
|
||||
fix(fixer) {
|
||||
const previousToken = getSourceCode(context).getTokenBefore(token);
|
||||
return fixByTrimmingWhitespace(fixer, previousToken.range[1], token.range[0], 'end', spacing);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports that there shouldn't be a space after the first token
|
||||
* @param {ASTNode} node - The node to report in the event of an error.
|
||||
* @param {Token} token - The token to use for the report.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportNoBeginningSpace(node, token) {
|
||||
report(context, messages.noSpaceAfter, 'noSpaceAfter', {
|
||||
node,
|
||||
loc: token.loc.start,
|
||||
data: {
|
||||
token: token.value,
|
||||
},
|
||||
fix(fixer) {
|
||||
const sourceCode = getSourceCode(context);
|
||||
const nextToken = sourceCode.getTokenAfter(token);
|
||||
let nextComment;
|
||||
|
||||
// eslint >=4.x
|
||||
if (sourceCode.getCommentsAfter) {
|
||||
nextComment = sourceCode.getCommentsAfter(token);
|
||||
// eslint 3.x
|
||||
} else {
|
||||
const potentialComment = sourceCode.getTokenAfter(token, { includeComments: true });
|
||||
nextComment = nextToken === potentialComment ? [] : [potentialComment];
|
||||
}
|
||||
|
||||
// Take comments into consideration to narrow the fix range to what is actually affected. (See #1414)
|
||||
if (nextComment.length > 0) {
|
||||
return fixByTrimmingWhitespace(fixer, token.range[1], Math.min(nextToken.range[0], nextComment[0].range[0]), 'start');
|
||||
}
|
||||
|
||||
return fixByTrimmingWhitespace(fixer, token.range[1], nextToken.range[0], 'start');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports that there shouldn't be a space before the last token
|
||||
* @param {ASTNode} node - The node to report in the event of an error.
|
||||
* @param {Token} token - The token to use for the report.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportNoEndingSpace(node, token) {
|
||||
report(context, messages.noSpaceBefore, 'noSpaceBefore', {
|
||||
node,
|
||||
loc: token.loc.start,
|
||||
data: {
|
||||
token: token.value,
|
||||
},
|
||||
fix(fixer) {
|
||||
const sourceCode = getSourceCode(context);
|
||||
const previousToken = sourceCode.getTokenBefore(token);
|
||||
let previousComment;
|
||||
|
||||
// eslint >=4.x
|
||||
if (sourceCode.getCommentsBefore) {
|
||||
previousComment = sourceCode.getCommentsBefore(token);
|
||||
// eslint 3.x
|
||||
} else {
|
||||
const potentialComment = sourceCode.getTokenBefore(token, { includeComments: true });
|
||||
previousComment = previousToken === potentialComment ? [] : [potentialComment];
|
||||
}
|
||||
|
||||
// Take comments into consideration to narrow the fix range to what is actually affected. (See #1414)
|
||||
if (previousComment.length > 0) {
|
||||
return fixByTrimmingWhitespace(fixer, Math.max(previousToken.range[1], previousComment[0].range[1]), token.range[0], 'end');
|
||||
}
|
||||
|
||||
return fixByTrimmingWhitespace(fixer, previousToken.range[1], token.range[0], 'end');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports that there should be a space after the first token
|
||||
* @param {ASTNode} node - The node to report in the event of an error.
|
||||
* @param {Token} token - The token to use for the report.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportRequiredBeginningSpace(node, token) {
|
||||
report(context, messages.spaceNeededAfter, 'spaceNeededAfter', {
|
||||
node,
|
||||
loc: token.loc.start,
|
||||
data: {
|
||||
token: token.value,
|
||||
},
|
||||
fix(fixer) {
|
||||
return fixer.insertTextAfter(token, ' ');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports that there should be a space before the last token
|
||||
* @param {ASTNode} node - The node to report in the event of an error.
|
||||
* @param {Token} token - The token to use for the report.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportRequiredEndingSpace(node, token) {
|
||||
report(context, messages.spaceNeededBefore, 'spaceNeededBefore', {
|
||||
node,
|
||||
loc: token.loc.start,
|
||||
data: {
|
||||
token: token.value,
|
||||
},
|
||||
fix(fixer) {
|
||||
return fixer.insertTextBefore(token, ' ');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if spacing in curly braces is valid.
|
||||
* @param {ASTNode} node The AST node to check.
|
||||
* @returns {void}
|
||||
*/
|
||||
function validateBraceSpacing(node) {
|
||||
let config;
|
||||
switch (node.parent.type) {
|
||||
case 'JSXAttribute':
|
||||
case 'JSXOpeningElement':
|
||||
config = attributesConfig;
|
||||
break;
|
||||
|
||||
case 'JSXElement':
|
||||
case 'JSXFragment':
|
||||
config = childrenConfig;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
if (config === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sourceCode = getSourceCode(context);
|
||||
const first = sourceCode.getFirstToken(node);
|
||||
const last = sourceCode.getLastToken(node);
|
||||
let second = sourceCode.getTokenAfter(first, { includeComments: true });
|
||||
let penultimate = sourceCode.getTokenBefore(last, { includeComments: true });
|
||||
|
||||
if (!second) {
|
||||
second = sourceCode.getTokenAfter(first);
|
||||
const leadingComments = sourceCode.getNodeByRangeIndex(second.range[0]).leadingComments;
|
||||
second = leadingComments ? leadingComments[0] : second;
|
||||
}
|
||||
if (!penultimate) {
|
||||
penultimate = sourceCode.getTokenBefore(last);
|
||||
const trailingComments = sourceCode.getNodeByRangeIndex(penultimate.range[0]).trailingComments;
|
||||
penultimate = trailingComments ? trailingComments[trailingComments.length - 1] : penultimate;
|
||||
}
|
||||
|
||||
const isObjectLiteral = first.value === second.value;
|
||||
const spacing = isObjectLiteral ? config.objectLiteralSpaces : config.when;
|
||||
if (spacing === SPACING.always) {
|
||||
if (!sourceCode.isSpaceBetweenTokens(first, second)) {
|
||||
reportRequiredBeginningSpace(node, first);
|
||||
} else if (!config.allowMultiline && isMultiline(first, second)) {
|
||||
reportNoBeginningNewline(node, first, spacing);
|
||||
}
|
||||
if (!sourceCode.isSpaceBetweenTokens(penultimate, last)) {
|
||||
reportRequiredEndingSpace(node, last);
|
||||
} else if (!config.allowMultiline && isMultiline(penultimate, last)) {
|
||||
reportNoEndingNewline(node, last, spacing);
|
||||
}
|
||||
} else if (spacing === SPACING.never) {
|
||||
if (isMultiline(first, second)) {
|
||||
if (!config.allowMultiline) {
|
||||
reportNoBeginningNewline(node, first, spacing);
|
||||
}
|
||||
} else if (sourceCode.isSpaceBetweenTokens(first, second)) {
|
||||
reportNoBeginningSpace(node, first);
|
||||
}
|
||||
if (isMultiline(penultimate, last)) {
|
||||
if (!config.allowMultiline) {
|
||||
reportNoEndingNewline(node, last, spacing);
|
||||
}
|
||||
} else if (sourceCode.isSpaceBetweenTokens(penultimate, last)) {
|
||||
reportNoEndingSpace(node, last);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Public
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
JSXExpressionContainer: validateBraceSpacing,
|
||||
JSXSpreadAttribute: validateBraceSpacing,
|
||||
};
|
||||
},
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-equals-spacing.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-equals-spacing.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=jsx-equals-spacing.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-equals-spacing.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-equals-spacing.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"jsx-equals-spacing.d.ts","sourceRoot":"","sources":["jsx-equals-spacing.js"],"names":[],"mappings":"wBAsBW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
112
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-equals-spacing.js
generated
vendored
Normal file
112
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-equals-spacing.js
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* @fileoverview Disallow or enforce spaces around equal signs in JSX attributes.
|
||||
* @author ryym
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const getSourceCode = require('../util/eslint').getSourceCode;
|
||||
const report = require('../util/report');
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const messages = {
|
||||
noSpaceBefore: 'There should be no space before \'=\'',
|
||||
noSpaceAfter: 'There should be no space after \'=\'',
|
||||
needSpaceBefore: 'A space is required before \'=\'',
|
||||
needSpaceAfter: 'A space is required after \'=\'',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Enforce or disallow spaces around equal signs in JSX attributes',
|
||||
category: 'Stylistic Issues',
|
||||
recommended: false,
|
||||
url: docsUrl('jsx-equals-spacing'),
|
||||
},
|
||||
fixable: 'code',
|
||||
|
||||
messages,
|
||||
|
||||
schema: [{
|
||||
enum: ['always', 'never'],
|
||||
}],
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const config = context.options[0] || 'never';
|
||||
|
||||
/**
|
||||
* Determines a given attribute node has an equal sign.
|
||||
* @param {ASTNode} attrNode - The attribute node.
|
||||
* @returns {boolean} Whether or not the attriute node has an equal sign.
|
||||
*/
|
||||
function hasEqual(attrNode) {
|
||||
return attrNode.type !== 'JSXSpreadAttribute' && attrNode.value !== null;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Public
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
JSXOpeningElement(node) {
|
||||
node.attributes.forEach((attrNode) => {
|
||||
if (!hasEqual(attrNode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sourceCode = getSourceCode(context);
|
||||
const equalToken = sourceCode.getTokenAfter(attrNode.name);
|
||||
const spacedBefore = sourceCode.isSpaceBetweenTokens(attrNode.name, equalToken);
|
||||
const spacedAfter = sourceCode.isSpaceBetweenTokens(equalToken, attrNode.value);
|
||||
|
||||
if (config === 'never') {
|
||||
if (spacedBefore) {
|
||||
report(context, messages.noSpaceBefore, 'noSpaceBefore', {
|
||||
node: attrNode,
|
||||
loc: equalToken.loc.start,
|
||||
fix(fixer) {
|
||||
return fixer.removeRange([attrNode.name.range[1], equalToken.range[0]]);
|
||||
},
|
||||
});
|
||||
}
|
||||
if (spacedAfter) {
|
||||
report(context, messages.noSpaceAfter, 'noSpaceAfter', {
|
||||
node: attrNode,
|
||||
loc: equalToken.loc.start,
|
||||
fix(fixer) {
|
||||
return fixer.removeRange([equalToken.range[1], attrNode.value.range[0]]);
|
||||
},
|
||||
});
|
||||
}
|
||||
} else if (config === 'always') {
|
||||
if (!spacedBefore) {
|
||||
report(context, messages.needSpaceBefore, 'needSpaceBefore', {
|
||||
node: attrNode,
|
||||
loc: equalToken.loc.start,
|
||||
fix(fixer) {
|
||||
return fixer.insertTextBefore(equalToken, ' ');
|
||||
},
|
||||
});
|
||||
}
|
||||
if (!spacedAfter) {
|
||||
report(context, messages.needSpaceAfter, 'needSpaceAfter', {
|
||||
node: attrNode,
|
||||
loc: equalToken.loc.start,
|
||||
fix(fixer) {
|
||||
return fixer.insertTextAfter(equalToken, ' ');
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-filename-extension.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-filename-extension.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=jsx-filename-extension.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-filename-extension.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-filename-extension.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"jsx-filename-extension.d.ts","sourceRoot":"","sources":["jsx-filename-extension.js"],"names":[],"mappings":"wBA8BW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
120
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-filename-extension.js
generated
vendored
Normal file
120
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-filename-extension.js
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* @fileoverview Restrict file extensions that may contain JSX
|
||||
* @author Joe Lencioni
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const report = require('../util/report');
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Constants
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const DEFAULTS = {
|
||||
allow: 'always',
|
||||
extensions: ['.jsx'],
|
||||
ignoreFilesWithoutCode: false,
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const messages = {
|
||||
noJSXWithExtension: 'JSX not allowed in files with extension \'{{ext}}\'',
|
||||
extensionOnlyForJSX: 'Only files containing JSX may use the extension \'{{ext}}\'',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Disallow file extensions that may contain JSX',
|
||||
category: 'Stylistic Issues',
|
||||
recommended: false,
|
||||
url: docsUrl('jsx-filename-extension'),
|
||||
},
|
||||
|
||||
messages,
|
||||
|
||||
schema: [{
|
||||
type: 'object',
|
||||
properties: {
|
||||
allow: {
|
||||
enum: ['always', 'as-needed'],
|
||||
},
|
||||
extensions: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
ignoreFilesWithoutCode: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
}],
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const filename = context.getFilename();
|
||||
|
||||
let jsxNode;
|
||||
|
||||
if (filename === '<text>') {
|
||||
// No need to traverse any nodes.
|
||||
return {};
|
||||
}
|
||||
|
||||
const allow = (context.options[0] && context.options[0].allow) || DEFAULTS.allow;
|
||||
const allowedExtensions = (context.options[0] && context.options[0].extensions) || DEFAULTS.extensions;
|
||||
const ignoreFilesWithoutCode = (context.options[0] && context.options[0].ignoreFilesWithoutCode)
|
||||
|| DEFAULTS.ignoreFilesWithoutCode;
|
||||
const isAllowedExtension = allowedExtensions.some((extension) => filename.slice(-extension.length) === extension);
|
||||
|
||||
function handleJSX(node) {
|
||||
if (!jsxNode) {
|
||||
jsxNode = node;
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Public
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
JSXElement: handleJSX,
|
||||
JSXFragment: handleJSX,
|
||||
|
||||
'Program:exit'(node) {
|
||||
if (jsxNode) {
|
||||
if (!isAllowedExtension) {
|
||||
report(context, messages.noJSXWithExtension, 'noJSXWithExtension', {
|
||||
node: jsxNode,
|
||||
data: {
|
||||
ext: path.extname(filename),
|
||||
},
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (isAllowedExtension && allow === 'as-needed') {
|
||||
if (ignoreFilesWithoutCode && node.body.length === 0) {
|
||||
return;
|
||||
}
|
||||
report(context, messages.extensionOnlyForJSX, 'extensionOnlyForJSX', {
|
||||
node,
|
||||
data: {
|
||||
ext: path.extname(filename),
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-first-prop-new-line.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-first-prop-new-line.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=jsx-first-prop-new-line.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-first-prop-new-line.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-first-prop-new-line.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"jsx-first-prop-new-line.d.ts","sourceRoot":"","sources":["jsx-first-prop-new-line.js"],"names":[],"mappings":"wBAoBW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
83
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-first-prop-new-line.js
generated
vendored
Normal file
83
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-first-prop-new-line.js
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* @fileoverview Ensure proper position of the first property in JSX
|
||||
* @author Joachim Seminck
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const report = require('../util/report');
|
||||
const propsUtil = require('../util/props');
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const messages = {
|
||||
propOnNewLine: 'Property should be placed on a new line',
|
||||
propOnSameLine: 'Property should be placed on the same line as the component declaration',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Enforce proper position of the first property in JSX',
|
||||
category: 'Stylistic Issues',
|
||||
recommended: false,
|
||||
url: docsUrl('jsx-first-prop-new-line'),
|
||||
},
|
||||
fixable: 'code',
|
||||
|
||||
messages,
|
||||
|
||||
schema: [{
|
||||
enum: ['always', 'never', 'multiline', 'multiline-multiprop', 'multiprop'],
|
||||
}],
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const configuration = context.options[0] || 'multiline-multiprop';
|
||||
|
||||
function isMultilineJSX(jsxNode) {
|
||||
return jsxNode.loc.start.line < jsxNode.loc.end.line;
|
||||
}
|
||||
|
||||
return {
|
||||
JSXOpeningElement(node) {
|
||||
if (
|
||||
(configuration === 'multiline' && isMultilineJSX(node))
|
||||
|| (configuration === 'multiline-multiprop' && isMultilineJSX(node) && node.attributes.length > 1)
|
||||
|| (configuration === 'multiprop' && node.attributes.length > 1)
|
||||
|| (configuration === 'always')
|
||||
) {
|
||||
node.attributes.some((decl) => {
|
||||
if (decl.loc.start.line === node.loc.start.line) {
|
||||
report(context, messages.propOnNewLine, 'propOnNewLine', {
|
||||
node: decl,
|
||||
fix(fixer) {
|
||||
const nodeTypeArguments = propsUtil.getTypeArguments(node);
|
||||
return fixer.replaceTextRange([(nodeTypeArguments || node.name).range[1], decl.range[0]], '\n');
|
||||
},
|
||||
});
|
||||
}
|
||||
return true;
|
||||
});
|
||||
} else if (
|
||||
(configuration === 'never' && node.attributes.length > 0)
|
||||
|| (configuration === 'multiprop' && isMultilineJSX(node) && node.attributes.length <= 1)
|
||||
) {
|
||||
const firstNode = node.attributes[0];
|
||||
if (node.loc.start.line < firstNode.loc.start.line) {
|
||||
report(context, messages.propOnSameLine, 'propOnSameLine', {
|
||||
node: firstNode,
|
||||
fix(fixer) {
|
||||
return fixer.replaceTextRange([node.name.range[1], firstNode.range[0]], ' ');
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-fragments.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-fragments.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=jsx-fragments.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-fragments.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-fragments.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"jsx-fragments.d.ts","sourceRoot":"","sources":["jsx-fragments.js"],"names":[],"mappings":"wBA6BW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
213
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-fragments.js
generated
vendored
Normal file
213
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-fragments.js
generated
vendored
Normal file
@@ -0,0 +1,213 @@
|
||||
/**
|
||||
* @fileoverview Enforce shorthand or standard form for React fragments.
|
||||
* @author Alex Zherdev
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const elementType = require('jsx-ast-utils/elementType');
|
||||
const pragmaUtil = require('../util/pragma');
|
||||
const variableUtil = require('../util/variable');
|
||||
const testReactVersion = require('../util/version').testReactVersion;
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const report = require('../util/report');
|
||||
const getText = require('../util/eslint').getText;
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
function replaceNode(source, node, text) {
|
||||
return `${source.slice(0, node.range[0])}${text}${source.slice(node.range[1])}`;
|
||||
}
|
||||
|
||||
const messages = {
|
||||
fragmentsNotSupported: 'Fragments are only supported starting from React v16.2. Please disable the `react/jsx-fragments` rule in `eslint` settings or upgrade your version of React.',
|
||||
preferPragma: 'Prefer {{react}}.{{fragment}} over fragment shorthand',
|
||||
preferFragment: 'Prefer fragment shorthand over {{react}}.{{fragment}}',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Enforce shorthand or standard form for React fragments',
|
||||
category: 'Stylistic Issues',
|
||||
recommended: false,
|
||||
url: docsUrl('jsx-fragments'),
|
||||
},
|
||||
fixable: 'code',
|
||||
|
||||
messages,
|
||||
|
||||
schema: [{
|
||||
enum: ['syntax', 'element'],
|
||||
}],
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const configuration = context.options[0] || 'syntax';
|
||||
const reactPragma = pragmaUtil.getFromContext(context);
|
||||
const fragmentPragma = pragmaUtil.getFragmentFromContext(context);
|
||||
const openFragShort = '<>';
|
||||
const closeFragShort = '</>';
|
||||
const openFragLong = `<${reactPragma}.${fragmentPragma}>`;
|
||||
const closeFragLong = `</${reactPragma}.${fragmentPragma}>`;
|
||||
|
||||
function reportOnReactVersion(node) {
|
||||
if (!testReactVersion(context, '>= 16.2.0')) {
|
||||
report(context, messages.fragmentsNotSupported, 'fragmentsNotSupported', {
|
||||
node,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getFixerToLong(jsxFragment) {
|
||||
if (!jsxFragment.closingFragment || !jsxFragment.openingFragment) {
|
||||
// the old TS parser crashes here
|
||||
// TODO: FIXME: can we fake these two descriptors?
|
||||
return null;
|
||||
}
|
||||
return function fix(fixer) {
|
||||
let source = getText(context);
|
||||
source = replaceNode(source, jsxFragment.closingFragment, closeFragLong);
|
||||
source = replaceNode(source, jsxFragment.openingFragment, openFragLong);
|
||||
const lengthDiff = openFragLong.length - getText(context, jsxFragment.openingFragment).length
|
||||
+ closeFragLong.length - getText(context, jsxFragment.closingFragment).length;
|
||||
const range = jsxFragment.range;
|
||||
return fixer.replaceTextRange(range, source.slice(range[0], range[1] + lengthDiff));
|
||||
};
|
||||
}
|
||||
|
||||
function getFixerToShort(jsxElement) {
|
||||
return function fix(fixer) {
|
||||
let source = getText(context);
|
||||
let lengthDiff;
|
||||
if (jsxElement.closingElement) {
|
||||
source = replaceNode(source, jsxElement.closingElement, closeFragShort);
|
||||
source = replaceNode(source, jsxElement.openingElement, openFragShort);
|
||||
lengthDiff = getText(context, jsxElement.openingElement).length - openFragShort.length
|
||||
+ getText(context, jsxElement.closingElement).length - closeFragShort.length;
|
||||
} else {
|
||||
source = replaceNode(source, jsxElement.openingElement, `${openFragShort}${closeFragShort}`);
|
||||
lengthDiff = getText(context, jsxElement.openingElement).length - openFragShort.length
|
||||
- closeFragShort.length;
|
||||
}
|
||||
|
||||
const range = jsxElement.range;
|
||||
return fixer.replaceTextRange(range, source.slice(range[0], range[1] - lengthDiff));
|
||||
};
|
||||
}
|
||||
|
||||
function refersToReactFragment(node, name) {
|
||||
const variableInit = variableUtil.findVariableByName(context, node, name);
|
||||
if (!variableInit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// const { Fragment } = React;
|
||||
if (variableInit.type === 'Identifier' && variableInit.name === reactPragma) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// const Fragment = React.Fragment;
|
||||
if (
|
||||
variableInit.type === 'MemberExpression'
|
||||
&& variableInit.object.type === 'Identifier'
|
||||
&& variableInit.object.name === reactPragma
|
||||
&& variableInit.property.type === 'Identifier'
|
||||
&& variableInit.property.name === fragmentPragma
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// const { Fragment } = require('react');
|
||||
if (
|
||||
variableInit.callee
|
||||
&& variableInit.callee.name === 'require'
|
||||
&& variableInit.arguments
|
||||
&& variableInit.arguments[0]
|
||||
&& variableInit.arguments[0].value === 'react'
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const jsxElements = [];
|
||||
const fragmentNames = new Set([`${reactPragma}.${fragmentPragma}`]);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Public
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
JSXElement(node) {
|
||||
jsxElements.push(node);
|
||||
},
|
||||
|
||||
JSXFragment(node) {
|
||||
if (reportOnReactVersion(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (configuration === 'element') {
|
||||
report(context, messages.preferPragma, 'preferPragma', {
|
||||
node,
|
||||
data: {
|
||||
react: reactPragma,
|
||||
fragment: fragmentPragma,
|
||||
},
|
||||
fix: getFixerToLong(node),
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
ImportDeclaration(node) {
|
||||
if (node.source && node.source.value === 'react') {
|
||||
node.specifiers.forEach((spec) => {
|
||||
if (
|
||||
'imported' in spec
|
||||
&& spec.imported
|
||||
&& 'name' in spec.imported
|
||||
&& spec.imported.name === fragmentPragma
|
||||
) {
|
||||
if (spec.local) {
|
||||
fragmentNames.add(spec.local.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
'Program:exit'() {
|
||||
jsxElements.forEach((node) => {
|
||||
const openingEl = node.openingElement;
|
||||
const elName = elementType(openingEl);
|
||||
|
||||
if (fragmentNames.has(elName) || refersToReactFragment(node, elName)) {
|
||||
if (reportOnReactVersion(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const attrs = openingEl.attributes;
|
||||
if (configuration === 'syntax' && !(attrs && attrs.length > 0)) {
|
||||
report(context, messages.preferFragment, 'preferFragment', {
|
||||
node,
|
||||
data: {
|
||||
react: reactPragma,
|
||||
fragment: fragmentPragma,
|
||||
},
|
||||
fix: getFixerToShort(node),
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-handler-names.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-handler-names.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=jsx-handler-names.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-handler-names.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-handler-names.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"jsx-handler-names.d.ts","sourceRoot":"","sources":["jsx-handler-names.js"],"names":[],"mappings":"wBA6BW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
209
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-handler-names.js
generated
vendored
Normal file
209
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-handler-names.js
generated
vendored
Normal file
@@ -0,0 +1,209 @@
|
||||
/**
|
||||
* @fileoverview Enforce event handler naming conventions in JSX
|
||||
* @author Jake Marsh
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const minimatch = require('minimatch');
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const getText = require('../util/eslint').getText;
|
||||
const report = require('../util/report');
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const messages = {
|
||||
badHandlerName: 'Handler function for {{propKey}} prop key must be a camelCase name beginning with \'{{handlerPrefix}}\' only',
|
||||
badPropKey: 'Prop key for {{propValue}} must begin with \'{{handlerPropPrefix}}\'',
|
||||
};
|
||||
|
||||
function isPrefixDisabled(prefix) {
|
||||
return prefix === false;
|
||||
}
|
||||
|
||||
function isInlineHandler(node) {
|
||||
return node.value.expression.type === 'ArrowFunctionExpression';
|
||||
}
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Enforce event handler naming conventions in JSX',
|
||||
category: 'Stylistic Issues',
|
||||
recommended: false,
|
||||
url: docsUrl('jsx-handler-names'),
|
||||
},
|
||||
|
||||
messages,
|
||||
|
||||
schema: [{
|
||||
anyOf: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
eventHandlerPrefix: { type: 'string' },
|
||||
eventHandlerPropPrefix: { type: 'string' },
|
||||
checkLocalVariables: { type: 'boolean' },
|
||||
checkInlineFunction: { type: 'boolean' },
|
||||
ignoreComponentNames: {
|
||||
type: 'array',
|
||||
uniqueItems: true,
|
||||
items: { type: 'string' },
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
eventHandlerPrefix: { type: 'string' },
|
||||
eventHandlerPropPrefix: {
|
||||
type: 'boolean',
|
||||
enum: [false],
|
||||
},
|
||||
checkLocalVariables: { type: 'boolean' },
|
||||
checkInlineFunction: { type: 'boolean' },
|
||||
ignoreComponentNames: {
|
||||
type: 'array',
|
||||
uniqueItems: true,
|
||||
items: { type: 'string' },
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
eventHandlerPrefix: {
|
||||
type: 'boolean',
|
||||
enum: [false],
|
||||
},
|
||||
eventHandlerPropPrefix: { type: 'string' },
|
||||
checkLocalVariables: { type: 'boolean' },
|
||||
checkInlineFunction: { type: 'boolean' },
|
||||
ignoreComponentNames: {
|
||||
type: 'array',
|
||||
uniqueItems: true,
|
||||
items: { type: 'string' },
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
checkLocalVariables: { type: 'boolean' },
|
||||
},
|
||||
additionalProperties: false,
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
checkInlineFunction: { type: 'boolean' },
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
ignoreComponentNames: {
|
||||
type: 'array',
|
||||
uniqueItems: true,
|
||||
items: { type: 'string' },
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}],
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const configuration = context.options[0] || {};
|
||||
|
||||
const eventHandlerPrefix = isPrefixDisabled(configuration.eventHandlerPrefix)
|
||||
? null
|
||||
: configuration.eventHandlerPrefix || 'handle';
|
||||
const eventHandlerPropPrefix = isPrefixDisabled(configuration.eventHandlerPropPrefix)
|
||||
? null
|
||||
: configuration.eventHandlerPropPrefix || 'on';
|
||||
|
||||
const EVENT_HANDLER_REGEX = !eventHandlerPrefix
|
||||
? null
|
||||
: new RegExp(`^((props\\.${eventHandlerPropPrefix || ''})|((.*\\.)?${eventHandlerPrefix}))[0-9]*[A-Z].*$`);
|
||||
const PROP_EVENT_HANDLER_REGEX = !eventHandlerPropPrefix
|
||||
? null
|
||||
: new RegExp(`^(${eventHandlerPropPrefix}[A-Z].*|ref)$`);
|
||||
|
||||
const checkLocal = !!configuration.checkLocalVariables;
|
||||
|
||||
const checkInlineFunction = !!configuration.checkInlineFunction;
|
||||
|
||||
const ignoreComponentNames = configuration.ignoreComponentNames || [];
|
||||
|
||||
return {
|
||||
JSXAttribute(node) {
|
||||
const componentName = node.parent.name.name;
|
||||
|
||||
const isComponentNameIgnored = ignoreComponentNames.some((ignoredComponentNamePattern) => minimatch(
|
||||
componentName,
|
||||
ignoredComponentNamePattern
|
||||
));
|
||||
|
||||
if (
|
||||
!node.value
|
||||
|| !node.value.expression
|
||||
|| (!checkInlineFunction && isInlineHandler(node))
|
||||
|| (
|
||||
!checkLocal
|
||||
&& (isInlineHandler(node)
|
||||
? !node.value.expression.body.callee || !node.value.expression.body.callee.object
|
||||
: !node.value.expression.object
|
||||
)
|
||||
)
|
||||
|| isComponentNameIgnored
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const propKey = typeof node.name === 'object' ? node.name.name : node.name;
|
||||
const expression = node.value.expression;
|
||||
const propValue = getText(
|
||||
context,
|
||||
checkInlineFunction && isInlineHandler(node) ? expression.body.callee : expression
|
||||
).replace(/\s*/g, '').replace(/^this\.|.*::/, '');
|
||||
|
||||
if (propKey === 'ref') {
|
||||
return;
|
||||
}
|
||||
|
||||
const propIsEventHandler = PROP_EVENT_HANDLER_REGEX && PROP_EVENT_HANDLER_REGEX.test(propKey);
|
||||
const propFnIsNamedCorrectly = EVENT_HANDLER_REGEX && EVENT_HANDLER_REGEX.test(propValue);
|
||||
|
||||
if (
|
||||
propIsEventHandler
|
||||
&& propFnIsNamedCorrectly !== null
|
||||
&& !propFnIsNamedCorrectly
|
||||
) {
|
||||
report(context, messages.badHandlerName, 'badHandlerName', {
|
||||
node,
|
||||
data: {
|
||||
propKey,
|
||||
handlerPrefix: eventHandlerPrefix,
|
||||
},
|
||||
});
|
||||
} else if (
|
||||
propFnIsNamedCorrectly
|
||||
&& propIsEventHandler !== null
|
||||
&& !propIsEventHandler
|
||||
) {
|
||||
report(context, messages.badPropKey, 'badPropKey', {
|
||||
node,
|
||||
data: {
|
||||
propValue,
|
||||
handlerPropPrefix: eventHandlerPropPrefix,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-indent-props.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-indent-props.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=jsx-indent-props.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-indent-props.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-indent-props.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"jsx-indent-props.d.ts","sourceRoot":"","sources":["jsx-indent-props.js"],"names":[],"mappings":"wBA+CW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
218
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-indent-props.js
generated
vendored
Normal file
218
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-indent-props.js
generated
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
/**
|
||||
* @fileoverview Validate props indentation in JSX
|
||||
* @author Yannick Croissant
|
||||
|
||||
* This rule has been ported and modified from eslint and nodeca.
|
||||
* @author Vitaly Puzrin
|
||||
* @author Gyandeep Singh
|
||||
* @copyright 2015 Vitaly Puzrin. All rights reserved.
|
||||
* @copyright 2015 Gyandeep Singh. All rights reserved.
|
||||
Copyright (C) 2014 by Vitaly Puzrin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the 'Software'), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const repeat = require('string.prototype.repeat');
|
||||
|
||||
const astUtil = require('../util/ast');
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const getText = require('../util/eslint').getText;
|
||||
const reportC = require('../util/report');
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const messages = {
|
||||
wrongIndent: 'Expected indentation of {{needed}} {{type}} {{characters}} but found {{gotten}}.',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Enforce props indentation in JSX',
|
||||
category: 'Stylistic Issues',
|
||||
recommended: false,
|
||||
url: docsUrl('jsx-indent-props'),
|
||||
},
|
||||
fixable: 'code',
|
||||
|
||||
messages,
|
||||
|
||||
schema: [{
|
||||
anyOf: [{
|
||||
enum: ['tab', 'first'],
|
||||
}, {
|
||||
type: 'integer',
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
indentMode: {
|
||||
anyOf: [{
|
||||
enum: ['tab', 'first'],
|
||||
}, {
|
||||
type: 'integer',
|
||||
}],
|
||||
},
|
||||
ignoreTernaryOperator: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
}],
|
||||
}],
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const extraColumnStart = 0;
|
||||
let indentType = 'space';
|
||||
/** @type {number|'first'} */
|
||||
let indentSize = 4;
|
||||
const line = {
|
||||
isUsingOperator: false,
|
||||
currentOperator: false,
|
||||
};
|
||||
let ignoreTernaryOperator = false;
|
||||
|
||||
if (context.options.length) {
|
||||
const isConfigObject = typeof context.options[0] === 'object';
|
||||
const indentMode = isConfigObject
|
||||
? context.options[0].indentMode
|
||||
: context.options[0];
|
||||
|
||||
if (indentMode === 'first') {
|
||||
indentSize = 'first';
|
||||
indentType = 'space';
|
||||
} else if (indentMode === 'tab') {
|
||||
indentSize = 1;
|
||||
indentType = 'tab';
|
||||
} else if (typeof indentMode === 'number') {
|
||||
indentSize = indentMode;
|
||||
indentType = 'space';
|
||||
}
|
||||
|
||||
if (isConfigObject && context.options[0].ignoreTernaryOperator) {
|
||||
ignoreTernaryOperator = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports a given indent violation and properly pluralizes the message
|
||||
* @param {ASTNode} node Node violating the indent rule
|
||||
* @param {number} needed Expected indentation character count
|
||||
* @param {number} gotten Indentation character count in the actual node/code
|
||||
*/
|
||||
function report(node, needed, gotten) {
|
||||
const msgContext = {
|
||||
needed,
|
||||
type: indentType,
|
||||
characters: needed === 1 ? 'character' : 'characters',
|
||||
gotten,
|
||||
};
|
||||
|
||||
reportC(context, messages.wrongIndent, 'wrongIndent', {
|
||||
node,
|
||||
data: msgContext,
|
||||
fix(fixer) {
|
||||
return fixer.replaceTextRange([node.range[0] - node.loc.start.column, node.range[0]],
|
||||
repeat(indentType === 'space' ? ' ' : '\t', needed)
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get node indent
|
||||
* @param {ASTNode} node Node to examine
|
||||
* @return {number} Indent
|
||||
*/
|
||||
function getNodeIndent(node) {
|
||||
let src = getText(context, node, node.loc.start.column + extraColumnStart);
|
||||
const lines = src.split('\n');
|
||||
src = lines[0];
|
||||
|
||||
let regExp;
|
||||
if (indentType === 'space') {
|
||||
regExp = /^[ ]+/;
|
||||
} else {
|
||||
regExp = /^[\t]+/;
|
||||
}
|
||||
|
||||
const indent = regExp.exec(src);
|
||||
const useOperator = /^([ ]|[\t])*[:]/.test(src) || /^([ ]|[\t])*[?]/.test(src);
|
||||
const useBracket = /[<]/.test(src);
|
||||
|
||||
line.currentOperator = false;
|
||||
if (useOperator) {
|
||||
line.isUsingOperator = true;
|
||||
line.currentOperator = true;
|
||||
} else if (useBracket) {
|
||||
line.isUsingOperator = false;
|
||||
}
|
||||
|
||||
return indent ? indent[0].length : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check indent for nodes list
|
||||
* @param {ASTNode[]} nodes list of node objects
|
||||
* @param {number} indent needed indent
|
||||
*/
|
||||
function checkNodesIndent(nodes, indent) {
|
||||
let nestedIndent = indent;
|
||||
nodes.forEach((node) => {
|
||||
const nodeIndent = getNodeIndent(node);
|
||||
if (
|
||||
line.isUsingOperator
|
||||
&& !line.currentOperator
|
||||
&& indentSize !== 'first'
|
||||
&& !ignoreTernaryOperator
|
||||
) {
|
||||
nestedIndent += indentSize;
|
||||
line.isUsingOperator = false;
|
||||
}
|
||||
if (
|
||||
node.type !== 'ArrayExpression' && node.type !== 'ObjectExpression'
|
||||
&& nodeIndent !== nestedIndent && astUtil.isNodeFirstInLine(context, node)
|
||||
) {
|
||||
report(node, nestedIndent, nodeIndent);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
JSXOpeningElement(node) {
|
||||
if (!node.attributes.length) {
|
||||
return;
|
||||
}
|
||||
let propIndent;
|
||||
if (indentSize === 'first') {
|
||||
const firstPropNode = node.attributes[0];
|
||||
propIndent = firstPropNode.loc.start.column;
|
||||
} else {
|
||||
const elementIndent = getNodeIndent(node);
|
||||
propIndent = elementIndent + indentSize;
|
||||
}
|
||||
checkNodesIndent(node.attributes, propIndent);
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-indent.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-indent.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=jsx-indent.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-indent.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-indent.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"jsx-indent.d.ts","sourceRoot":"","sources":["jsx-indent.js"],"names":[],"mappings":"wBAoDW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
447
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-indent.js
generated
vendored
Normal file
447
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-indent.js
generated
vendored
Normal file
@@ -0,0 +1,447 @@
|
||||
/**
|
||||
* @fileoverview Validate JSX indentation
|
||||
* @author Yannick Croissant
|
||||
|
||||
* This rule has been ported and modified from eslint and nodeca.
|
||||
* @author Vitaly Puzrin
|
||||
* @author Gyandeep Singh
|
||||
* @copyright 2015 Vitaly Puzrin. All rights reserved.
|
||||
* @copyright 2015 Gyandeep Singh. All rights reserved.
|
||||
Copyright (C) 2014 by Vitaly Puzrin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the 'Software'), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const matchAll = require('string.prototype.matchall');
|
||||
const repeat = require('string.prototype.repeat');
|
||||
|
||||
const astUtil = require('../util/ast');
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const reportC = require('../util/report');
|
||||
const jsxUtil = require('../util/jsx');
|
||||
const eslintUtil = require('../util/eslint');
|
||||
|
||||
const getSourceCode = eslintUtil.getSourceCode;
|
||||
const getText = eslintUtil.getText;
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const messages = {
|
||||
wrongIndent: 'Expected indentation of {{needed}} {{type}} {{characters}} but found {{gotten}}.',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Enforce JSX indentation',
|
||||
category: 'Stylistic Issues',
|
||||
recommended: false,
|
||||
url: docsUrl('jsx-indent'),
|
||||
},
|
||||
fixable: 'whitespace',
|
||||
|
||||
messages,
|
||||
|
||||
schema: [{
|
||||
anyOf: [{
|
||||
enum: ['tab'],
|
||||
}, {
|
||||
type: 'integer',
|
||||
}],
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
checkAttributes: {
|
||||
type: 'boolean',
|
||||
},
|
||||
indentLogicalExpressions: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
}],
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const extraColumnStart = 0;
|
||||
let indentType = 'space';
|
||||
let indentSize = 4;
|
||||
|
||||
if (context.options.length) {
|
||||
if (context.options[0] === 'tab') {
|
||||
indentSize = 1;
|
||||
indentType = 'tab';
|
||||
} else if (typeof context.options[0] === 'number') {
|
||||
indentSize = context.options[0];
|
||||
indentType = 'space';
|
||||
}
|
||||
}
|
||||
|
||||
const indentChar = indentType === 'space' ? ' ' : '\t';
|
||||
const options = context.options[1] || {};
|
||||
const checkAttributes = options.checkAttributes || false;
|
||||
const indentLogicalExpressions = options.indentLogicalExpressions || false;
|
||||
|
||||
/**
|
||||
* Responsible for fixing the indentation issue fix
|
||||
* @param {ASTNode} node Node violating the indent rule
|
||||
* @param {number} needed Expected indentation character count
|
||||
* @returns {Function} function to be executed by the fixer
|
||||
* @private
|
||||
*/
|
||||
function getFixerFunction(node, needed) {
|
||||
const indent = repeat(indentChar, needed);
|
||||
|
||||
if (node.type === 'JSXText' || node.type === 'Literal') {
|
||||
return function fix(fixer) {
|
||||
const regExp = /\n[\t ]*(\S)/g;
|
||||
const fixedText = node.raw.replace(regExp, (match, p1) => `\n${indent}${p1}`);
|
||||
return fixer.replaceText(node, fixedText);
|
||||
};
|
||||
}
|
||||
|
||||
if (node.type === 'ReturnStatement') {
|
||||
const raw = getText(context, node);
|
||||
const lines = raw.split('\n');
|
||||
if (lines.length > 1) {
|
||||
return function fix(fixer) {
|
||||
const lastLineStart = raw.lastIndexOf('\n');
|
||||
const lastLine = raw.slice(lastLineStart).replace(/^\n[\t ]*(\S)/, (match, p1) => `\n${indent}${p1}`);
|
||||
return fixer.replaceTextRange(
|
||||
[node.range[0] + lastLineStart, node.range[1]],
|
||||
lastLine
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return function fix(fixer) {
|
||||
return fixer.replaceTextRange(
|
||||
[node.range[0] - node.loc.start.column, node.range[0]],
|
||||
indent
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports a given indent violation and properly pluralizes the message
|
||||
* @param {ASTNode} node Node violating the indent rule
|
||||
* @param {number} needed Expected indentation character count
|
||||
* @param {number} gotten Indentation character count in the actual node/code
|
||||
* @param {Object} [loc] Error line and column location
|
||||
*/
|
||||
function report(node, needed, gotten, loc) {
|
||||
const msgContext = {
|
||||
needed,
|
||||
type: indentType,
|
||||
characters: needed === 1 ? 'character' : 'characters',
|
||||
gotten,
|
||||
};
|
||||
|
||||
reportC(context, messages.wrongIndent, 'wrongIndent', Object.assign({
|
||||
node,
|
||||
data: msgContext,
|
||||
fix: getFixerFunction(node, needed),
|
||||
}, loc && { loc }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get node indent
|
||||
* @param {ASTNode} node Node to examine
|
||||
* @param {boolean} [byLastLine] get indent of node's last line
|
||||
* @param {boolean} [excludeCommas] skip comma on start of line
|
||||
* @return {number} Indent
|
||||
*/
|
||||
function getNodeIndent(node, byLastLine, excludeCommas) {
|
||||
let src = getText(context, node, node.loc.start.column + extraColumnStart);
|
||||
const lines = src.split('\n');
|
||||
if (byLastLine) {
|
||||
src = lines[lines.length - 1];
|
||||
} else {
|
||||
src = lines[0];
|
||||
}
|
||||
|
||||
const skip = excludeCommas ? ',' : '';
|
||||
|
||||
let regExp;
|
||||
if (indentType === 'space') {
|
||||
regExp = new RegExp(`^[ ${skip}]+`);
|
||||
} else {
|
||||
regExp = new RegExp(`^[\t${skip}]+`);
|
||||
}
|
||||
|
||||
const indent = regExp.exec(src);
|
||||
return indent ? indent[0].length : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the node is the right member of a logical expression
|
||||
* @param {ASTNode} node The node to check
|
||||
* @return {boolean} true if its the case, false if not
|
||||
*/
|
||||
function isRightInLogicalExp(node) {
|
||||
return (
|
||||
node.parent
|
||||
&& node.parent.parent
|
||||
&& node.parent.parent.type === 'LogicalExpression'
|
||||
&& node.parent.parent.right === node.parent
|
||||
&& !indentLogicalExpressions
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the node is the alternate member of a conditional expression
|
||||
* @param {ASTNode} node The node to check
|
||||
* @return {boolean} true if its the case, false if not
|
||||
*/
|
||||
function isAlternateInConditionalExp(node) {
|
||||
return (
|
||||
node.parent
|
||||
&& node.parent.parent
|
||||
&& node.parent.parent.type === 'ConditionalExpression'
|
||||
&& node.parent.parent.alternate === node.parent
|
||||
&& getSourceCode(context).getTokenBefore(node).value !== '('
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the node is within a DoExpression block but not the first expression (which need to be indented)
|
||||
* @param {ASTNode} node The node to check
|
||||
* @return {boolean} true if its the case, false if not
|
||||
*/
|
||||
function isSecondOrSubsequentExpWithinDoExp(node) {
|
||||
/*
|
||||
It returns true when node.parent.parent.parent.parent matches:
|
||||
|
||||
DoExpression({
|
||||
...,
|
||||
body: BlockStatement({
|
||||
...,
|
||||
body: [
|
||||
..., // 1-n times
|
||||
ExpressionStatement({
|
||||
...,
|
||||
expression: JSXElement({
|
||||
...,
|
||||
openingElement: JSXOpeningElement() // the node
|
||||
})
|
||||
}),
|
||||
... // 0-n times
|
||||
]
|
||||
})
|
||||
})
|
||||
|
||||
except:
|
||||
|
||||
DoExpression({
|
||||
...,
|
||||
body: BlockStatement({
|
||||
...,
|
||||
body: [
|
||||
ExpressionStatement({
|
||||
...,
|
||||
expression: JSXElement({
|
||||
...,
|
||||
openingElement: JSXOpeningElement() // the node
|
||||
})
|
||||
}),
|
||||
... // 0-n times
|
||||
]
|
||||
})
|
||||
})
|
||||
*/
|
||||
const isInExpStmt = (
|
||||
node.parent
|
||||
&& node.parent.parent
|
||||
&& node.parent.parent.type === 'ExpressionStatement'
|
||||
);
|
||||
if (!isInExpStmt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const expStmt = node.parent.parent;
|
||||
const isInBlockStmtWithinDoExp = (
|
||||
expStmt.parent
|
||||
&& expStmt.parent.type === 'BlockStatement'
|
||||
&& expStmt.parent.parent
|
||||
&& expStmt.parent.parent.type === 'DoExpression'
|
||||
);
|
||||
if (!isInBlockStmtWithinDoExp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const blockStmt = expStmt.parent;
|
||||
const blockStmtFirstExp = blockStmt.body[0];
|
||||
return !(blockStmtFirstExp === expStmt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check indent for nodes list
|
||||
* @param {ASTNode} node The node to check
|
||||
* @param {number} indent needed indent
|
||||
* @param {boolean} [excludeCommas] skip comma on start of line
|
||||
*/
|
||||
function checkNodesIndent(node, indent, excludeCommas) {
|
||||
const nodeIndent = getNodeIndent(node, false, excludeCommas);
|
||||
const isCorrectRightInLogicalExp = isRightInLogicalExp(node) && (nodeIndent - indent) === indentSize;
|
||||
const isCorrectAlternateInCondExp = isAlternateInConditionalExp(node) && (nodeIndent - indent) === 0;
|
||||
if (
|
||||
nodeIndent !== indent
|
||||
&& astUtil.isNodeFirstInLine(context, node)
|
||||
&& !isCorrectRightInLogicalExp
|
||||
&& !isCorrectAlternateInCondExp
|
||||
) {
|
||||
report(node, indent, nodeIndent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check indent for Literal Node or JSXText Node
|
||||
* @param {ASTNode} node The node to check
|
||||
* @param {number} indent needed indent
|
||||
*/
|
||||
function checkLiteralNodeIndent(node, indent) {
|
||||
const value = node.value;
|
||||
const regExp = indentType === 'space' ? /\n( *)[\t ]*\S/g : /\n(\t*)[\t ]*\S/g;
|
||||
const nodeIndentsPerLine = Array.from(
|
||||
matchAll(String(value), regExp),
|
||||
(match) => (match[1] ? match[1].length : 0)
|
||||
);
|
||||
const hasFirstInLineNode = nodeIndentsPerLine.length > 0;
|
||||
if (
|
||||
hasFirstInLineNode
|
||||
&& !nodeIndentsPerLine.every((actualIndent) => actualIndent === indent)
|
||||
) {
|
||||
nodeIndentsPerLine.forEach((nodeIndent) => {
|
||||
report(node, indent, nodeIndent);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handleOpeningElement(node) {
|
||||
const sourceCode = getSourceCode(context);
|
||||
let prevToken = sourceCode.getTokenBefore(node);
|
||||
if (!prevToken) {
|
||||
return;
|
||||
}
|
||||
// Use the parent in a list or an array
|
||||
if (prevToken.type === 'JSXText' || ((prevToken.type === 'Punctuator') && prevToken.value === ',')) {
|
||||
prevToken = sourceCode.getNodeByRangeIndex(prevToken.range[0]);
|
||||
prevToken = prevToken.type === 'Literal' || prevToken.type === 'JSXText' ? prevToken.parent : prevToken;
|
||||
// Use the first non-punctuator token in a conditional expression
|
||||
} else if (prevToken.type === 'Punctuator' && prevToken.value === ':') {
|
||||
do {
|
||||
prevToken = sourceCode.getTokenBefore(prevToken);
|
||||
} while (prevToken.type === 'Punctuator' && prevToken.value !== '/');
|
||||
prevToken = sourceCode.getNodeByRangeIndex(prevToken.range[0]);
|
||||
while (prevToken.parent && prevToken.parent.type !== 'ConditionalExpression') {
|
||||
prevToken = prevToken.parent;
|
||||
}
|
||||
}
|
||||
prevToken = prevToken.type === 'JSXExpressionContainer' ? prevToken.expression : prevToken;
|
||||
const parentElementIndent = getNodeIndent(prevToken);
|
||||
const indent = (
|
||||
prevToken.loc.start.line === node.loc.start.line
|
||||
|| isRightInLogicalExp(node)
|
||||
|| isAlternateInConditionalExp(node)
|
||||
|| isSecondOrSubsequentExpWithinDoExp(node)
|
||||
) ? 0 : indentSize;
|
||||
checkNodesIndent(node, parentElementIndent + indent);
|
||||
}
|
||||
|
||||
function handleClosingElement(node) {
|
||||
if (!node.parent) {
|
||||
return;
|
||||
}
|
||||
const peerElementIndent = getNodeIndent(node.parent.openingElement || node.parent.openingFragment);
|
||||
checkNodesIndent(node, peerElementIndent);
|
||||
}
|
||||
|
||||
function handleAttribute(node) {
|
||||
if (!checkAttributes || (!node.value || node.value.type !== 'JSXExpressionContainer')) {
|
||||
return;
|
||||
}
|
||||
const nameIndent = getNodeIndent(node.name);
|
||||
const lastToken = getSourceCode(context).getLastToken(node.value);
|
||||
const firstInLine = astUtil.getFirstNodeInLine(context, lastToken);
|
||||
const indent = node.name.loc.start.line === firstInLine.loc.start.line ? 0 : nameIndent;
|
||||
checkNodesIndent(firstInLine, indent);
|
||||
}
|
||||
|
||||
function handleLiteral(node) {
|
||||
if (!node.parent) {
|
||||
return;
|
||||
}
|
||||
if (node.parent.type !== 'JSXElement' && node.parent.type !== 'JSXFragment') {
|
||||
return;
|
||||
}
|
||||
const parentNodeIndent = getNodeIndent(node.parent);
|
||||
checkLiteralNodeIndent(node, parentNodeIndent + indentSize);
|
||||
}
|
||||
|
||||
return {
|
||||
JSXOpeningElement: handleOpeningElement,
|
||||
JSXOpeningFragment: handleOpeningElement,
|
||||
JSXClosingElement: handleClosingElement,
|
||||
JSXClosingFragment: handleClosingElement,
|
||||
JSXAttribute: handleAttribute,
|
||||
JSXExpressionContainer(node) {
|
||||
if (!node.parent) {
|
||||
return;
|
||||
}
|
||||
const parentNodeIndent = getNodeIndent(node.parent);
|
||||
checkNodesIndent(node, parentNodeIndent + indentSize);
|
||||
},
|
||||
Literal: handleLiteral,
|
||||
JSXText: handleLiteral,
|
||||
|
||||
ReturnStatement(node) {
|
||||
if (
|
||||
!node.parent
|
||||
|| !jsxUtil.isJSX(node.argument)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
let fn = node.parent;
|
||||
while (fn && fn.type !== 'FunctionDeclaration' && fn.type !== 'FunctionExpression') {
|
||||
fn = fn.parent;
|
||||
}
|
||||
if (
|
||||
!fn
|
||||
|| !jsxUtil.isReturningJSX(context, node, true)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const openingIndent = getNodeIndent(node);
|
||||
const closingIndent = getNodeIndent(node, true);
|
||||
|
||||
if (openingIndent !== closingIndent) {
|
||||
report(node, openingIndent, closingIndent);
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-key.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-key.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=jsx-key.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-key.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-key.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"jsx-key.d.ts","sourceRoot":"","sources":["jsx-key.js"],"names":[],"mappings":"wBAmCW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
303
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-key.js
generated
vendored
Normal file
303
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-key.js
generated
vendored
Normal file
@@ -0,0 +1,303 @@
|
||||
/**
|
||||
* @fileoverview Report missing `key` props in iterators/collection literals.
|
||||
* @author Ben Mosher
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const hasProp = require('jsx-ast-utils/hasProp');
|
||||
const propName = require('jsx-ast-utils/propName');
|
||||
const values = require('object.values');
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const pragmaUtil = require('../util/pragma');
|
||||
const report = require('../util/report');
|
||||
const astUtil = require('../util/ast');
|
||||
const getText = require('../util/eslint').getText;
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const defaultOptions = {
|
||||
checkFragmentShorthand: false,
|
||||
checkKeyMustBeforeSpread: false,
|
||||
warnOnDuplicates: false,
|
||||
};
|
||||
|
||||
const messages = {
|
||||
missingIterKey: 'Missing "key" prop for element in iterator',
|
||||
missingIterKeyUsePrag: 'Missing "key" prop for element in iterator. Shorthand fragment syntax does not support providing keys. Use {{reactPrag}}.{{fragPrag}} instead',
|
||||
missingArrayKey: 'Missing "key" prop for element in array',
|
||||
missingArrayKeyUsePrag: 'Missing "key" prop for element in array. Shorthand fragment syntax does not support providing keys. Use {{reactPrag}}.{{fragPrag}} instead',
|
||||
keyBeforeSpread: '`key` prop must be placed before any `{...spread}, to avoid conflicting with React’s new JSX transform: https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html`',
|
||||
nonUniqueKeys: '`key` prop must be unique',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Disallow missing `key` props in iterators/collection literals',
|
||||
category: 'Possible Errors',
|
||||
recommended: true,
|
||||
url: docsUrl('jsx-key'),
|
||||
},
|
||||
|
||||
messages,
|
||||
|
||||
schema: [{
|
||||
type: 'object',
|
||||
properties: {
|
||||
checkFragmentShorthand: {
|
||||
type: 'boolean',
|
||||
default: defaultOptions.checkFragmentShorthand,
|
||||
},
|
||||
checkKeyMustBeforeSpread: {
|
||||
type: 'boolean',
|
||||
default: defaultOptions.checkKeyMustBeforeSpread,
|
||||
},
|
||||
warnOnDuplicates: {
|
||||
type: 'boolean',
|
||||
default: defaultOptions.warnOnDuplicates,
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
}],
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const options = Object.assign({}, defaultOptions, context.options[0]);
|
||||
const checkFragmentShorthand = options.checkFragmentShorthand;
|
||||
const checkKeyMustBeforeSpread = options.checkKeyMustBeforeSpread;
|
||||
const warnOnDuplicates = options.warnOnDuplicates;
|
||||
const reactPragma = pragmaUtil.getFromContext(context);
|
||||
const fragmentPragma = pragmaUtil.getFragmentFromContext(context);
|
||||
|
||||
function isKeyAfterSpread(attributes) {
|
||||
let hasFoundSpread = false;
|
||||
return attributes.some((attribute) => {
|
||||
if (attribute.type === 'JSXSpreadAttribute') {
|
||||
hasFoundSpread = true;
|
||||
return false;
|
||||
}
|
||||
if (attribute.type !== 'JSXAttribute') {
|
||||
return false;
|
||||
}
|
||||
return hasFoundSpread && propName(attribute) === 'key';
|
||||
});
|
||||
}
|
||||
|
||||
function checkIteratorElement(node) {
|
||||
if (node.type === 'JSXElement') {
|
||||
if (!hasProp(node.openingElement.attributes, 'key')) {
|
||||
report(context, messages.missingIterKey, 'missingIterKey', { node });
|
||||
} else {
|
||||
const attrs = node.openingElement.attributes;
|
||||
|
||||
if (checkKeyMustBeforeSpread && isKeyAfterSpread(attrs)) {
|
||||
report(context, messages.keyBeforeSpread, 'keyBeforeSpread', { node });
|
||||
}
|
||||
}
|
||||
} else if (checkFragmentShorthand && node.type === 'JSXFragment') {
|
||||
report(context, messages.missingIterKeyUsePrag, 'missingIterKeyUsePrag', {
|
||||
node,
|
||||
data: {
|
||||
reactPrag: reactPragma,
|
||||
fragPrag: fragmentPragma,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getReturnStatements(node) {
|
||||
const returnStatements = arguments[1] || [];
|
||||
if (node.type === 'IfStatement') {
|
||||
if (node.consequent) {
|
||||
getReturnStatements(node.consequent, returnStatements);
|
||||
}
|
||||
if (node.alternate) {
|
||||
getReturnStatements(node.alternate, returnStatements);
|
||||
}
|
||||
} else if (node.type === 'ReturnStatement') {
|
||||
returnStatements.push(node);
|
||||
} else if (Array.isArray(node.body)) {
|
||||
node.body.forEach((item) => {
|
||||
if (item.type === 'IfStatement') {
|
||||
getReturnStatements(item, returnStatements);
|
||||
}
|
||||
|
||||
if (item.type === 'ReturnStatement') {
|
||||
returnStatements.push(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return returnStatements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given node is a function expression or arrow function,
|
||||
* and checks if there is a missing key prop in return statement's arguments
|
||||
* @param {ASTNode} node
|
||||
*/
|
||||
function checkFunctionsBlockStatement(node) {
|
||||
if (astUtil.isFunctionLikeExpression(node)) {
|
||||
if (node.body.type === 'BlockStatement') {
|
||||
getReturnStatements(node.body)
|
||||
.filter((returnStatement) => returnStatement && returnStatement.argument)
|
||||
.forEach((returnStatement) => {
|
||||
checkIteratorElement(returnStatement.argument);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given node is an arrow function that has an JSX Element or JSX Fragment in its body,
|
||||
* and the JSX is missing a key prop
|
||||
* @param {ASTNode} node
|
||||
*/
|
||||
function checkArrowFunctionWithJSX(node) {
|
||||
const isArrFn = node && node.type === 'ArrowFunctionExpression';
|
||||
const shouldCheckNode = (n) => n && (n.type === 'JSXElement' || n.type === 'JSXFragment');
|
||||
if (isArrFn && shouldCheckNode(node.body)) {
|
||||
checkIteratorElement(node.body);
|
||||
}
|
||||
if (node.body.type === 'ConditionalExpression') {
|
||||
if (shouldCheckNode(node.body.consequent)) {
|
||||
checkIteratorElement(node.body.consequent);
|
||||
}
|
||||
if (shouldCheckNode(node.body.alternate)) {
|
||||
checkIteratorElement(node.body.alternate);
|
||||
}
|
||||
} else if (node.body.type === 'LogicalExpression' && shouldCheckNode(node.body.right)) {
|
||||
checkIteratorElement(node.body.right);
|
||||
}
|
||||
}
|
||||
|
||||
const childrenToArraySelector = `:matches(
|
||||
CallExpression
|
||||
[callee.object.object.name=${reactPragma}]
|
||||
[callee.object.property.name=Children]
|
||||
[callee.property.name=toArray],
|
||||
CallExpression
|
||||
[callee.object.name=Children]
|
||||
[callee.property.name=toArray]
|
||||
)`.replace(/\s/g, '');
|
||||
let isWithinChildrenToArray = false;
|
||||
|
||||
const seen = new WeakSet();
|
||||
|
||||
return {
|
||||
[childrenToArraySelector]() {
|
||||
isWithinChildrenToArray = true;
|
||||
},
|
||||
|
||||
[`${childrenToArraySelector}:exit`]() {
|
||||
isWithinChildrenToArray = false;
|
||||
},
|
||||
|
||||
'ArrayExpression, JSXElement > JSXElement'(node) {
|
||||
if (isWithinChildrenToArray) {
|
||||
return;
|
||||
}
|
||||
|
||||
const jsx = (node.type === 'ArrayExpression' ? node.elements : node.parent.children).filter((x) => x && x.type === 'JSXElement');
|
||||
if (jsx.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const map = {};
|
||||
jsx.forEach((element) => {
|
||||
const attrs = element.openingElement.attributes;
|
||||
const keys = attrs.filter((x) => x.name && x.name.name === 'key');
|
||||
|
||||
if (keys.length === 0) {
|
||||
if (node.type === 'ArrayExpression') {
|
||||
report(context, messages.missingArrayKey, 'missingArrayKey', {
|
||||
node: element,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
keys.forEach((attr) => {
|
||||
const value = getText(context, attr.value);
|
||||
if (!map[value]) { map[value] = []; }
|
||||
map[value].push(attr);
|
||||
|
||||
if (checkKeyMustBeforeSpread && isKeyAfterSpread(attrs)) {
|
||||
report(context, messages.keyBeforeSpread, 'keyBeforeSpread', {
|
||||
node: node.type === 'ArrayExpression' ? node : node.parent,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (warnOnDuplicates) {
|
||||
values(map).filter((v) => v.length > 1).forEach((v) => {
|
||||
v.forEach((n) => {
|
||||
if (!seen.has(n)) {
|
||||
seen.add(n);
|
||||
report(context, messages.nonUniqueKeys, 'nonUniqueKeys', {
|
||||
node: n,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
JSXFragment(node) {
|
||||
if (!checkFragmentShorthand || isWithinChildrenToArray) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.parent.type === 'ArrayExpression') {
|
||||
report(context, messages.missingArrayKeyUsePrag, 'missingArrayKeyUsePrag', {
|
||||
node,
|
||||
data: {
|
||||
reactPrag: reactPragma,
|
||||
fragPrag: fragmentPragma,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// Array.prototype.map
|
||||
// eslint-disable-next-line no-multi-str
|
||||
'CallExpression[callee.type="MemberExpression"][callee.property.name="map"],\
|
||||
CallExpression[callee.type="OptionalMemberExpression"][callee.property.name="map"],\
|
||||
OptionalCallExpression[callee.type="MemberExpression"][callee.property.name="map"],\
|
||||
OptionalCallExpression[callee.type="OptionalMemberExpression"][callee.property.name="map"]'(node) {
|
||||
if (isWithinChildrenToArray) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fn = node.arguments.length > 0 && node.arguments[0];
|
||||
if (!fn || !astUtil.isFunctionLikeExpression(fn)) {
|
||||
return;
|
||||
}
|
||||
|
||||
checkArrowFunctionWithJSX(fn);
|
||||
|
||||
checkFunctionsBlockStatement(fn);
|
||||
},
|
||||
|
||||
// Array.from
|
||||
'CallExpression[callee.type="MemberExpression"][callee.property.name="from"]'(node) {
|
||||
if (isWithinChildrenToArray) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fn = node.arguments.length > 1 && node.arguments[1];
|
||||
if (!astUtil.isFunctionLikeExpression(fn)) {
|
||||
return;
|
||||
}
|
||||
|
||||
checkArrowFunctionWithJSX(fn);
|
||||
|
||||
checkFunctionsBlockStatement(fn);
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-max-depth.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-max-depth.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=jsx-max-depth.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-max-depth.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-max-depth.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"jsx-max-depth.d.ts","sourceRoot":"","sources":["jsx-max-depth.js"],"names":[],"mappings":"wBAsBW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
162
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-max-depth.js
generated
vendored
Normal file
162
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-max-depth.js
generated
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
/**
|
||||
* @fileoverview Validate JSX maximum depth
|
||||
* @author Chris<wfsr@foxmail.com>
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const has = require('hasown');
|
||||
const includes = require('array-includes');
|
||||
const variableUtil = require('../util/variable');
|
||||
const jsxUtil = require('../util/jsx');
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const reportC = require('../util/report');
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const messages = {
|
||||
wrongDepth: 'Expected the depth of nested jsx elements to be <= {{needed}}, but found {{found}}.',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Enforce JSX maximum depth',
|
||||
category: 'Stylistic Issues',
|
||||
recommended: false,
|
||||
url: docsUrl('jsx-max-depth'),
|
||||
},
|
||||
|
||||
messages,
|
||||
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
max: {
|
||||
type: 'integer',
|
||||
minimum: 0,
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
create(context) {
|
||||
const DEFAULT_DEPTH = 2;
|
||||
|
||||
const option = context.options[0] || {};
|
||||
const maxDepth = has(option, 'max') ? option.max : DEFAULT_DEPTH;
|
||||
|
||||
function isExpression(node) {
|
||||
return node.type === 'JSXExpressionContainer';
|
||||
}
|
||||
|
||||
function hasJSX(node) {
|
||||
return jsxUtil.isJSX(node) || (isExpression(node) && jsxUtil.isJSX(node.expression));
|
||||
}
|
||||
|
||||
function isLeaf(node) {
|
||||
const children = node.children;
|
||||
|
||||
return !children || children.length === 0 || !children.some(hasJSX);
|
||||
}
|
||||
|
||||
function getDepth(node) {
|
||||
let count = 0;
|
||||
|
||||
while (jsxUtil.isJSX(node.parent) || isExpression(node.parent)) {
|
||||
node = node.parent;
|
||||
if (jsxUtil.isJSX(node)) {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
function report(node, depth) {
|
||||
reportC(context, messages.wrongDepth, 'wrongDepth', {
|
||||
node,
|
||||
data: {
|
||||
found: depth,
|
||||
needed: maxDepth,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function findJSXElementOrFragment(startNode, name, previousReferences) {
|
||||
function find(refs, prevRefs) {
|
||||
for (let i = refs.length - 1; i >= 0; i--) {
|
||||
if (typeof refs[i].writeExpr !== 'undefined') {
|
||||
const writeExpr = refs[i].writeExpr;
|
||||
|
||||
return (jsxUtil.isJSX(writeExpr)
|
||||
&& writeExpr)
|
||||
|| ((writeExpr && writeExpr.type === 'Identifier')
|
||||
&& findJSXElementOrFragment(startNode, writeExpr.name, prevRefs));
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
const variable = variableUtil.getVariableFromContext(context, startNode, name);
|
||||
if (variable && variable.references) {
|
||||
const containDuplicates = previousReferences.some((ref) => includes(variable.references, ref));
|
||||
|
||||
// Prevent getting stuck in circular references
|
||||
if (containDuplicates) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return find(variable.references, previousReferences.concat(variable.references));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function checkDescendant(baseDepth, children) {
|
||||
baseDepth += 1;
|
||||
(children || []).filter((node) => hasJSX(node)).forEach((node) => {
|
||||
if (baseDepth > maxDepth) {
|
||||
report(node, baseDepth);
|
||||
} else if (!isLeaf(node)) {
|
||||
checkDescendant(baseDepth, node.children);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handleJSX(node) {
|
||||
if (!isLeaf(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const depth = getDepth(node);
|
||||
if (depth > maxDepth) {
|
||||
report(node, depth);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
JSXElement: handleJSX,
|
||||
JSXFragment: handleJSX,
|
||||
|
||||
JSXExpressionContainer(node) {
|
||||
if (node.expression.type !== 'Identifier') {
|
||||
return;
|
||||
}
|
||||
|
||||
const element = findJSXElementOrFragment(node, node.expression.name, []);
|
||||
|
||||
if (element) {
|
||||
const baseDepth = getDepth(node);
|
||||
checkDescendant(baseDepth, element.children);
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-max-props-per-line.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-max-props-per-line.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=jsx-max-props-per-line.d.ts.map
|
||||
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-max-props-per-line.d.ts.map
generated
vendored
Normal file
1
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-max-props-per-line.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"jsx-max-props-per-line.d.ts","sourceRoot":"","sources":["jsx-max-props-per-line.js"],"names":[],"mappings":"wBA0BW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU"}
|
||||
155
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-max-props-per-line.js
generated
vendored
Normal file
155
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-max-props-per-line.js
generated
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
* @fileoverview Limit maximum of props on a single line in JSX
|
||||
* @author Yannick Croissant
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const docsUrl = require('../util/docsUrl');
|
||||
const getText = require('../util/eslint').getText;
|
||||
const report = require('../util/report');
|
||||
|
||||
function getPropName(context, propNode) {
|
||||
if (propNode.type === 'JSXSpreadAttribute') {
|
||||
return getText(context, propNode.argument);
|
||||
}
|
||||
return propNode.name.name;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
const messages = {
|
||||
newLine: 'Prop `{{prop}}` must be placed on a new line',
|
||||
};
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'Enforce maximum of props on a single line in JSX',
|
||||
category: 'Stylistic Issues',
|
||||
recommended: false,
|
||||
url: docsUrl('jsx-max-props-per-line'),
|
||||
},
|
||||
fixable: 'code',
|
||||
|
||||
messages,
|
||||
|
||||
schema: [{
|
||||
anyOf: [{
|
||||
type: 'object',
|
||||
properties: {
|
||||
maximum: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
single: {
|
||||
type: 'integer',
|
||||
minimum: 1,
|
||||
},
|
||||
multi: {
|
||||
type: 'integer',
|
||||
minimum: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
maximum: {
|
||||
type: 'number',
|
||||
minimum: 1,
|
||||
},
|
||||
when: {
|
||||
type: 'string',
|
||||
enum: ['always', 'multiline'],
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
}],
|
||||
}],
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const configuration = context.options[0] || {};
|
||||
const maximum = configuration.maximum || 1;
|
||||
|
||||
const maxConfig = typeof maximum === 'number'
|
||||
? {
|
||||
single: configuration.when === 'multiline' ? Infinity : maximum,
|
||||
multi: maximum,
|
||||
}
|
||||
: {
|
||||
single: maximum.single || Infinity,
|
||||
multi: maximum.multi || Infinity,
|
||||
};
|
||||
|
||||
function generateFixFunction(line, max) {
|
||||
const output = [];
|
||||
const front = line[0].range[0];
|
||||
const back = line[line.length - 1].range[1];
|
||||
|
||||
for (let i = 0; i < line.length; i += max) {
|
||||
const nodes = line.slice(i, i + max);
|
||||
output.push(nodes.reduce((prev, curr) => {
|
||||
if (prev === '') {
|
||||
return getText(context, curr);
|
||||
}
|
||||
return `${prev} ${getText(context, curr)}`;
|
||||
}, ''));
|
||||
}
|
||||
|
||||
const code = output.join('\n');
|
||||
|
||||
return function fix(fixer) {
|
||||
return fixer.replaceTextRange([front, back], code);
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
JSXOpeningElement(node) {
|
||||
if (!node.attributes.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isSingleLineTag = node.loc.start.line === node.loc.end.line;
|
||||
|
||||
if ((isSingleLineTag ? maxConfig.single : maxConfig.multi) === Infinity) {
|
||||
return;
|
||||
}
|
||||
|
||||
const firstProp = node.attributes[0];
|
||||
const linePartitionedProps = [[firstProp]];
|
||||
|
||||
node.attributes.reduce((last, decl) => {
|
||||
if (last.loc.end.line === decl.loc.start.line) {
|
||||
linePartitionedProps[linePartitionedProps.length - 1].push(decl);
|
||||
} else {
|
||||
linePartitionedProps.push([decl]);
|
||||
}
|
||||
return decl;
|
||||
});
|
||||
|
||||
linePartitionedProps.forEach((propsInLine) => {
|
||||
const maxPropsCountPerLine = isSingleLineTag && propsInLine[0].loc.start.line === node.loc.start.line
|
||||
? maxConfig.single
|
||||
: maxConfig.multi;
|
||||
|
||||
if (propsInLine.length > maxPropsCountPerLine) {
|
||||
const name = getPropName(context, propsInLine[maxPropsCountPerLine]);
|
||||
report(context, messages.newLine, 'newLine', {
|
||||
node: propsInLine[maxPropsCountPerLine],
|
||||
data: {
|
||||
prop: name,
|
||||
},
|
||||
fix: generateFixFunction(propsInLine, maxPropsCountPerLine),
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-newline.d.ts
generated
vendored
Normal file
3
Lab/node_modules/eslint-plugin-react/lib/rules/jsx-newline.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const _exports: import('eslint').Rule.RuleModule;
|
||||
export = _exports;
|
||||
//# sourceMappingURL=jsx-newline.d.ts.map
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user