astro-ghostcms/.pnpm-store/v3/files/a9/cee6704a4bf5f3b0d43e63be7ef...

173 lines
8.3 KiB
Plaintext

"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("@typescript-eslint/utils");
const ts = __importStar(require("typescript"));
const util_1 = require("../util");
const analyzeChain_1 = require("./prefer-optional-chain-utils/analyzeChain");
const gatherLogicalOperands_1 = require("./prefer-optional-chain-utils/gatherLogicalOperands");
exports.default = (0, util_1.createRule)({
name: 'prefer-optional-chain',
meta: {
type: 'suggestion',
docs: {
description: 'Enforce using concise optional chain expressions instead of chained logical ands, negated logical ors, or empty objects',
recommended: 'stylistic',
requiresTypeChecking: true,
},
fixable: 'code',
hasSuggestions: true,
messages: {
preferOptionalChain: "Prefer using an optional chain expression instead, as it's more concise and easier to read.",
optionalChainSuggest: 'Change to an optional chain.',
},
schema: [
{
type: 'object',
additionalProperties: false,
properties: {
checkAny: {
type: 'boolean',
description: 'Check operands that are typed as `any` when inspecting "loose boolean" operands.',
},
checkUnknown: {
type: 'boolean',
description: 'Check operands that are typed as `unknown` when inspecting "loose boolean" operands.',
},
checkString: {
type: 'boolean',
description: 'Check operands that are typed as `string` when inspecting "loose boolean" operands.',
},
checkNumber: {
type: 'boolean',
description: 'Check operands that are typed as `number` when inspecting "loose boolean" operands.',
},
checkBoolean: {
type: 'boolean',
description: 'Check operands that are typed as `boolean` when inspecting "loose boolean" operands.',
},
checkBigInt: {
type: 'boolean',
description: 'Check operands that are typed as `bigint` when inspecting "loose boolean" operands.',
},
requireNullish: {
type: 'boolean',
description: 'Skip operands that are not typed with `null` and/or `undefined` when inspecting "loose boolean" operands.',
},
allowPotentiallyUnsafeFixesThatModifyTheReturnTypeIKnowWhatImDoing: {
type: 'boolean',
description: 'Allow autofixers that will change the return type of the expression. This option is considered unsafe as it may break the build.',
},
},
},
],
},
defaultOptions: [
{
checkAny: true,
checkUnknown: true,
checkString: true,
checkNumber: true,
checkBoolean: true,
checkBigInt: true,
requireNullish: false,
allowPotentiallyUnsafeFixesThatModifyTheReturnTypeIKnowWhatImDoing: false,
},
],
create(context, [options]) {
const parserServices = (0, util_1.getParserServices)(context);
const seenLogicals = new Set();
return {
// specific handling for `(foo ?? {}).bar` / `(foo || {}).bar`
'LogicalExpression[operator="||"], LogicalExpression[operator="??"]'(node) {
const leftNode = node.left;
const rightNode = node.right;
const parentNode = node.parent;
const isRightNodeAnEmptyObjectLiteral = rightNode.type === utils_1.AST_NODE_TYPES.ObjectExpression &&
rightNode.properties.length === 0;
if (!isRightNodeAnEmptyObjectLiteral ||
parentNode.type !== utils_1.AST_NODE_TYPES.MemberExpression ||
parentNode.optional) {
return;
}
seenLogicals.add(node);
function isLeftSideLowerPrecedence() {
const logicalTsNode = parserServices.esTreeNodeToTSNodeMap.get(node);
const leftTsNode = parserServices.esTreeNodeToTSNodeMap.get(leftNode);
const operator = ts.isBinaryExpression(logicalTsNode)
? logicalTsNode.operatorToken.kind
: ts.SyntaxKind.Unknown;
const leftPrecedence = (0, util_1.getOperatorPrecedence)(leftTsNode.kind, operator);
return leftPrecedence < util_1.OperatorPrecedence.LeftHandSide;
}
context.report({
node: parentNode,
messageId: 'preferOptionalChain',
suggest: [
{
messageId: 'optionalChainSuggest',
fix: (fixer) => {
const leftNodeText = context.sourceCode.getText(leftNode);
// Any node that is made of an operator with higher or equal precedence,
const maybeWrappedLeftNode = isLeftSideLowerPrecedence()
? `(${leftNodeText})`
: leftNodeText;
const propertyToBeOptionalText = context.sourceCode.getText(parentNode.property);
const maybeWrappedProperty = parentNode.computed
? `[${propertyToBeOptionalText}]`
: propertyToBeOptionalText;
return fixer.replaceTextRange(parentNode.range, `${maybeWrappedLeftNode}?.${maybeWrappedProperty}`);
},
},
],
});
},
'LogicalExpression[operator!="??"]'(node) {
if (seenLogicals.has(node)) {
return;
}
const { operands, newlySeenLogicals } = (0, gatherLogicalOperands_1.gatherLogicalOperands)(node, parserServices, options);
for (const logical of newlySeenLogicals) {
seenLogicals.add(logical);
}
let currentChain = [];
for (const operand of operands) {
if (operand.type === "Invalid" /* OperandValidity.Invalid */) {
(0, analyzeChain_1.analyzeChain)(context, parserServices, options, node.operator, currentChain);
currentChain = [];
}
else {
currentChain.push(operand);
}
}
// make sure to check whatever's left
if (currentChain.length > 0) {
(0, analyzeChain_1.analyzeChain)(context, parserServices, options, node.operator, currentChain);
}
},
};
},
});
//# sourceMappingURL=prefer-optional-chain.js.map