UNPKG

eslint-plugin-sonarjs

Version:
86 lines (85 loc) • 3.57 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.isTrustedJQueryBinding = isTrustedJQueryBinding; exports.isTrustedDocumentBinding = isTrustedDocumentBinding; const ast_js_1 = require("../../helpers/ast.js"); const helpers_js_1 = require("./helpers.js"); /** * Returns whether a `Variable`-def's declaration is an ambient, type-only * declaration (`declare const $: JQueryStatic;`). A plain uninitialized binding * (`let $;`) or a for-of/for-in binding also has a null `init`, so the TypeScript * `declare` flag - not a null init - is what actually distinguishes the two. */ function isAmbientDeclaration(def) { return def.parent?.declare === true; } function isTrustedJQueryBinding(scope, name, seen = new Set()) { if (seen.has(name)) { return false; } seen.add(name); const variable = (0, ast_js_1.getVariableFromScope)(scope, name); if (!variable?.defs.length) { return true; } return variable.defs.some(def => { if (def.type === 'ImportBinding') { return def.parent.type === 'ImportDeclaration' && def.parent.source.value === 'jquery'; } if (def.type !== 'Variable') { return false; } if (def.node.init == null) { return isAmbientDeclaration(def); } const init = (0, helpers_js_1.unwrapTypeAssertion)(def.node.init); return ((init.type === 'CallExpression' && (0, ast_js_1.isRequireModule)(init, 'jquery')) || // `const $ = jQuery;` aliasing an already-trusted jQuery binding ((0, ast_js_1.isIdentifier)(init, 'jQuery') && isTrustedJQueryBinding(scope, 'jQuery', seen))); }); } function isTrustedDocumentBinding(scope) { const variable = (0, ast_js_1.getVariableFromScope)(scope, 'document'); if (!variable?.defs.length) { return true; } const windowNotShadowed = !(0, ast_js_1.getVariableFromScope)(scope, 'window')?.defs.length; return variable.defs.some(def => { if (def.type !== 'Variable') { return false; } if (def.node.init == null) { return isAmbientDeclaration(def); } if (!windowNotShadowed) { return false; } const init = (0, helpers_js_1.unwrapTypeAssertion)(def.node.init); if (init.type === 'MemberExpression') { return (0, ast_js_1.isIdentifier)(init.object, 'window') && (0, ast_js_1.isIdentifier)(init.property, 'document'); } if (def.node.id.type === 'ObjectPattern' && (0, ast_js_1.isIdentifier)(init, 'window')) { // `const { document } = window;` return def.node.id.properties.some(property => property.type === 'Property' && !property.computed && (0, ast_js_1.isIdentifier)(property.key, 'document')); } return false; }); }