Files
NapCatQQ/.pnpm-store/v3/files/bf/f86a794c470bf2ed74a65e28f5a550c1f96ee6522a78b650e791a1ea4f45d9f0f3c37b17ce8ca740f13ca3319ce176976c2d3044b43c12b3ba0cdfc440edfd
TanTan e311ca3275
Build NapCat Artifacts / Windows Loader Test (push) Canceled after 0s
Build NapCat Artifacts / Type Check & Test (push) Canceled after 0s
Build NapCat Artifacts / Build NapCat.Framework (push) Canceled after 0s
Build NapCat Artifacts / Build NapCat.Shell (push) Canceled after 0s
docs: 仓库链接指向本镜像仓库
2026-11-13 09:25:58 +08:00

106 lines
3.2 KiB
Plaintext

/**
* @fileoverview Prevent usage of referential-type variables as default param in functional component
* @author Chang Yan
*/
'use strict';
const values = require('object.values');
const Components = require('../util/Components');
const docsUrl = require('../util/docsUrl');
const astUtil = require('../util/ast');
const report = require('../util/report');
const FORBIDDEN_TYPES_MAP = {
ArrowFunctionExpression: 'arrow function',
FunctionExpression: 'function expression',
ObjectExpression: 'object literal',
ArrayExpression: 'array literal',
ClassExpression: 'class expression',
NewExpression: 'construction expression',
JSXElement: 'JSX element',
};
const FORBIDDEN_TYPES = new Set(Object.keys(FORBIDDEN_TYPES_MAP));
const MESSAGE_ID = 'forbiddenTypeDefaultParam';
const messages = {
[MESSAGE_ID]: '{{propName}} has a/an {{forbiddenType}} as default prop. This could lead to potential infinite render loop in React. Use a variable reference instead of {{forbiddenType}}.',
};
function hasUsedObjectDestructuringSyntax(params) {
return (
params != null
&& params.length >= 1
&& params[0].type === 'ObjectPattern'
);
}
function verifyDefaultPropsDestructuring(context, properties) {
// Loop through each of the default params
properties.filter((prop) => prop.type === 'Property' && prop.value.type === 'AssignmentPattern').forEach((prop) => {
const propName = prop.key.name;
const propDefaultValue = prop.value;
const propDefaultValueType = propDefaultValue.right.type;
if (
propDefaultValueType === 'Literal'
&& propDefaultValue.right.regex != null
) {
report(context, messages[MESSAGE_ID], MESSAGE_ID, {
node: propDefaultValue,
data: {
propName,
forbiddenType: 'regex literal',
},
});
} else if (
astUtil.isCallExpression(propDefaultValue.right)
&& propDefaultValue.right.callee.type === 'Identifier'
&& propDefaultValue.right.callee.name === 'Symbol'
) {
report(context, messages[MESSAGE_ID], MESSAGE_ID, {
node: propDefaultValue,
data: {
propName,
forbiddenType: 'Symbol literal',
},
});
} else if (FORBIDDEN_TYPES.has(propDefaultValueType)) {
report(context, messages[MESSAGE_ID], MESSAGE_ID, {
node: propDefaultValue,
data: {
propName,
forbiddenType: FORBIDDEN_TYPES_MAP[propDefaultValueType],
},
});
}
});
}
/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
docs: {
description: 'Disallow usage of referential-type variables as default param in functional component',
category: 'Best Practices',
recommended: false,
url: docsUrl('no-object-type-as-default-prop'),
},
messages,
},
create: Components.detect((context, components) => ({
'Program:exit'() {
const list = components.list();
values(list)
.filter((component) => hasUsedObjectDestructuringSyntax(component.node.params))
.forEach((component) => {
const node = component.node;
const properties = node.params[0].properties;
verifyDefaultPropsDestructuring(context, properties);
});
},
})),
};