UNPKG

eslint-plugin-sonarjs

Version:
94 lines (93 loc) • 3.83 kB
"use strict"; /* * SonarQube JavaScript Plugin * Copyright (C) SonarSource Sàrl * mailto:info AT sonarsource DOT com * * You can redistribute and/or modify this program under the terms of * the Sonar Source-Available License Version 1, as published by SonarSource Sàrl. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the Sonar Source-Available License for more details. * * You should have received a copy of the Sonar Source-Available License * along with this program; if not, see https://sonarsource.com/license/ssal/ */ Object.defineProperty(exports, "__esModule", { value: true }); exports.getNearestFunctionScope = getNearestFunctionScope; exports.hasSingleWrite = hasSingleWrite; exports.isDescendantOrSameScope = isDescendantOrSameScope; exports.getUniqueWriteReferenceBefore = getUniqueWriteReferenceBefore; exports.unwrapTypeAssertion = unwrapTypeAssertion; const ast_js_1 = require("../../helpers/ast.js"); /** * Returns the nearest enclosing function, module, or global scope. */ function getNearestFunctionScope(scope) { let current = scope; while (current.type !== 'function' && current.type !== 'module' && current.type !== 'global') { if (!current.upper) { return current; } current = current.upper; } return current; } /** * Returns whether a variable is written exactly once in its entire lifetime * (e.g. a `const`, or a `let`/`var` that is never reassigned). Such a binding * has only one possible value once its write executes, so its value can be * trusted from a reader nested inside the write's function scope, as long as * the write also textually precedes the read. */ function hasSingleWrite(variable) { return variable.references.filter(reference => reference.isWrite()).length === 1; } /** * Returns whether `scope` is `ancestor` or is nested within it. */ function isDescendantOrSameScope(scope, ancestor) { let current = scope; while (current) { if (current === ancestor) { return true; } current = current.upper; } return false; } /** * Returns a variable's sole write reference before a given identifier use. * Unlike the generic `getUniqueWriteReference` in `helpers/ast.ts` (which finds * a variable's one and only write in its entire lifetime), this also accepts * a `node` to bound the search to writes preceding that specific use, which * this rule's cross-function scope check relies on. */ function getUniqueWriteReferenceBefore(variable, node) { const useStart = node.range?.[0]; const writeReferences = variable.references.filter(reference => { const writeEnd = reference.identifier.range?.[1]; return (reference.isWrite() && writeEnd !== undefined && useStart !== undefined && writeEnd <= useStart); }); return writeReferences.length === 1 ? writeReferences[0] : undefined; } /** * Unwraps TypeScript type assertions (delegating to the shared * `unwrapTypeScriptExpression`, which handles TSAsExpression, TSSatisfiesExpression, * TSTypeAssertion, and TSNonNullExpression) as well as ChainExpression (`x?.property`) * produced by optional chaining; unwrapping it returns the contained optional * MemberExpression (`x?.property`), not its object (`x`). The two kinds of wrapper * can nest in either order, so this alternates between them until neither applies. */ function unwrapTypeAssertion(node) { let current = (0, ast_js_1.unwrapTypeScriptExpression)(node); while (current.type === 'ChainExpression') { current = (0, ast_js_1.unwrapTypeScriptExpression)(current.expression); } return current; }