β¬ οΈ Back to Table of Contents
π prefer-destructuring¶
π Analysis Summary¶
| Metric | Count |
|---|---|
| π§ Functions | 8 |
| π¦ Imports | 10 |
| π Variables & Constants | 2 |
| π Type Aliases | 5 |
π Table of Contents¶
π οΈ File Location:¶
π packages/eslint-plugin/src/rules/prefer-destructuring.ts
π€ Default Export¶
| Property | Value |
|---|---|
name |
'prefer-destructuring' |
meta.type |
'suggestion' |
meta.docs.description |
'Require destructuring from arrays and/or objects' |
meta.docs.extendsBaseRule |
true |
meta.docs.frozen |
true |
meta.docs.requiresTypeChecking |
true |
meta.fixable |
baseRule.meta.fixable |
meta.hasSuggestions |
baseRule.meta.hasSuggestions |
meta.messages |
baseRule.meta.messages |
defaultOptions |
[ { AssignmentExpression: { array: true, object: true, }, VariableDeclarator: { array: true, object: true, }, }, {}, ] |
Entry point: create β documented under Functions.
π¦ Imports¶
| Name | Source |
|---|---|
TSESLint |
@typescript-eslint/utils |
TSESTree |
@typescript-eslint/utils |
JSONSchema4 |
@typescript-eslint/utils/json-schema |
AST_NODE_TYPES |
@typescript-eslint/utils |
InferMessageIdsTypeFromRule |
../util |
InferOptionsTypeFromRule |
../util |
createRule |
../util |
getParserServices |
../util |
isTypeAnyType |
../util |
getESLintCoreRule |
../util/getESLintCoreRule |
Variables & Constants¶
| Name | Type | Kind | Value | Exported |
|---|---|---|---|---|
destructuringTypeConfig |
JSONSchema4 |
const | { type: 'object', additionalProperties: false, properties: { array: { type: '... |
β |
schema |
readonly JSONSchema4[] |
const | [ { oneOf: [ { type: 'object', additionalProperties: false, properties: { Ass... |
β |
Functions¶
create(context: any, [enabledTypes, options]: any): { AssignmentExpression(node: any): void; VariableDeclarator⦶
Parameters:
contextany[enabledTypes, options]any
Returns: { AssignmentExpression(node: any): void; VariableDeclarator(node: any): void; }
Calls:
getParserServices (from ../util)program.getTypeCheckerbaseRule.createperformCheckbaseRulesWithoutFixisArrayLiteralIntegerIndexAccessesTreeNodeToTSNodeMap.gettypeChecker.getTypeAtLocationisTypeAnyOrIterableTypegetNormalizedEnabledTypecontext.reportrules.AssignmentExpressionrules.VariableDeclaratornoFixContext
Code
create(context, [enabledTypes, options]) {
const {
enforceForDeclarationWithTypeAnnotation = false,
enforceForRenamedProperties = false,
} = options;
const { esTreeNodeToTSNodeMap, program } = getParserServices(context);
const typeChecker = program.getTypeChecker();
const baseRules = baseRule.create(context);
let baseRulesWithoutFixCache: typeof baseRules | null = null;
return {
AssignmentExpression(node): void {
if (node.operator !== '=') {
return;
}
performCheck(node.left, node.right, node);
},
VariableDeclarator(node): void {
performCheck(node.id, node.init, node);
},
};
function performCheck(
leftNode: TSESTree.BindingName | TSESTree.Expression,
rightNode: TSESTree.Expression | null,
reportNode: TSESTree.AssignmentExpression | TSESTree.VariableDeclarator,
): void {
const rules =
leftNode.type === AST_NODE_TYPES.Identifier &&
leftNode.typeAnnotation == null
? baseRules
: baseRulesWithoutFix();
if (
(leftNode.type === AST_NODE_TYPES.ArrayPattern ||
leftNode.type === AST_NODE_TYPES.Identifier ||
leftNode.type === AST_NODE_TYPES.ObjectPattern) &&
leftNode.typeAnnotation != null &&
!enforceForDeclarationWithTypeAnnotation
) {
return;
}
if (
rightNode != null &&
isArrayLiteralIntegerIndexAccess(rightNode) &&
rightNode.object.type !== AST_NODE_TYPES.Super
) {
const tsObj = esTreeNodeToTSNodeMap.get(rightNode.object);
const objType = typeChecker.getTypeAtLocation(tsObj);
if (!isTypeAnyOrIterableType(objType, typeChecker)) {
if (
!enforceForRenamedProperties ||
!getNormalizedEnabledType(reportNode.type, 'object')
) {
return;
}
context.report({
node: reportNode,
messageId: 'preferDestructuring',
data: { type: 'object' },
});
return;
}
}
if (reportNode.type === AST_NODE_TYPES.AssignmentExpression) {
rules.AssignmentExpression(reportNode);
} else {
rules.VariableDeclarator(reportNode);
}
}
function getNormalizedEnabledType(
nodeType:
AST_NODE_TYPES.AssignmentExpression | AST_NODE_TYPES.VariableDeclarator,
destructuringType: 'array' | 'object',
): boolean | undefined {
if ('object' in enabledTypes || 'array' in enabledTypes) {
return enabledTypes[destructuringType];
}
return enabledTypes[nodeType as keyof typeof enabledTypes][
destructuringType as keyof (typeof enabledTypes)[keyof typeof enabledTypes]
];
}
function baseRulesWithoutFix(): ReturnType<typeof baseRule.create> {
baseRulesWithoutFixCache ??= baseRule.create(noFixContext(context));
return baseRulesWithoutFixCache;
}
}
noFixContext(context: Context): Context¶
Parameters:
contextContext
Returns: Context
Calls:
context.reportReflect.get
Internal Comments:
// we can't directly proxy `context` because its `report` property is non-configurable
// and non-writable. So we proxy `customContext` and redirect all
// property access to the original context except for `report`
Code
function noFixContext(context: Context): Context {
const customContext: {
report: Context['report'];
} = {
report: (descriptor): void => {
context.report({
...descriptor,
fix: undefined,
});
},
};
// we can't directly proxy `context` because its `report` property is non-configurable
// and non-writable. So we proxy `customContext` and redirect all
// property access to the original context except for `report`
return new Proxy(customContext as typeof context, {
get(target, path, receiver): unknown {
if (path !== 'report') {
return Reflect.get(context, path, receiver);
}
return Reflect.get(target, path, receiver);
},
});
}
isTypeAnyOrIterableType(type: ts.Type, typeChecker: ts.TypeChecker): boolean¶
Parameters:
typets.TypetypeCheckerts.TypeChecker
Returns: boolean
Calls:
isTypeAnyType (from ../util)type.isUniontsutils.getWellKnownSymbolPropertyOfTypetype.types.everyisTypeAnyOrIterableType
Code
function isTypeAnyOrIterableType(
type: ts.Type,
typeChecker: ts.TypeChecker,
): boolean {
if (isTypeAnyType(type)) {
return true;
}
if (!type.isUnion()) {
const iterator = tsutils.getWellKnownSymbolPropertyOfType(
type,
'iterator',
typeChecker,
);
return iterator != null;
}
return type.types.every(t => isTypeAnyOrIterableType(t, typeChecker));
}
isArrayLiteralIntegerIndexAccess(node: TSESTree.Expression): node is TSESTree.MemberExpression¶
Parameters:
nodeTSESTree.Expression
Returns: node is TSESTree.MemberExpression
Calls:
Number.isInteger
Code
Internal helpers¶
Declared inside another function in this file.
performCheck(leftNode: TSESTree.BindingName | TSESTree.Expressβ¦, rightNode: TSESTree.Expression | null, reportNode: TSESTree.AssignmentExpression | TSESTreβ¦): void¶
Parameters:
leftNodeTSESTree.BindingName | TSESTree.ExpressionrightNodeTSESTree.Expression | nullreportNodeTSESTree.AssignmentExpression | TSESTree.VariableDeclarator
Returns: void
Calls:
baseRulesWithoutFixisArrayLiteralIntegerIndexAccessesTreeNodeToTSNodeMap.gettypeChecker.getTypeAtLocationisTypeAnyOrIterableTypegetNormalizedEnabledTypecontext.reportrules.AssignmentExpressionrules.VariableDeclarator
Code
function performCheck(
leftNode: TSESTree.BindingName | TSESTree.Expression,
rightNode: TSESTree.Expression | null,
reportNode: TSESTree.AssignmentExpression | TSESTree.VariableDeclarator,
): void {
const rules =
leftNode.type === AST_NODE_TYPES.Identifier &&
leftNode.typeAnnotation == null
? baseRules
: baseRulesWithoutFix();
if (
(leftNode.type === AST_NODE_TYPES.ArrayPattern ||
leftNode.type === AST_NODE_TYPES.Identifier ||
leftNode.type === AST_NODE_TYPES.ObjectPattern) &&
leftNode.typeAnnotation != null &&
!enforceForDeclarationWithTypeAnnotation
) {
return;
}
if (
rightNode != null &&
isArrayLiteralIntegerIndexAccess(rightNode) &&
rightNode.object.type !== AST_NODE_TYPES.Super
) {
const tsObj = esTreeNodeToTSNodeMap.get(rightNode.object);
const objType = typeChecker.getTypeAtLocation(tsObj);
if (!isTypeAnyOrIterableType(objType, typeChecker)) {
if (
!enforceForRenamedProperties ||
!getNormalizedEnabledType(reportNode.type, 'object')
) {
return;
}
context.report({
node: reportNode,
messageId: 'preferDestructuring',
data: { type: 'object' },
});
return;
}
}
if (reportNode.type === AST_NODE_TYPES.AssignmentExpression) {
rules.AssignmentExpression(reportNode);
} else {
rules.VariableDeclarator(reportNode);
}
}
getNormalizedEnabledType(nodeType: AST_NODE_TYPES.AssignmentExpression | Aβ¦, destructuringType: 'array' | 'object'): boolean | undefined¶
Parameters:
nodeTypeAST_NODE_TYPES.AssignmentExpression | AST_NODE_TYPES.VariableDeclaratordestructuringType'array' | 'object'
Returns: boolean | undefined
Code
function getNormalizedEnabledType(
nodeType:
AST_NODE_TYPES.AssignmentExpression | AST_NODE_TYPES.VariableDeclarator,
destructuringType: 'array' | 'object',
): boolean | undefined {
if ('object' in enabledTypes || 'array' in enabledTypes) {
return enabledTypes[destructuringType];
}
return enabledTypes[nodeType as keyof typeof enabledTypes][
destructuringType as keyof (typeof enabledTypes)[keyof typeof enabledTypes]
];
}
baseRulesWithoutFix(): ReturnType<typeof baseRule.create>¶
Returns: ReturnType<typeof baseRule.create>
Calls:
baseRule.createnoFixContext
Code
report(descriptor: any): void¶
Parameters:
descriptorany
Returns: void
Calls:
context.report
Type Aliases¶
BaseOptions¶
EnforcementOptions¶
Options¶
MessageIds¶
Context¶
Generated by Syntax Scribe