'use strict'; var useAtYourOwnRisk = require('eslint/use-at-your-own-risk'); var jsxAstUtils = require('jsx-ast-utils'); var getElementType = require('eslint-plugin-jsx-a11y/lib/util/getElementType.js'); var ts = require('typescript'); var fs = require('fs'); var path = require('path'); require('minimatch'); var jsxA11y = require('eslint-plugin-jsx-a11y'); var regexpp = require('@eslint-community/regexpp'); var createTree = require('functional-red-black-tree'); var locations = require('eslint-plugin-sonarjs/lib/src/utils/locations.js'); var sonarjs = require('eslint-plugin-sonarjs'); var eslint = require('eslint'); var tsEslint = require('@typescript-eslint/eslint-plugin'); var react = require('eslint-plugin-react'); var bytes = require('bytes'); var equivalence = require('eslint-plugin-sonarjs/lib/src/utils/equivalence.js'); var url = require('url'); var babelESLintParser = require('@babel/eslint-parser'); var tmp = require('tmp'); var semver = require('semver'); var net = require('net'); var builtins = require('builtin-modules'); var utils = require('@typescript-eslint/utils'); var isHiddenFromScreenReader = require('eslint-plugin-jsx-a11y/lib/util/isHiddenFromScreenReader.js'); var nodes = require('eslint-plugin-sonarjs/lib/src/utils/nodes.js'); var reactHooks = require('eslint-plugin-react-hooks'); var scslre = require('scslre'); function _interopNamespaceDefault(e) { var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n.default = e; return Object.freeze(n); } var ts__namespace = /*#__PURE__*/_interopNamespaceDefault(ts); var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs); var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path); var regexpp__namespace = /*#__PURE__*/_interopNamespaceDefault(regexpp); var babelESLintParser__namespace = /*#__PURE__*/_interopNamespaceDefault(babelESLintParser); var semver__namespace = /*#__PURE__*/_interopNamespaceDefault(semver); var name = "eslint-plugin-sonar"; var version = "0.14.1"; const eslintRules = Object.fromEntries(useAtYourOwnRisk.builtinRules); function isPresentationTable(context, node) { const DISALLOWED_VALUES = ['presentation', 'none']; const type = getElementType(context)(node); if (type.toLowerCase() !== 'table') { return false; } const role = jsxAstUtils.getProp(node.attributes, 'role'); if (!role) { return false; } const roleValue = String(jsxAstUtils.getLiteralPropValue(role)); return DISALLOWED_VALUES.includes(roleValue === null || roleValue === void 0 ? void 0 : roleValue.toLowerCase()); } const FUNCTION_NODES = [ 'FunctionDeclaration', 'FunctionExpression', 'ArrowFunctionExpression', ]; const functionLike$1 = new Set([ 'FunctionDeclaration', 'FunctionExpression', 'ArrowFunctionExpression', 'MethodDefinition', ]); function isIdentifier(node, ...values) { return ((node === null || node === void 0 ? void 0 : node.type) === 'Identifier' && (values.length === 0 || values.some(value => value === node.name))); } function isMemberWithProperty$1(node, ...values) { return node.type === 'MemberExpression' && isIdentifier(node.property, ...values); } function isMemberExpression(node, objectValue, ...propertyValue) { if (node.type === 'MemberExpression') { const { object, property } = node; if (isIdentifier(object, objectValue) && isIdentifier(property, ...propertyValue)) { return true; } } return false; } function isBinaryPlus(node) { return node.type === 'BinaryExpression' && node.operator === '+'; } function isArrayExpression(node) { return node !== undefined && node.type === 'ArrayExpression'; } function isRequireModule(node, ...moduleNames) { if (isIdentifier(node.callee, 'require') && node.arguments.length === 1) { const argument = node.arguments[0]; if (argument.type === 'Literal') { return moduleNames.includes(String(argument.value)); } } return false; } function isMethodInvocation(callExpression, objectIdentifierName, methodName, minArgs) { return (callExpression.callee.type === 'MemberExpression' && isIdentifier(callExpression.callee.object, objectIdentifierName) && isIdentifier(callExpression.callee.property, methodName) && callExpression.callee.property.type === 'Identifier' && callExpression.arguments.length >= minArgs); } function isFunctionCall(node) { return node.type === 'CallExpression' && node.callee.type === 'Identifier'; } function isMethodCall(callExpr) { return (callExpr.callee.type === 'MemberExpression' && !callExpr.callee.computed && callExpr.callee.property.type === 'Identifier'); } function isCallingMethod(callExpr, arity, ...methodNames) { return (isMethodCall(callExpr) && callExpr.arguments.length === arity && methodNames.includes(callExpr.callee.property.name)); } function isModuleExports(node) { return (node.type === 'MemberExpression' && node.object.type === 'Identifier' && node.object.name === 'module' && node.property.type === 'Identifier' && node.property.name === 'exports'); } function isFunctionNode(node) { return FUNCTION_NODES.includes(node.type); } function isLiteral$2(n) { return n != null && n.type === 'Literal'; } function isNullLiteral(n) { return isLiteral$2(n) && n.value === null; } function isFalseLiteral(n) { return isLiteral$2(n) && n.value === false; } function isUndefined(node) { return node.type === 'Identifier' && node.name === 'undefined'; } function isElementWrite(statement, ref) { if (statement.expression.type === 'AssignmentExpression') { const assignmentExpression = statement.expression; const lhs = assignmentExpression.left; return isMemberExpressionReference(lhs, ref); } return false; } function isMemberExpressionReference(lhs, ref) { return (lhs.type === 'MemberExpression' && (isReferenceTo(ref, lhs.object) || isMemberExpressionReference(lhs.object, ref))); } function isReferenceTo(ref, node) { return node.type === 'Identifier' && node === ref.identifier; } function getUniqueWriteUsage(context, name, node) { const variable = getVariableFromName(context, name, node); return getUniqueWriteReference(variable); } function getUniqueWriteReference(variable) { if (variable) { const writeReferences = variable.references.filter(reference => reference.isWrite()); if (writeReferences.length === 1 && writeReferences[0].writeExpr) { return writeReferences[0].writeExpr; } } return undefined; } function getUniqueWriteUsageOrNode(context, node, recursive = false) { if (node.type === 'Identifier') { const usage = getUniqueWriteUsage(context, node.name, node); if (usage) { return recursive ? getUniqueWriteUsageOrNode(context, usage, recursive) : usage; } else { return node; } } else { return node; } } function getValueOfExpression(context, expr, type, recursive = false) { if (!expr) { return undefined; } if (isNodeType(expr, type)) { return expr; } if (expr.type === 'Identifier') { const usage = getUniqueWriteUsage(context, expr.name, expr); if (usage) { if (isNodeType(usage, type)) { return usage; } if (recursive) { return getValueOfExpression(context, usage, type, true); } } } return undefined; } function isNodeType(node, type) { return node.type === type; } function getLhsVariable(context, node) { const ancestors = context.sourceCode.getAncestors(node); const parent = ancestors[ancestors.length - 1]; let formIdentifier; if (parent.type === 'VariableDeclarator' && parent.id.type === 'Identifier') { formIdentifier = parent.id; } else if (parent.type === 'AssignmentExpression' && parent.left.type === 'Identifier') { formIdentifier = parent.left; } if (formIdentifier) { return getVariableFromName(context, formIdentifier.name, node); } return undefined; } function getVariableFromScope(scope, name) { let variable; while (variable == null && scope != null) { variable = scope.variables.find(value => value.name === name); scope = scope.upper; } return variable; } function getVariableFromName(context, name, node) { const scope = context.sourceCode.getScope(node); return getVariableFromScope(scope, name); } function flattenArgs(context, args) { function recHelper(nodePossiblyIdentifier) { const n = getUniqueWriteUsageOrNode(context, nodePossiblyIdentifier); if (n.type === 'ArrayExpression') { return flatMap(n.elements, recHelper); } else { return [n]; } } return flatMap(args, recHelper); } function resolveIdentifiers(node, acceptShorthand = false) { const identifiers = []; resolveIdentifiersAcc(node, identifiers, acceptShorthand); return identifiers; } function resolveIdentifiersAcc(node, identifiers, acceptShorthand) { if (!node) { return; } switch (node.type) { case 'Identifier': identifiers.push(node); break; case 'ObjectPattern': node.properties.forEach(prop => resolveIdentifiersAcc(prop, identifiers, acceptShorthand)); break; case 'ArrayPattern': node.elements.forEach(elem => elem && resolveIdentifiersAcc(elem, identifiers, acceptShorthand)); break; case 'Property': if (acceptShorthand || !node.shorthand) { resolveIdentifiersAcc(node.value, identifiers, acceptShorthand); } break; case 'RestElement': resolveIdentifiersAcc(node.argument, identifiers, acceptShorthand); break; case 'AssignmentPattern': resolveIdentifiersAcc(node.left, identifiers, acceptShorthand); break; case 'TSParameterProperty': resolveIdentifiersAcc(node.parameter, identifiers, acceptShorthand); break; } } function getPropertyWithValue(context, objectExpression, propertyName, propertyValue) { const maybeProperty = getProperty$1(objectExpression, propertyName, context); if (maybeProperty) { const maybePropertyValue = getValueOfExpression(context, maybeProperty.value, 'Literal'); if ((maybePropertyValue === null || maybePropertyValue === void 0 ? void 0 : maybePropertyValue.value) === propertyValue) { return maybeProperty; } } return undefined; } function getPropertyFromSpreadElement(spreadElement, key, ctx) { const props = getValueOfExpression(ctx, spreadElement.argument, 'ObjectExpression'); const recursiveDefinition = findFirstMatchingAncestor(spreadElement.argument, node => node === props); if (recursiveDefinition || props === undefined) { return undefined; } return getProperty$1(props, key, ctx); } function getProperty$1(expr, key, ctx) { if ((expr === null || expr === void 0 ? void 0 : expr.type) !== 'ObjectExpression') { return null; } let unresolvedSpreadElement = false; for (let i = expr.properties.length - 1; i >= 0; --i) { const property = expr.properties[i]; if (isProperty(property, key)) { return property; } if (property.type === 'SpreadElement') { const prop = getPropertyFromSpreadElement(property, key, ctx); if (prop === undefined) { unresolvedSpreadElement = true; } else if (prop !== null) { return prop; } } } if (unresolvedSpreadElement) { return undefined; } return null; function isProperty(node, key) { return (node.type === 'Property' && (isIdentifier(node.key, key) || (isStringLiteral(node.key) && node.key.value === key))); } } function resolveFromFunctionReference(context, functionIdentifier) { const { scopeManager } = context.sourceCode; for (const scope of scopeManager.scopes) { const reference = scope.references.find(r => r.identifier === functionIdentifier); if ((reference === null || reference === void 0 ? void 0 : reference.resolved) && reference.resolved.defs.length === 1 && reference.resolved.defs[0].type === 'FunctionName') { return reference.resolved.defs[0].node; } } return null; } function resolveFunction(context, node) { if (isFunctionNode(node)) { return node; } else if (node.type === 'Identifier') { return resolveFromFunctionReference(context, node); } else { return null; } } function checkSensitiveCall(context, callExpression, sensitiveArgumentIndex, sensitiveProperty, sensitivePropertyValue, message) { if (callExpression.arguments.length < sensitiveArgumentIndex + 1) { return; } const sensitiveArgument = callExpression.arguments[sensitiveArgumentIndex]; const options = getValueOfExpression(context, sensitiveArgument, 'ObjectExpression'); if (!options) { return; } const unsafeProperty = getPropertyWithValue(context, options, sensitiveProperty, sensitivePropertyValue); if (unsafeProperty) { context.report({ node: callExpression.callee, message: toEncodedMessage$1(message, [unsafeProperty]), }); } } function isStringLiteral(node) { return isLiteral$2(node) && typeof node.value === 'string'; } function isBooleanLiteral(node) { return isLiteral$2(node) && typeof node.value === 'boolean'; } function isNumberLiteral(node) { return isLiteral$2(node) && typeof node.value === 'number'; } function isRegexLiteral(node) { return node.type === 'Literal' && node.value instanceof RegExp; } function isDotNotation(node) { return node.type === 'MemberExpression' && !node.computed && node.property.type === 'Identifier'; } function isIndexNotation(node) { return node.type === 'MemberExpression' && node.computed && isStringLiteral(node.property); } function isObjectDestructuring(node) { return ((node.type === 'VariableDeclarator' && node.id.type === 'ObjectPattern') || (node.type === 'AssignmentExpression' && node.left.type === 'ObjectPattern')); } function isStaticTemplateLiteral(node) { return (node.type === 'TemplateLiteral' && node.expressions.length === 0 && node.quasis.length === 1); } function isSimpleRawString(node) { return (node.type === 'TaggedTemplateExpression' && isDotNotation(node.tag) && isIdentifier(node.tag.object, 'String') && isIdentifier(node.tag.property, 'raw') && isStaticTemplateLiteral(node.quasi)); } function getSimpleRawStringValue(node) { return node.quasi.quasis[0].value.raw; } function isThisExpression(node) { return node.type === 'ThisExpression'; } function isProperty(node) { return node.type === 'Property'; } function isUnresolved(node, ctx) { if (!node || getFullyQualifiedName(ctx, node) || isUndefined(node)) { return false; } let nodeToCheck = node; while (nodeToCheck.type === 'MemberExpression') { nodeToCheck = nodeToCheck.object; } if (nodeToCheck.type === 'Identifier') { const variable = getVariableFromName(ctx, nodeToCheck.name, node); const writeReferences = variable === null || variable === void 0 ? void 0 : variable.references.filter(reference => reference.isWrite()); if (!variable || !(writeReferences === null || writeReferences === void 0 ? void 0 : writeReferences.length)) { return true; } } return false; } function findFirstMatchingLocalAncestor(node, predicate) { return localAncestorsChain(node).find(predicate); } function findFirstMatchingAncestor(node, predicate) { return ancestorsChain(node, new Set()).find(predicate); } function localAncestorsChain(node) { return ancestorsChain(node, functionLike$1); } function ancestorsChain(node, boundaryTypes) { const chain = []; let currentNode = node.parent; while (currentNode) { chain.push(currentNode); if (boundaryTypes.has(currentNode.type)) { break; } currentNode = currentNode.parent; } return chain; } function getParent(context, node) { const ancestors = context.sourceCode.getAncestors(node); return ancestors.length > 0 ? ancestors[ancestors.length - 1] : undefined; } function getNodeParent(node) { return node.parent; } var Chai; (function (Chai) { function isImported(context) { return (getRequireCalls(context).some(r => r.arguments[0].type === 'Literal' && r.arguments[0].value === 'chai') || getImportDeclarations(context).some(i => i.source.value === 'chai')); } Chai.isImported = isImported; function isAssertion(context, node) { return isAssertUsage(context, node) || isExpectUsage(context, node) || isShouldUsage(node); } Chai.isAssertion = isAssertion; function isAssertUsage(context, node) { const fqn = extractFQNforCallExpression(context, node); if (!fqn) { return false; } const names = fqn.split('.'); return names[0] === 'chai' && names[1] === 'assert'; } function isExpectUsage(context, node) { return extractFQNforCallExpression(context, node) === 'chai.expect'; } function isShouldUsage(node) { return node.type === 'MemberExpression' && isIdentifier(node.property, 'should'); } function extractFQNforCallExpression(context, node) { if (node.type !== 'CallExpression') { return undefined; } return getFullyQualifiedName(context, node); } })(Chai || (Chai = {})); const sortLike = ['sort', '"sort"', "'sort'"]; const copyingSortLike = ['toSorted', '"toSorted"', "'toSorted'"]; function flatMap(xs, f) { const acc = []; for (const x of xs) { acc.push(...f(x)); } return acc; } function last(arr) { return arr[arr.length - 1]; } const NUM_ARGS_NODE_MESSAGE = 2; function interceptReport(rule, onReport, contextOverrider) { return { ...(!!rule.meta && { meta: rule.meta }), create(originalContext) { let interceptingContext; if (contextOverrider == null) { interceptingContext = { id: originalContext.id, options: originalContext.options, settings: originalContext.settings, parserPath: originalContext.parserPath, parserOptions: originalContext.parserOptions, parserServices: originalContext.sourceCode.parserServices, sourceCode: originalContext.sourceCode, cwd: originalContext.cwd, filename: originalContext.filename, physicalFilename: originalContext.physicalFilename, languageOptions: originalContext.languageOptions, getCwd() { return originalContext.cwd; }, getPhysicalFilename() { return originalContext.physicalFilename; }, getAncestors() { return originalContext.getAncestors(); }, getDeclaredVariables(node) { return originalContext.getDeclaredVariables(node); }, getFilename() { return originalContext.filename; }, getScope() { return originalContext.getScope(); }, getSourceCode() { return originalContext.sourceCode; }, markVariableAsUsed(name) { return originalContext.markVariableAsUsed(name); }, report(...args) { let descr = undefined; if (args.length === 1) { descr = args[0]; } else if (args.length === NUM_ARGS_NODE_MESSAGE && typeof args[1] === 'string') { descr = { node: args[0], message: args[1], }; } if (descr) { onReport(originalContext, descr); } }, }; } else { interceptingContext = contextOverrider(originalContext, onReport); } return rule.create(interceptingContext); }, }; } function interceptReportForReact(rule, onReport) { return interceptReport(rule, onReport, contextOverriderForReact); } function contextOverriderForReact(context, onReport) { const overriddenReportContext = { report(reportDescriptor) { onReport(context, reportDescriptor); }, }; Object.setPrototypeOf(overriddenReportContext, context); return overriddenReportContext; } function mergeRules(...rules) { const merged = Object.assign({}, ...rules); for (const listener of Object.keys(merged)) { merged[listener] = mergeListeners(...rules.map(rule => rule[listener])); } return merged; } function mergeListeners(...listeners) { return (...args) => { for (const listener of listeners) { if (listener) { listener(...args); } } }; } function toUnixPath(path) { return path.replace(/[\\/]+/g, '/'); } var ErrorCode; (function (ErrorCode) { ErrorCode["Parsing"] = "PARSING"; ErrorCode["FailingTypeScript"] = "FAILING_TYPESCRIPT"; ErrorCode["Unexpected"] = "GENERAL_ERROR"; ErrorCode["LinterInitialization"] = "LINTER_INITIALIZATION"; })(ErrorCode || (ErrorCode = {})); const SONAR_RUNTIME = 'sonar-runtime'; var Express; (function (Express) { const EXPRESS = 'express'; function attemptFindAppInstantiation(varDecl, context) { const rhs = varDecl.init; if (rhs && rhs.type === 'CallExpression' && getFullyQualifiedName(context, rhs) === EXPRESS) { const pattern = varDecl.id; return pattern.type === 'Identifier' ? pattern : undefined; } return undefined; } Express.attemptFindAppInstantiation = attemptFindAppInstantiation; function attemptFindAppInjection(functionDef, context, node) { const app = functionDef.params.find(param => param.type === 'Identifier' && param.name === 'app'); if (app) { const parent = getParent(context, node); if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'AssignmentExpression') { const { left } = parent; if (left.type === 'MemberExpression' && (isModuleExports(left) || isModuleExports(left.object))) { return app; } } } return undefined; } Express.attemptFindAppInjection = attemptFindAppInjection; function isUsingMiddleware(context, callExpression, app, middlewareNodePredicate) { if (isMethodInvocation(callExpression, app.name, 'use', 1)) { const flattenedArgs = flattenArgs(context, callExpression.arguments); return Boolean(flattenedArgs.find(middlewareNodePredicate)); } return false; } Express.isUsingMiddleware = isUsingMiddleware; function isMiddlewareInstance(context, middlewares, n) { if (n.type === 'CallExpression') { const fqn = getFullyQualifiedName(context, n); return middlewares.some(middleware => middleware === fqn); } return false; } Express.isMiddlewareInstance = isMiddlewareInstance; function SensitiveMiddlewarePropertyRule(sensitivePropertyFinder, message) { return { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { let app; let sensitiveProperties; function isExposing(middlewareNode) { return Boolean(sensitiveProperties.push(...findSensitiveProperty(middlewareNode))); } function findSensitiveProperty(middlewareNode) { if (middlewareNode.type === 'CallExpression') { return sensitivePropertyFinder(context, middlewareNode); } return []; } return { Program: () => { app = null; sensitiveProperties = []; }, CallExpression: (node) => { if (app) { const callExpr = node; const isSafe = !isUsingMiddleware(context, callExpr, app, isExposing); if (!isSafe) { for (const sensitive of sensitiveProperties) { context.report({ node: callExpr, message: toEncodedMessage$1(message, [sensitive]), }); } sensitiveProperties = []; } } }, VariableDeclarator: (node) => { if (!app) { const varDecl = node; const instantiatedApp = attemptFindAppInstantiation(varDecl, context); if (instantiatedApp) { app = instantiatedApp; } } }, ':function': (node) => { if (!app) { const functionDef = node; const injectedApp = attemptFindAppInjection(functionDef, context, node); if (injectedApp) { app = injectedApp; } } }, }; }, }; } Express.SensitiveMiddlewarePropertyRule = SensitiveMiddlewarePropertyRule; })(Express || (Express = {})); function isTestCode(context) { return getFileType(context) === 'TEST'; } function getFileType(context) { return context.settings['fileType']; } const globalsByLibraries = { builtin: [ 'Array', 'ArrayBuffer', 'Boolean', 'DataView', 'Date', 'Error', 'EvalError', 'Float32Array', 'Float64Array', 'Function', 'Infinity', 'Int16Array', 'Int32Array', 'Int8Array', 'JSON', 'Map', 'Math', 'NaN', 'Number', 'Object', 'Promise', 'Proxy', 'RangeError', 'ReferenceError', 'Reflect', 'RegExp', 'Set', 'String', 'Symbol', 'SyntaxError', 'TypeError', 'URIError', 'Uint16Array', 'Uint32Array', 'Uint8Array', 'Uint8ClampedArray', 'WeakMap', 'WeakSet', 'constructor', 'decodeURI', 'decodeURIComponent', 'encodeURI', 'encodeURIComponent', 'escape', 'eval', 'hasOwnProperty', 'isFinite', 'isNaN', 'isPrototypeOf', 'parseFloat', 'parseInt', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'unescape', 'valueOf', ], browser: [ 'addEventListener', 'alert', 'AnalyserNode', 'Animation', 'AnimationEffectReadOnly', 'AnimationEffectTiming', 'AnimationEffectTimingReadOnly', 'AnimationEvent', 'AnimationPlaybackEvent', 'AnimationTimeline', 'applicationCache', 'ApplicationCache', 'ApplicationCacheErrorEvent', 'atob', 'Attr', 'Audio', 'AudioBuffer', 'AudioBufferSourceNode', 'AudioContext', 'AudioDestinationNode', 'AudioListener', 'AudioNode', 'AudioParam', 'AudioProcessingEvent', 'AutocompleteErrorEvent', 'BarProp', 'BatteryManager', 'BeforeUnloadEvent', 'BiquadFilterNode', 'Blob', 'blur', 'btoa', 'Cache', 'caches', 'CacheStorage', 'cancelAnimationFrame', 'CanvasGradient', 'CanvasPattern', 'CanvasRenderingContext2D', 'CDATASection', 'ChannelMergerNode', 'ChannelSplitterNode', 'CharacterData', 'clearInterval', 'clearTimeout', 'clientInformation', 'ClientRect', 'ClientRectList', 'ClipboardEvent', 'close', 'closed', 'CloseEvent', 'Comment', 'CompositionEvent', 'confirm', 'console', 'ConvolverNode', 'Credential', 'CredentialsContainer', 'crypto', 'Crypto', 'CryptoKey', 'CSS', 'CSSAnimation', 'CSSFontFaceRule', 'CSSImportRule', 'CSSKeyframeRule', 'CSSKeyframesRule', 'CSSMediaRule', 'CSSPageRule', 'CSSRule', 'CSSRuleList', 'CSSStyleDeclaration', 'CSSStyleRule', 'CSSStyleSheet', 'CSSSupportsRule', 'CSSTransition', 'CSSUnknownRule', 'CSSViewportRule', 'customElements', 'CustomEvent', 'DataTransfer', 'DataTransferItem', 'DataTransferItemList', 'Debug', 'defaultStatus', 'defaultstatus', 'DelayNode', 'DeviceMotionEvent', 'DeviceOrientationEvent', 'devicePixelRatio', 'dispatchEvent', 'document', 'Document', 'DocumentFragment', 'DocumentTimeline', 'DocumentType', 'DOMError', 'DOMException', 'DOMImplementation', 'DOMParser', 'DOMSettableTokenList', 'DOMStringList', 'DOMStringMap', 'DOMTokenList', 'DragEvent', 'DynamicsCompressorNode', 'Element', 'ElementTimeControl', 'ErrorEvent', 'event', 'Event', 'EventSource', 'EventTarget', 'external', 'FederatedCredential', 'fetch', 'File', 'FileError', 'FileList', 'FileReader', 'find', 'focus', 'FocusEvent', 'FontFace', 'FormData', 'frameElement', 'frames', 'GainNode', 'Gamepad', 'GamepadButton', 'GamepadEvent', 'getComputedStyle', 'getSelection', 'HashChangeEvent', 'Headers', 'history', 'History', 'HTMLAllCollection', 'HTMLAnchorElement', 'HTMLAppletElement', 'HTMLAreaElement', 'HTMLAudioElement', 'HTMLBaseElement', 'HTMLBlockquoteElement', 'HTMLBodyElement', 'HTMLBRElement', 'HTMLButtonElement', 'HTMLCanvasElement', 'HTMLCollection', 'HTMLContentElement', 'HTMLDataListElement', 'HTMLDetailsElement', 'HTMLDialogElement', 'HTMLDirectoryElement', 'HTMLDivElement', 'HTMLDListElement', 'HTMLDocument', 'HTMLElement', 'HTMLEmbedElement', 'HTMLFieldSetElement', 'HTMLFontElement', 'HTMLFormControlsCollection', 'HTMLFormElement', 'HTMLFrameElement', 'HTMLFrameSetElement', 'HTMLHeadElement', 'HTMLHeadingElement', 'HTMLHRElement', 'HTMLHtmlElement', 'HTMLIFrameElement', 'HTMLImageElement', 'HTMLInputElement', 'HTMLIsIndexElement', 'HTMLKeygenElement', 'HTMLLabelElement', 'HTMLLayerElement', 'HTMLLegendElement', 'HTMLLIElement', 'HTMLLinkElement', 'HTMLMapElement', 'HTMLMarqueeElement', 'HTMLMediaElement', 'HTMLMenuElement', 'HTMLMetaElement', 'HTMLMeterElement', 'HTMLModElement', 'HTMLObjectElement', 'HTMLOListElement', 'HTMLOptGroupElement', 'HTMLOptionElement', 'HTMLOptionsCollection', 'HTMLOutputElement', 'HTMLParagraphElement', 'HTMLParamElement', 'HTMLPictureElement', 'HTMLPreElement', 'HTMLProgressElement', 'HTMLQuoteElement', 'HTMLScriptElement', 'HTMLSelectElement', 'HTMLShadowElement', 'HTMLSourceElement', 'HTMLSpanElement', 'HTMLStyleElement', 'HTMLTableCaptionElement', 'HTMLTableCellElement', 'HTMLTableColElement', 'HTMLTableElement', 'HTMLTableRowElement', 'HTMLTableSectionElement', 'HTMLTemplateElement', 'HTMLTextAreaElement', 'HTMLTitleElement', 'HTMLTrackElement', 'HTMLUListElement', 'HTMLUnknownElement', 'HTMLVideoElement', 'IDBCursor', 'IDBCursorWithValue', 'IDBDatabase', 'IDBEnvironment', 'IDBFactory', 'IDBIndex', 'IDBKeyRange', 'IDBObjectStore', 'IDBOpenDBRequest', 'IDBRequest', 'IDBTransaction', 'IDBVersionChangeEvent', 'Image', 'ImageBitmap', 'ImageData', 'indexedDB', 'innerHeight', 'innerWidth', 'InputEvent', 'InputMethodContext', 'IntersectionObserver', 'IntersectionObserverEntry', 'Intl', 'KeyboardEvent', 'KeyframeEffect', 'KeyframeEffectReadOnly', 'length', 'localStorage', 'location', 'Location', 'locationbar', 'matchMedia', 'MediaElementAudioSourceNode', 'MediaEncryptedEvent', 'MediaError', 'MediaKeyError', 'MediaKeyEvent', 'MediaKeyMessageEvent', 'MediaKeys', 'MediaKeySession', 'MediaKeyStatusMap', 'MediaKeySystemAccess', 'MediaList', 'MediaQueryList', 'MediaQueryListEvent', 'MediaSource', 'MediaStream', 'MediaStreamAudioDestinationNode', 'MediaStreamAudioSourceNode', 'MediaStreamEvent', 'MediaStreamTrack', 'menubar', 'MessageChannel', 'MessageEvent', 'MessagePort', 'MIDIAccess', 'MIDIConnectionEvent', 'MIDIInput', 'MIDIInputMap', 'MIDIMessageEvent', 'MIDIOutput', 'MIDIOutputMap', 'MIDIPort', 'MimeType', 'MimeTypeArray', 'MouseEvent', 'moveBy', 'moveTo', 'MutationEvent', 'MutationObserver', 'MutationRecord', 'name', 'NamedNodeMap', 'navigator', 'Navigator', 'Node', 'NodeFilter', 'NodeIterator', 'NodeList', 'Notification', 'OfflineAudioCompletionEvent', 'OfflineAudioContext', 'offscreenBuffering', 'onbeforeunload', 'onblur', 'onerror', 'onfocus', 'onload', 'onresize', 'onunload', 'open', 'openDatabase', 'opener', 'opera', 'Option', 'OscillatorNode', 'outerHeight', 'outerWidth', 'PageTransitionEvent', 'pageXOffset', 'pageYOffset', 'parent', 'PasswordCredential', 'Path2D', 'performance', 'Performance', 'PerformanceEntry', 'PerformanceMark', 'PerformanceMeasure', 'PerformanceNavigation', 'PerformanceResourceTiming', 'PerformanceTiming', 'PeriodicWave', 'Permissions', 'PermissionStatus', 'personalbar', 'Plugin', 'PluginArray', 'PopStateEvent', 'postMessage', 'print', 'ProcessingInstruction', 'ProgressEvent', 'PromiseRejectionEvent', 'prompt', 'PushManager', 'PushSubscription', 'RadioNodeList', 'Range', 'ReadableByteStream', 'ReadableStream', 'removeEventListener', 'Request', 'requestAnimationFrame', 'requestIdleCallback', 'resizeBy', 'resizeTo', 'Response', 'RTCIceCandidate', 'RTCSessionDescription', 'RTCPeerConnection', 'screen', 'Screen', 'screenLeft', 'ScreenOrientation', 'screenTop', 'screenX', 'screenY', 'ScriptProcessorNode', 'scroll', 'scrollbars', 'scrollBy', 'scrollTo', 'scrollX', 'scrollY', 'SecurityPolicyViolationEvent', 'Selection', 'self', 'ServiceWorker', 'ServiceWorkerContainer', 'ServiceWorkerRegistration', 'sessionStorage', 'setInterval', 'setTimeout', 'ShadowRoot', 'SharedKeyframeList', 'SharedWorker', 'showModalDialog', 'SiteBoundCredential', 'speechSynthesis', 'SpeechSynthesisEvent', 'SpeechSynthesisUtterance', 'status', 'statusbar', 'stop', 'Storage', 'StorageEvent', 'styleMedia', 'StyleSheet', 'StyleSheetList', 'SubtleCrypto', 'SVGAElement', 'SVGAltGlyphDefElement', 'SVGAltGlyphElement', 'SVGAltGlyphItemElement', 'SVGAngle', 'SVGAnimateColorElement', 'SVGAnimatedAngle', 'SVGAnimatedBoolean', 'SVGAnimatedEnumeration', 'SVGAnimatedInteger', 'SVGAnimatedLength', 'SVGAnimatedLengthList', 'SVGAnimatedNumber', 'SVGAnimatedNumberList', 'SVGAnimatedPathData', 'SVGAnimatedPoints', 'SVGAnimatedPreserveAspectRatio', 'SVGAnimatedRect', 'SVGAnimatedString', 'SVGAnimatedTransformList', 'SVGAnimateElement', 'SVGAnimateMotionElement', 'SVGAnimateTransformElement', 'SVGAnimationElement', 'SVGCircleElement', 'SVGClipPathElement', 'SVGColor', 'SVGColorProfileElement', 'SVGColorProfileRule', 'SVGComponentTransferFunctionElement', 'SVGCSSRule', 'SVGCursorElement', 'SVGDefsElement', 'SVGDescElement', 'SVGDiscardElement', 'SVGDocument', 'SVGElement', 'SVGElementInstance', 'SVGElementInstanceList', 'SVGEllipseElement', 'SVGEvent', 'SVGExternalResourcesRequired', 'SVGFEBlendElement', 'SVGFEColorMatrixElement', 'SVGFEComponentTransferElement', 'SVGFECompositeElement', 'SVGFEConvolveMatrixElement', 'SVGFEDiffuseLightingElement', 'SVGFEDisplacementMapElement', 'SVGFEDistantLightElement', 'SVGFEDropShadowElement', 'SVGFEFloodElement', 'SVGFEFuncAElement', 'SVGFEFuncBElement', 'SVGFEFuncGElement', 'SVGFEFuncRElement', 'SVGFEGaussianBlurElement', 'SVGFEImageElement', 'SVGFEMergeElement', 'SVGFEMergeNodeElement', 'SVGFEMorphologyElement', 'SVGFEOffsetElement', 'SVGFEPointLightElement', 'SVGFESpecularLightingElement', 'SVGFESpotLightElement', 'SVGFETileElement', 'SVGFETurbulenceElement', 'SVGFilterElement', 'SVGFilterPrimitiveStandardAttributes', 'SVGFitToViewBox', 'SVGFontElement', 'SVGFontFaceElement', 'SVGFontFaceFormatElement', 'SVGFontFaceNameElement', 'SVGFontFaceSrcElement', 'SVGFontFaceUriElement', 'SVGForeignObjectElement', 'SVGGElement', 'SVGGeometryElement', 'SVGGlyphElement', 'SVGGlyphRefElement', 'SVGGradientElement', 'SVGGraphicsElement', 'SVGHKernElement', 'SVGICCColor', 'SVGImageElement', 'SVGLangSpace', 'SVGLength', 'SVGLengthList', 'SVGLinearGradientElement', 'SVGLineElement', 'SVGLocatable', 'SVGMarkerElement', 'SVGMaskElement', 'SVGMatrix', 'SVGMetadataElement', 'SVGMissingGlyphElement', 'SVGMPathElement', 'SVGNumber', 'SVGNumberList', 'SVGPaint', 'SVGPathElement', 'SVGPathSeg', 'SVGPathSegArcAbs', 'SVGPathSegArcRel', 'SVGPathSegClosePath', 'SVGPathSegCurvetoCubicAbs', 'SVGPathSegCurvetoCubicRel', 'SVGPathSegCurvetoCubicSmoothAbs', 'SVGPathSegCurvetoCubicSmoothRel', 'SVGPathSegCurvetoQuadraticAbs', 'SVGPathSegCurvetoQuadraticRel', 'SVGPathSegCurvetoQuadraticSmoothAbs', 'SVGPathSegCurvetoQuadraticSmoothRel', 'SVGPathSegLinetoAbs', 'SVGPathSegLinetoHorizontalAbs', 'SVGPathSegLinetoHorizontalRel', 'SVGPathSegLinetoRel', 'SVGPathSegLinetoVerticalAbs', 'SVGPathSegLinetoVerticalRel', 'SVGPathSegList', 'SVGPathSegMovetoAbs', 'SVGPathSegMovetoRel', 'SVGPatternElement', 'SVGPoint', 'SVGPointList', 'SVGPolygonElement', 'SVGPolylineElement', 'SVGPreserveAspectRatio', 'SVGRadialGradientElement', 'SVGRect', 'SVGRectElement', 'SVGRenderingIntent', 'SVGScriptElement', 'SVGSetElement', 'SVGStopElement', 'SVGStringList', 'SVGStylable', 'SVGStyleElement', 'SVGSVGElement', 'SVGSwitchElement', 'SVGSymbolElement', 'SVGTests', 'SVGTextContentElement', 'SVGTextElement', 'SVGTextPathElement', 'SVGTextPositioningElement', 'SVGTitleElement', 'SVGTransform', 'SVGTransformable', 'SVGTransformList', 'SVGTRefElement', 'SVGTSpanElement', 'SVGUnitTypes', 'SVGURIReference', 'SVGUseElement', 'SVGViewElement', 'SVGViewSpec', 'SVGVKernElement', 'SVGZoomAndPan', 'SVGZoomEvent', 'Text', 'TextDecoder', 'TextEncoder', 'TextEvent', 'TextMetrics', 'TextTrack', 'TextTrackCue', 'TextTrackCueList', 'TextTrackList', 'TimeEvent', 'TimeRanges', 'toolbar', 'top', 'Touch', 'TouchEvent', 'TouchList', 'TrackEvent', 'TransitionEvent', 'TreeWalker', 'UIEvent', 'URL', 'URLSearchParams', 'ValidityState', 'VTTCue', 'WaveShaperNode', 'WebGLActiveInfo', 'WebGLBuffer', 'WebGLContextEvent', 'WebGLFramebuffer', 'WebGLProgram', 'WebGLRenderbuffer', 'WebGLRenderingContext', 'WebGLShader', 'WebGLShaderPrecisionFormat', 'WebGLTexture', 'WebGLUniformLocation', 'WebSocket', 'WheelEvent', 'window', 'Window', 'Worker', 'XDomainRequest', 'XMLDocument', 'XMLHttpRequest', 'XMLHttpRequestEventTarget', 'XMLHttpRequestProgressEvent', 'XMLHttpRequestUpload', 'XMLSerializer', 'XPathEvaluator', 'XPathException', 'XPathExpression', 'XPathNamespace', 'XPathNSResolver', 'XPathResult', 'XSLTProcessor', ], worker: [ 'applicationCache', 'atob', 'Blob', 'BroadcastChannel', 'btoa', 'Cache', 'caches', 'clearInterval', 'clearTimeout', 'close', 'console', 'fetch', 'FileReaderSync', 'FormData', 'Headers', 'IDBCursor', 'IDBCursorWithValue', 'IDBDatabase', 'IDBFactory', 'IDBIndex', 'IDBKeyRange', 'IDBObjectStore', 'IDBOpenDBRequest', 'IDBRequest', 'IDBTransaction', 'IDBVersionChangeEvent', 'ImageData', 'importScripts', 'indexedDB', 'location', 'MessageChannel', 'MessagePort', 'name', 'navigator', 'Notification', 'onclose', 'onconnect', 'onerror', 'onlanguagechange', 'onmessage', 'onoffline', 'ononline', 'onrejectionhandled', 'onunhandledrejection', 'performance', 'Performance', 'PerformanceEntry', 'PerformanceMark', 'PerformanceMeasure', 'PerformanceNavigation', 'PerformanceResourceTiming', 'PerformanceTiming', 'postMessage', 'Promise', 'Request', 'Response', 'self', 'ServiceWorkerRegistration', 'setInterval', 'setTimeout', 'TextDecoder', 'TextEncoder', 'URL', 'URLSearchParams', 'WebSocket', 'Worker', 'XMLHttpRequest', ], node: [ '__dirname', '__filename', 'Buffer', 'clearImmediate', 'clearInterval', 'clearTimeout', 'console', 'exports', 'global', 'module', 'process', 'require', 'setImmediate', 'setInterval', 'setTimeout', ], commonjs: ['exports', 'module', 'require', 'global'], amd: ['define', 'require'], mocha: [ 'after', 'afterEach', 'before', 'beforeEach', 'context', 'describe', 'it', 'mocha', 'run', 'setup', 'specify', 'suite', 'suiteSetup', 'suiteTeardown', 'teardown', 'test', 'xcontext', 'xdescribe', 'xit', 'xspecify', ], jasmine: [ 'afterAll', 'afterEach', 'beforeAll', 'beforeEach', 'describe', 'expect', 'fail', 'fdescribe', 'fit', 'it', 'jasmine', 'pending', 'runs', 'spyOn', 'waits', 'waitsFor', 'xdescribe', 'xit', ], jest: [ 'afterAll', 'afterEach', 'beforeAll', 'beforeEach', 'check', 'describe', 'expect', 'gen', 'it', 'fit', 'jest', 'pit', 'require', 'test', 'xdescribe', 'xit', 'xtest', ], qunit: [ 'asyncTest', 'deepEqual', 'equal', 'expect', 'module', 'notDeepEqual', 'notEqual', 'notOk', 'notPropEqual', 'notStrictEqual', 'ok', 'propEqual', 'QUnit', 'raises', 'start', 'stop', 'strictEqual', 'test', 'throws', ], phantomjs: ['console', 'exports', 'phantom', 'require', 'WebPage'], couch: [ 'emit', 'exports', 'getRow', 'log', 'module', 'provides', 'require', 'respond', 'send', 'start', 'sum', ], rhino: [ 'defineClass', 'deserialize', 'gc', 'help', 'importClass', 'importPackage', 'java', 'load', 'loadClass', 'Packages', 'print', 'quit', 'readFile', 'readUrl', 'runCommand', 'seal', 'serialize', 'spawn', 'sync', 'toint32', 'version', ], nashorn: [ '__DIR__', '__FILE__', '__LINE__', 'com', 'edu', 'exit', 'Java', 'java', 'javafx', 'JavaImporter', 'javax', 'JSAdapter', 'load', 'loadWithNewGlobal', 'org', 'Packages', 'print', 'quit', ], wsh: [ 'ActiveXObject', 'Enumerator', 'GetObject', 'ScriptEngine', 'ScriptEngineBuildVersion', 'ScriptEngineMajorVersion', 'ScriptEngineMinorVersion', 'VBArray', 'WScript', 'WSH', 'XDomainRequest', ], jquery: ['$', 'jQuery'], yui: ['Y', 'YUI', 'YUI_config'], shelljs: [ 'cat', 'cd', 'chmod', 'config', 'cp', 'dirs', 'echo', 'env', 'error', 'exec', 'exit', 'find', 'grep', 'ls', 'ln', 'mkdir', 'mv', 'popd', 'pushd', 'pwd', 'rm', 'sed', 'set', 'target', 'tempdir', 'test', 'touch', 'which', ], prototypejs: [ '$', '$$', '$A', '$break', '$continue', '$F', '$H', '$R', '$w', 'Abstract', 'Ajax', 'Autocompleter', 'Builder', 'Class', 'Control', 'Draggable', 'Draggables', 'Droppables', 'Effect', 'Element', 'Enumerable', 'Event', 'Field', 'Form', 'Hash', 'Insertion', 'ObjectRange', 'PeriodicalExecuter', 'Position', 'Prototype', 'Scriptaculous', 'Selector', 'Sortable', 'SortableObserver', 'Sound', 'Template', 'Toggle', 'Try', ], meteor: [ '$', '_', 'Accounts', 'AccountsClient', 'AccountsServer', 'AccountsCommon', 'App', 'Assets', 'Blaze', 'check', 'Cordova', 'DDP', 'DDPServer', 'DDPRateLimiter', 'Deps', 'EJSON', 'Email', 'HTTP', 'Log', 'Match', 'Meteor', 'Mongo', 'MongoInternals', 'Npm', 'Package', 'Plugin', 'process', 'Random', 'ReactiveDict', 'ReactiveVar', 'Router', 'ServiceConfiguration', 'Session', 'share', 'Spacebars', 'Template', 'Tinytest', 'Tracker', 'UI', 'Utils', 'WebApp', 'WebAppInternals', ], mongo: [ '_isWindows', '_rand', 'BulkWriteResult', 'cat', 'cd', 'connect', 'db', 'getHostName', 'getMemInfo', 'hostname', 'ISODate', 'listFiles', 'load', 'ls', 'md5sumFile', 'mkdir', 'Mongo', 'NumberInt', 'NumberLong', 'ObjectId', 'PlanCache', 'print', 'printjson', 'pwd', 'quit', 'removeFile', 'rs', 'sh', 'UUID', 'version', 'WriteResult', ], applescript: [ '$', 'Application', 'Automation', 'console', 'delay', 'Library', 'ObjC', 'ObjectSpecifier', 'Path', 'Progress', 'Ref', ], serviceworker: [ 'caches', 'Cache', 'CacheStorage', 'Client', 'clients', 'Clients', 'ExtendableEvent', 'ExtendableMessageEvent', 'FetchEvent', 'importScripts', 'registration', 'self', 'ServiceWorker', 'ServiceWorkerContainer', 'ServiceWorkerGlobalScope', 'ServiceWorkerMessageEvent', 'ServiceWorkerRegistration', 'skipWaiting', 'WindowClient', ], atomtest: [ 'advanceClock', 'fakeClearInterval', 'fakeClearTimeout', 'fakeSetInterval', 'fakeSetTimeout', 'resetTimeouts', 'waitsForPromise', ], embertest: [ 'andThen', 'click', 'currentPath', 'currentRouteName', 'currentURL', 'fillIn', 'find', 'findWithAssert', 'keyEvent', 'pauseTest', 'triggerEvent', 'visit', ], protractor: ['$', '$$', 'browser', 'By', 'by', 'DartObject', 'element', 'protractor'], 'shared-node-browser': ['clearInterval', 'clearTimeout', 'console', 'setInterval', 'setTimeout'], webextensions: ['browser', 'chrome', 'opr'], greasemonkey: [ 'GM_addStyle', 'GM_deleteValue', 'GM_getResourceText', 'GM_getResourceURL', 'GM_getValue', 'GM_info', 'GM_listValues', 'GM_log', 'GM_openInTab', 'GM_registerMenuCommand', 'GM_setClipboard', 'GM_setValue', 'GM_xmlhttpRequest', 'unsafeWindow', ], flow: [ 'boolean', 'number', 'string', 'null', 'void', 'mixed', 'any', 'empty', 'Array', 'Class', '$Call', '$TupleMap', '$ObjMap', '$ElementType', '$PropertyType', '$Rest', '$Diff', '$Exact', '$ReadOnly', '$ReadOnlyArray', '$Values', '$Keys', '$SuperType', '$Subtype', 'RegExp$flags', 'stream$Writable', 'stream$Readable', 'tty$WriteStream', 'tty$ReadStream', ], }; function toEncodedMessage$1(message, secondaryLocationsHolder = [], secondaryMessages, cost) { const encodedMessage = { message, cost, secondaryLocations: secondaryLocationsHolder.map((locationHolder, index) => toSecondaryLocation$1(locationHolder, !!secondaryMessages ? secondaryMessages[index] : undefined)), }; return JSON.stringify(encodedMessage); } function toSecondaryLocation$1(locationHolder, message) { if (!locationHolder.loc) { throw new Error('Invalid secondary location'); } return { message, column: locationHolder.loc.start.column, line: locationHolder.loc.start.line, endColumn: locationHolder.loc.end.column, endLine: locationHolder.loc.end.line, }; } function lva(liveVariablesMap) { const worklist = Array.from(liveVariablesMap.values(), lva => lva.segment); while (worklist.length > 0) { const current = worklist.pop(); const liveVariables = liveVariablesMap.get(current.id); const liveInHasChanged = liveVariables.propagate(liveVariablesMap); if (liveInHasChanged) { current.prevSegments.forEach(prev => worklist.push(prev)); } } } class LiveVariables { constructor(segment) { this.gen = new Set(); this.kill = new Set(); this.in = new Set(); this.out = []; this.references = new Set(); this.segment = segment; } add(ref) { const variable = ref.resolved; if (variable) { if (ref.isRead()) { this.gen.add(variable); } if (ref.isWrite()) { this.kill.add(variable); } this.references.add(ref); } } propagate(liveVariablesMap) { const out = []; this.segment.nextSegments.forEach(next => { out.push(...liveVariablesMap.get(next.id).in); }); const diff = difference(out, this.kill); this.out = out; if (shouldUpdate(this.in, this.gen, diff)) { this.in = new Set([...this.gen, ...diff]); return true; } else { return false; } } } function difference(a, b) { if (b.size === 0) { return a; } const diff = []; for (const e of a) { if (!b.has(e)) { diff.push(e); } } return diff; } function shouldUpdate(inSet, gen, diff) { for (const e of gen) { if (!inSet.has(e)) { return true; } } for (const e of diff) { if (!inSet.has(e)) { return true; } } return false; } var Mocha; (function (Mocha) { const TEST_CONSTRUCTS = [ 'describe', 'context', 'it', 'specify', 'before', 'after', 'beforeEach', 'afterEach', ]; function isTestConstruct(node, constructs = TEST_CONSTRUCTS) { return constructs.some(construct => { return (node.type === 'CallExpression' && (isIdentifier(node.callee, construct) || (node.callee.type === 'MemberExpression' && isIdentifier(node.callee.object, construct) && isIdentifier(node.callee.property, 'only', 'skip')))); }); } Mocha.isTestConstruct = isTestConstruct; function extractTestCase(node) { if (isTestCase(node)) { const callExpr = node; const [, callback] = callExpr.arguments; if (callback && FUNCTION_NODES.includes(callback.type)) { return { node: callExpr.callee, callback: callback }; } } return null; } Mocha.extractTestCase = extractTestCase; function isTestCase(node) { return isTestConstruct(node, ['it', 'specify']); } Mocha.isTestCase = isTestCase; function isDescribeCase(node) { return isTestConstruct(node, ['describe']); } Mocha.isDescribeCase = isDescribeCase; })(Mocha || (Mocha = {})); function getImportDeclarations(context) { const program = context.sourceCode.ast; if (program.sourceType === 'module') { return program.body.filter(node => node.type === 'ImportDeclaration'); } return []; } function getRequireCalls(context) { const required = []; const { scopeManager } = context.sourceCode; scopeManager.scopes.forEach(scope => scope.variables.forEach(variable => variable.defs.forEach(def => { if (def.type === 'Variable' && def.node.init) { if (isRequire$1(def.node.init)) { required.push(def.node.init); } else if (def.node.init.type === 'MemberExpression' && isRequire$1(def.node.init.object)) { required.push(def.node.init.object); } } }))); return required; } function isRequire$1(node) { return (node.type === 'CallExpression' && node.callee.type === 'Identifier' && node.callee.name === 'require' && node.arguments.length === 1); } function getModuleNameFromRequire(node) { if (isRequire$1(node)) { const moduleName = node.arguments[0]; if (moduleName.type === 'Literal') { return moduleName; } } return undefined; } function getFullyQualifiedName(context, node, fqn = [], scope) { return removeNodePrefixIfExists(getFullyQualifiedNameRaw(context, node, fqn, scope)); } function getFullyQualifiedNameRaw(context, node, fqn, scope, visitedVars = []) { const nodeToCheck = reduceToIdentifier(node, fqn); if (!isIdentifier(nodeToCheck)) { if (node.type === 'CallExpression') { const qualifiers = []; const maybeRequire = reduceTo('CallExpression', node.callee, qualifiers); const module = getModuleNameFromRequire(maybeRequire); if (typeof (module === null || module === void 0 ? void 0 : module.value) === 'string') { qualifiers.unshift(module.value); return qualifiers.join('.'); } } return null; } const variable = getVariableFromScope(scope !== null && scope !== void 0 ? scope : context.sourceCode.getScope(node), nodeToCheck.name); if (!variable || variable.defs.length > 1) { return null; } if (variable.writeable === false || visitedVars.includes(variable)) { fqn.unshift(nodeToCheck.name); return fqn.join('.'); } const definition = variable.defs.find(({ type }) => ['ImportBinding', 'Variable'].includes(type)); if (!definition) { return null; } const fqnFromImport = checkFqnFromImport(variable, definition, context, fqn, visitedVars); if (fqnFromImport !== null) { return fqnFromImport; } const fqnFromRequire = checkFqnFromRequire(variable, definition, context, fqn, visitedVars); if (fqnFromRequire !== null) { return fqnFromRequire; } return null; } function checkFqnFromImport(variable, definition, context, fqn, visitedVars) { var _a, _b, _c; if (definition.type === 'ImportBinding') { const specifier = definition.node; const importDeclaration = definition.parent; if (specifier.type === 'ImportSpecifier' && ((_a = specifier.imported) === null || _a === void 0 ? void 0 : _a.name) !== 'default') { fqn.unshift((_b = specifier.imported) === null || _b === void 0 ? void 0 : _b.name); } if (typeof ((_c = importDeclaration.source) === null || _c === void 0 ? void 0 : _c.value) === 'string') { const importedQualifiers = importDeclaration.source.value.split('/'); fqn.unshift(...importedQualifiers); return fqn.join('.'); } if (importDeclaration.type === 'TSImportEqualsDeclaration') { const importedModule = importDeclaration .moduleReference; if (importedModule.type === 'TSExternalModuleReference' && importedModule.expression.type === 'Literal' && typeof importedModule.expression.value === 'string') { const importedQualifiers = importedModule.expression.value.split('/'); fqn.unshift(...importedQualifiers); return fqn.join('.'); } if (importedModule.type === 'TSQualifiedName') { visitedVars.push(variable); return getFullyQualifiedNameRaw(context, importedModule, fqn, variable.scope, visitedVars); } } } return null; } function checkFqnFromRequire(variable, definition, context, fqn, visitedVars) { var _a; const value = getUniqueWriteReference(variable); if (definition.type === 'Variable' && value) { if (definition.node.id.type === 'ObjectPattern') { for (const property of definition.node.id.properties) { if (property.value === definition.name) { fqn.unshift(property.key.name); } } } const nodeToCheck = reduceTo('CallExpression', value, fqn); const module = (_a = getModuleNameFromRequire(nodeToCheck)) === null || _a === void 0 ? void 0 : _a.value; if (typeof module === 'string') { const importedQualifiers = module.split('/'); fqn.unshift(...importedQualifiers); return fqn.join('.'); } else { visitedVars.push(variable); return getFullyQualifiedNameRaw(context, nodeToCheck, fqn, variable.scope, visitedVars); } } return null; } function removeNodePrefixIfExists(fqn) { if (fqn === null) { return null; } const NODE_NAMESPACE = 'node:'; if (fqn.startsWith(NODE_NAMESPACE)) { return fqn.substring(NODE_NAMESPACE.length); } return fqn; } function reduceToIdentifier(node, fqn = []) { return reduceTo('Identifier', node, fqn); } function reduceTo(type, node, fqn = []) { let nodeToCheck = node; while (nodeToCheck.type !== type) { if (nodeToCheck.type === 'MemberExpression') { const { property } = nodeToCheck; if (property.type === 'Literal' && typeof property.value === 'string') { fqn.unshift(property.value); } else if (property.type === 'Identifier') { fqn.unshift(property.name); } nodeToCheck = nodeToCheck.object; } else if (nodeToCheck.type === 'CallExpression' && !getModuleNameFromRequire(nodeToCheck)) { nodeToCheck = nodeToCheck.callee; } else if (nodeToCheck.type === 'NewExpression') { nodeToCheck = nodeToCheck.callee; } else if (nodeToCheck.type === 'ChainExpression') { nodeToCheck = nodeToCheck.expression; } else if (nodeToCheck.type === 'TSNonNullExpression') { nodeToCheck = nodeToCheck .expression; } else if (nodeToCheck.type === 'TSQualifiedName') { const qualified = nodeToCheck; fqn.unshift(qualified.right.name); nodeToCheck = qualified.left; } else { break; } } return nodeToCheck; } function removeNodeWithLeadingWhitespaces(context, node, fixer, removeUntil) { const previousComments = context.sourceCode.getCommentsBefore(node); let start = 0; if (previousComments.length === 0) { const previousToken = context.sourceCode.getTokenBefore(node); if (previousToken) { start = previousToken.range[1]; } } else { start = previousComments[previousComments.length - 1].range[1]; } const end = removeUntil !== null && removeUntil !== void 0 ? removeUntil : node.range[1]; return fixer.removeRange([start, end]); } class AssignedValues extends Set { constructor() { super(...arguments); this.type = 'AssignedValues'; } } const assignedValues = (val) => new AssignedValues([val]); const unknownValue = { type: 'UnknownValue', }; function reachingDefinitions(reachingDefinitionsMap) { const worklist = Array.from(reachingDefinitionsMap.values(), defs => defs.segment); while (worklist.length > 0) { const current = worklist.pop(); const reachingDefs = reachingDefinitionsMap.get(current.id); const outHasChanged = reachingDefs.propagate(reachingDefinitionsMap); if (outHasChanged) { current.nextSegments.forEach(next => worklist.push(next)); } } } class ReachingDefinitions { constructor(segment) { this.in = new Map(); this.out = new Map(); this.references = new Set(); this.segment = segment; } add(ref) { const variable = ref.resolved; if (variable) { this.references.add(ref); } } propagate(reachingDefinitionsMap) { this.in.clear(); this.segment.prevSegments.forEach(prev => { this.join(reachingDefinitionsMap.get(prev.id).out); }); const newOut = new Map(this.in); this.references.forEach(ref => this.updateProgramState(ref, newOut)); if (!equals(this.out, newOut)) { this.out = newOut; return true; } else { return false; } } updateProgramState(ref, programState) { const variable = ref.resolved; if (!variable || !ref.isWrite()) { return; } if (!ref.writeExpr) { programState.set(variable, unknownValue); return; } const rhsValues = resolveAssignedValues(variable, ref.writeExpr, programState, ref.from); programState.set(variable, rhsValues); } join(previousOut) { var _a; for (const [key, values] of previousOut.entries()) { const inValues = (_a = this.in.get(key)) !== null && _a !== void 0 ? _a : new AssignedValues(); if (inValues.type === 'AssignedValues' && values.type === 'AssignedValues') { values.forEach(val => inValues.add(val)); this.in.set(key, inValues); } else { this.in.set(key, unknownValue); } } } } function resolveAssignedValues(lhsVariable, writeExpr, assignedValuesMap, scope) { if (!writeExpr) { return unknownValue; } switch (writeExpr.type) { case 'Literal': return writeExpr.raw ? assignedValues(writeExpr.raw) : unknownValue; case 'Identifier': { const resolvedVar = getVariableFromIdentifier(writeExpr, scope); if (resolvedVar && resolvedVar !== lhsVariable) { const resolvedAssignedValues = assignedValuesMap.get(resolvedVar); return resolvedAssignedValues !== null && resolvedAssignedValues !== void 0 ? resolvedAssignedValues : unknownValue; } return unknownValue; } default: return unknownValue; } } function equals(ps1, ps2) { if (ps1.size !== ps2.size) { return false; } for (const [variable, values1] of ps1) { const values2 = ps2.get(variable); if (!values2 || !valuesEquals(values2, values1)) { return false; } } return true; } function valuesEquals(a, b) { if (a.type === 'AssignedValues' && b.type === 'AssignedValues') { return setEquals(a, b); } return a === b; } function setEquals(a, b) { return a.size === b.size && [...a].every(e => b.has(e)); } function getVariableFromIdentifier(identifier, scope) { let variable = scope.variables.find(value => value.name === identifier.name); if (!variable && scope.upper) { variable = scope.upper.variables.find(value => value.name === identifier.name); } return variable; } const detectReactSelector = [ ':matches(', [ 'CallExpression[callee.name="require"][arguments.0.value="react"]', 'CallExpression[callee.name="require"][arguments.0.value="create-react-class"]', 'ImportDeclaration[source.value="react"]', ].join(','), ')', ].join(''); const rule$4E = { meta: { messages: { reactDetected: 'React detected', }, }, create(context) { return { [detectReactSelector](node) { context.report({ messageId: 'reactDetected', node, }); }, }; }, }; var Sinon; (function (Sinon) { function isImported(context) { return (getRequireCalls(context).some(r => r.arguments[0].type === 'Literal' && r.arguments[0].value === 'sinon') || getImportDeclarations(context).some(i => i.source.value === 'sinon')); } Sinon.isImported = isImported; function isAssertion(context, node) { return isAssertUsage(context, node); } Sinon.isAssertion = isAssertion; function isAssertUsage(context, node) { const fqn = extractFQNforCallExpression(context, node); if (!fqn) { return false; } const names = fqn.split('.'); return names.length === 3 && names[0] === 'sinon' && names[1] === 'assert'; } function extractFQNforCallExpression(context, node) { if (node.type !== 'CallExpression') { return undefined; } return getFullyQualifiedName(context, node); } })(Sinon || (Sinon = {})); function isArray(node, services) { var _a; const type = getTypeFromTreeNode$1(node, services); return ((_a = type.symbol) === null || _a === void 0 ? void 0 : _a.name) === 'Array'; } const UTILITY_TYPES = new Set([ 'Awaited', 'Partial', 'Required', 'Readonly', 'Record', 'Pick', 'Omit', 'Exclude', 'Extract', 'NonNullable', 'Parameters', 'ConstructorParameters', 'ReturnType', 'InstanceType', 'ThisParameterType', 'OmitThisParameter', 'ThisType', 'Uppercase', 'Lowercase', 'Capitalize', 'Uncapitalize', ]); const TYPED_ARRAY_TYPES = [ 'Int8Array', 'Uint8Array', 'Uint8ClampedArray', 'Int16Array', 'Uint16Array', 'Int32Array', 'Uint32Array', 'Float32Array', 'Float64Array', 'BigInt64Array', 'BigUint64Array', ]; function isTypedArray$1(node, services) { var _a; const type = getTypeFromTreeNode$1(node, services); return TYPED_ARRAY_TYPES.includes((_a = type.symbol) === null || _a === void 0 ? void 0 : _a.name); } function isString$1(node, services) { const checker = services.program.getTypeChecker(); const typ = checker.getTypeAtLocation(services.esTreeNodeToTSNodeMap.get(node)); return (typ.getFlags() & ts.TypeFlags.StringLike) !== 0; } function isNumber$2(node, services) { const checker = services.program.getTypeChecker(); const typ = checker.getTypeAtLocation(services.esTreeNodeToTSNodeMap.get(node)); return (typ.getFlags() & ts.TypeFlags.NumberLike) !== 0; } function isBigIntType(type) { return (type.getFlags() & ts.TypeFlags.BigIntLike) !== 0; } function isNumberType(type) { return (type.getFlags() & ts.TypeFlags.NumberLike) !== 0; } function isStringType$1(type) { var _a; return (type.flags & ts.TypeFlags.StringLike) > 0 || ((_a = type.symbol) === null || _a === void 0 ? void 0 : _a.name) === 'String'; } function isFunction$1(node, services) { const checker = services.program.getTypeChecker(); const type = checker.getTypeAtLocation(services.esTreeNodeToTSNodeMap.get(node)); return type.symbol && (type.symbol.flags & ts.SymbolFlags.Function) !== 0; } function isUnion$1(node, services) { const checker = services.program.getTypeChecker(); const type = checker.getTypeAtLocation(services.esTreeNodeToTSNodeMap.get(node)); return type.isUnion(); } function getUnionTypes(type) { return type.isUnion() ? type.types : [type]; } function isUndefinedOrNull(node, services) { const checker = services.program.getTypeChecker(); const typ = checker.getTypeAtLocation(services.esTreeNodeToTSNodeMap.get(node)); return ((typ.getFlags() & ts.TypeFlags.Undefined) !== 0 || (typ.getFlags() & ts.TypeFlags.Null) !== 0); } function isThenable$1(node, services) { const mapped = services.esTreeNodeToTSNodeMap.get(node); const tp = services.program.getTypeChecker().getTypeAtLocation(mapped); const thenProperty = tp.getProperty('then'); return Boolean(thenProperty && thenProperty.flags & ts.SymbolFlags.Method); } function isAny$2(type) { return type.flags === ts.TypeFlags.Any; } function isGenericType(node, services) { const type = getTypeFromTreeNode$1(node, services); return type.isTypeParameter(); } function getTypeFromTreeNode$1(node, services) { const checker = services.program.getTypeChecker(); return checker.getTypeAtLocation(services.esTreeNodeToTSNodeMap.get(node)); } function getTypeAsString(node, services) { const { typeToString, getBaseTypeOfLiteralType } = services.program.getTypeChecker(); return typeToString(getBaseTypeOfLiteralType(getTypeFromTreeNode$1(node, services))); } function getSymbolAtLocation(node, services) { const checker = services.program.getTypeChecker(); return checker.getSymbolAtLocation(services.esTreeNodeToTSNodeMap.get(node)); } function getSignatureFromCallee(node, services) { const checker = services.program.getTypeChecker(); return checker.getResolvedSignature(services.esTreeNodeToTSNodeMap.get(node)); } function isArrayLikeType(type, services) { const checker = services.program.getTypeChecker(); const constrained = checker.getBaseConstraintOfType(type); return isArrayOrUnionOfArrayType(constrained !== null && constrained !== void 0 ? constrained : type, services); } function isArrayOrUnionOfArrayType(type, services) { for (const part of getUnionTypes(type)) { if (!isArrayType(part, services)) { return false; } } return true; } function isStringArray(type, services) { return isArrayElementTypeMatching(type, services, isStringType$1); } function isNumberArray(type, services) { return isArrayElementTypeMatching(type, services, isNumberType); } function isBigIntArray(type, services) { return isArrayElementTypeMatching(type, services, isBigIntType); } function isArrayElementTypeMatching(type, services, predicate) { const checker = services.program.getTypeChecker(); if (!isArrayType(type, services)) { return false; } const [elementType] = checker.getTypeArguments(type); return elementType && predicate(elementType); } function isArrayType(type, services) { const checker = services.program.getTypeChecker(); return ('isArrayType' in checker && typeof checker.isArrayType === 'function' && checker.isArrayType(type)); } function isTypeAlias(node, context) { if (node.type !== 'TSTypeReference' || node.typeName.type !== 'Identifier' || node.typeArguments) { return false; } const scope = context.sourceCode.getScope(node); const variable = getVariableFromScope(scope, node.typeName.name); return variable === null || variable === void 0 ? void 0 : variable.defs.some(def => def.node.type === 'TSTypeAliasDeclaration'); } function isBooleanLiteralType(type) { return type.flags === ts.TypeFlags.BooleanLiteral; } function isBooleanTrueType(type) { return isBooleanLiteralType(type) && type.intrinsicName === 'true'; } function isBooleanType({ flags }) { return flags & ts.TypeFlags.BooleanLike; } function isNullOrUndefinedType({ flags }) { return flags & ts.TypeFlags.Null || flags & ts.TypeFlags.Undefined; } function isObjectType({ flags }) { return flags & ts.TypeFlags.Object; } var Vitest; (function (Vitest) { function isImported(context) { return (getRequireCalls(context).some(r => r.arguments[0].type === 'Literal' && r.arguments[0].value === 'vitest') || getImportDeclarations(context).some(i => i.source.value === 'vitest')); } Vitest.isImported = isImported; function isAssertion(context, node) { return isExpectUsage(context, node); } Vitest.isAssertion = isAssertion; function isExpectUsage(context, node) { return extractFQNforCallExpression(context, node) === 'vitest.expect'; } function extractFQNforCallExpression(context, node) { if (node.type !== 'CallExpression') { return undefined; } return getFullyQualifiedName(context, node); } })(Vitest || (Vitest = {})); function isVueSetupScript(element) { return (element.type === 'VElement' && element.name === 'script' && !!element.startTag.attributes.find(attr => attr.key.name === 'setup')); } function isInsideVueSetupScript(node, ctx) { var _a, _b; const doc = (_b = (_a = ctx.sourceCode.parserServices) === null || _a === void 0 ? void 0 : _a.getDocumentFragment) === null || _b === void 0 ? void 0 : _b.call(_a); const setupScript = doc === null || doc === void 0 ? void 0 : doc.children.find(isVueSetupScript); return (!!setupScript && !!node.range && setupScript.range[0] <= node.range[0] && setupScript.range[1] >= node.range[1]); } function isRequiredParserServices(services) { return !!(services === null || services === void 0 ? void 0 : services.program); } function decorate$K(rule) { return interceptReport(rule, reportExempting$b(isDecoratedSetterWithAngularInput)); } function reportExempting$b(exemptionCondition) { return (context, reportDescriptor) => { if ('node' in reportDescriptor) { const def = reportDescriptor['node']; if (!exemptionCondition(def)) { context.report(reportDescriptor); } } }; } function isDecoratedSetterWithAngularInput(def) { const { kind, decorators } = def; return (kind === 'set' && decorators !== undefined && decorators.some(decorator => decorator.expression.type === 'CallExpression' && decorator.expression.callee.type === 'Identifier' && decorator.expression.callee.name === 'Input')); } const rule$4D = decorate$K(eslintRules['accessor-pairs']); function decorate$J(rule) { return interceptReport(rule, (context, descriptor) => { const { node } = descriptor; const name = node.name; context.report({ ...descriptor, node: name }); }); } const rule$4C = decorate$J(jsxA11y.rules['alt-text']); function decorate$I(rule) { rule.meta.hasSuggestions = true; return interceptReport(rule, (context, reportDescriptor) => { const node = reportDescriptor.node; if (jsxAstUtils.hasAnyProp(node.attributes, ['title', 'aria-label'])) { return; } context.report({ ...reportDescriptor }); }); } const rule$4B = decorate$I(jsxA11y.rules['anchor-has-content']); const anchorIsValid = jsxA11y.rules['anchor-is-valid']; const rule$4A = interceptReport(anchorIsValid, (context, reportDescriptor) => { const descriptor = reportDescriptor; const { message } = descriptor; descriptor.message = message.substring(0, message.indexOf(' Learn')); context.report(descriptor); }); function isRegExpConstructor(node) { return (((node.type === 'CallExpression' || node.type === 'NewExpression') && node.callee.type === 'Identifier' && node.callee.name === 'RegExp' && node.arguments.length > 0) || isRegExpWithGlobalThis(node)); } function isStringReplaceCall(call, services) { return (call.callee.type === 'MemberExpression' && call.callee.property.type === 'Identifier' && !call.callee.computed && ['replace', 'replaceAll'].includes(call.callee.property.name) && call.arguments.length > 1 && isString$1(call.callee.object, services)); } function isStringRegexMethodCall(call, services) { return (call.callee.type === 'MemberExpression' && call.callee.property.type === 'Identifier' && !call.callee.computed && ['match', 'matchAll', 'search'].includes(call.callee.property.name) && call.arguments.length > 0 && isString$1(call.callee.object, services) && isString$1(call.arguments[0], services)); } function isRegExpWithGlobalThis(node) { return (node.type === 'NewExpression' && node.callee.type === 'MemberExpression' && isIdentifier(node.callee.object, 'globalThis') && isIdentifier(node.callee.property, 'RegExp') && node.arguments.length > 0); } function getFlags(callExpr, context) { if (callExpr.arguments.length < 2) { return ''; } const flags = callExpr.arguments[1]; if (isStringLiteral(flags)) { return flags.value; } if (flags.type === 'Identifier' && context !== undefined) { const variable = getVariableFromIdentifier(flags, context.sourceCode.getScope(callExpr)); const ref = getUniqueWriteReference(variable); if (ref !== undefined && isStringLiteral(ref)) { return ref.value; } } if (isStaticTemplateLiteral(flags) && flags.quasis[0].value.cooked != null) { return flags.quasis[0].value.cooked; } if (isSimpleRawString(flags)) { return getSimpleRawStringValue(flags); } return null; } function getParsedRegex(node, context) { const patternAndFlags = getPatternFromNode(node, context); if (patternAndFlags) { try { return regexpp__namespace.parseRegExpLiteral(new RegExp(patternAndFlags.pattern, patternAndFlags.flags)); } catch (_a) { } } return null; } function getPatternFromNode(node, context) { var _a; if (isRegExpConstructor(node)) { const patternOnly = getPatternFromNode(node.arguments[0], context); const flags = getFlags(node, context); if (patternOnly && flags !== null) { return { pattern: patternOnly.pattern, flags }; } } else if (isRegexLiteral(node)) { return node.regex; } else if (isStringLiteral(node)) { return { pattern: node.value, flags: '' }; } else if (isStaticTemplateLiteral(node)) { return { pattern: node.quasis[0].value.raw, flags: '' }; } else if (isSimpleRawString(node)) { return { pattern: getSimpleRawStringValue(node), flags: '' }; } else if (isIdentifier(node)) { const assignedExpression = getUniqueWriteUsage(context, node.name, node); if (assignedExpression && ((_a = assignedExpression.parent) === null || _a === void 0 ? void 0 : _a.type) === 'VariableDeclarator') { return getPatternFromNode(assignedExpression, context); } } else if (isBinaryPlus(node)) { const left = getPatternFromNode(node.left, context); const right = getPatternFromNode(node.right, context); if (left && right) { return { pattern: left.pattern + right.pattern, flags: '' }; } } return null; } function extractReferences(node) { const references = []; if (isStringLiteral(node)) { const str = node.value; const reg = /\$(\d+)|\$<([a-zA-Z]\w*)>/g; let match; while ((match = reg.exec(str)) !== null) { const [raw, index, name] = match; const value = index || name; references.push({ raw, value }); } } return references; } const UNICODE_ESCAPE_LENGTH = 4; const HEX_ESCAPE_LENGTH = 2; const CP_BACK_SLASH = cp('\\'); const CP_FORWARD_SLASH = cp('/'); const CP_CR = cp('\r'); const CP_LF = cp('\n'); const CP_n = cp('n'); const CP_r = cp('r'); const CP_t = cp('t'); const CP_b = cp('b'); const CP_v = cp('v'); const CP_f = cp('f'); const CP_u = cp('u'); const CP_x = cp('x'); function tokenizeString(s) { const tokens = []; let pos = 0; function next() { const c = cp(s, pos); pos = inc(pos, c); return c; } function readEscape() { const c = next(); switch (c) { case CP_n: return '\n'; case CP_r: return '\r'; case CP_t: return '\t'; case CP_b: return '\b'; case CP_v: return '\v'; case CP_f: return '\f'; case CP_BACK_SLASH: return '\\'; case CP_CR: if (cp(s, pos) === CP_LF) { pos++; } return ''; case CP_LF: return ''; case CP_u: return String.fromCodePoint(readUnicode()); case CP_x: return String.fromCodePoint(readHex()); default: if (isOctalDigit(c)) { return readOctal(c); } return String.fromCodePoint(c); } } function readUnicode() { let u; if (s.charAt(pos) === '{') { pos++; const close = s.indexOf('}', pos); u = s.substring(pos, close); pos = close + 1; } else { u = s.substring(pos, pos + UNICODE_ESCAPE_LENGTH); pos += UNICODE_ESCAPE_LENGTH; } return Number.parseInt(u, 16); } function readHex() { const x = Number.parseInt(s.substring(pos, pos + HEX_ESCAPE_LENGTH), 16); pos += HEX_ESCAPE_LENGTH; return x; } function readOctal(firstDigit) { let octal = String.fromCodePoint(firstDigit); let i = pos; while (isOctalDigit(cp(s, i)) && i - pos < 2) { octal += s.charAt(i); i++; } const res = Number.parseInt(octal, 8); pos = i; return String.fromCodePoint(res); } while (pos < s.length) { const start = pos; const c = next(); if (c === CP_BACK_SLASH) { const value = readEscape(); if (value !== '') { tokens.push({ value, range: [start, pos] }); } } else if (c === CP_FORWARD_SLASH) { const forwardSlash = { value: String.fromCodePoint(c), range: [start, pos], }; tokens.push(forwardSlash); tokens.push(forwardSlash); } else { tokens.push({ value: String.fromCodePoint(c), range: [start, pos] }); } } return tokens; } function inc(pos, c) { return pos + (c >= 0x10000 ? 2 : 1); } function isOctalDigit(c) { return c !== undefined && cp('0') <= c && c <= cp('7'); } function cp(s, i = 0) { return s.codePointAt(i); } function getRegexpRange(node, regexpNode) { if (isRegexLiteral(node)) { return [regexpNode.start, regexpNode.end]; } if (isStringLiteral(node)) { if (node.value === '') { return [0, 2]; } const s = node.raw; const tokens = tokenizeString(unquote(s)); if (regexpNode.start === regexpNode.end) { if (regexpNode.start - 1 < tokens.length) { return [ tokens[regexpNode.start - 1].range[0] + 1, tokens[regexpNode.start - 1].range[0] + 1, ]; } else { return [last(tokens).range[1] + 1, last(tokens).range[1] + 1]; } } const startToken = regexpNode.start - 1; if (tokens[startToken] === undefined) { return nodeRange(node); } const start = tokens[startToken].range[0]; const endToken = Math.min(regexpNode.end - 2, tokens.length - 1); if (tokens[endToken] === undefined) { return nodeRange(node); } const end = tokens[endToken].range[1]; return [start + 1, end + 1]; } if (node.type === 'TemplateLiteral') { return nodeRange(node); } throw new Error(`Expected regexp or string literal, got ${node.type}`); } function nodeRange(node) { return [0, node.range[1] - node.range[0]]; } function unquote(s) { if (!s.startsWith("'") && !s.startsWith('"')) { throw new Error(`invalid string to unquote: ${s}`); } return s.substring(1, s.length - 1); } function getRegexpLocation(node, regexpNode, context, offset = [0, 0]) { let loc; if (isRegexLiteral(node) || isStringLiteral(node)) { const source = context.sourceCode; const [start] = node.range; const [reStart, reEnd] = getRegexpRange(node, regexpNode); const locationStart = start + reStart + offset[0]; const locationEnd = start + reEnd + offset[1]; if (locationStart === locationEnd) { return null; } else { loc = { start: source.getLocFromIndex(locationStart), end: source.getLocFromIndex(locationEnd), }; } } else { loc = node.loc; } return loc; } function createRegExpRule(handlers, metadata = { meta: {} }) { return { ...metadata, create(context) { const services = isRequiredParserServices(context.sourceCode.parserServices) ? context.sourceCode.parserServices : null; function checkRegex(node, regExpAST) { if (!regExpAST) { return; } const ctx = Object.create(context); ctx.node = node; ctx.reportRegExpNode = reportRegExpNode; regexpp__namespace.visitRegExpAST(regExpAST, handlers(ctx)); } function reportRegExpNode(descriptor) { const { node, regexpNode, offset = [0, 0], ...rest } = descriptor; const loc = getRegexpLocation(node, regexpNode, context, offset); if (loc) { context.report({ ...rest, loc }); } } function checkLiteral(literal) { checkRegex(literal, getParsedRegex(literal, context)); } function checkCallExpression(callExpr) { let parsedRegex = getParsedRegex(callExpr, context); if (!parsedRegex && services && isStringRegexMethodCall(callExpr, services)) { const [implicitRegex] = callExpr.arguments; parsedRegex = getParsedRegex(implicitRegex, context); } checkRegex(callExpr.arguments[0], parsedRegex); } return { 'Literal[regex]': checkLiteral, NewExpression: checkCallExpression, CallExpression: checkCallExpression, }; }, }; } const MAX_CODE_POINT = 0x10ffff; class SimplifiedRegexCharacterClass { constructor(flags, element) { this.flags = flags; this.contents = createTree(); if (element) { this.add(element); } } add(element) { new SimplifiedRegexCharacterClass.Builder(this).visit(element); } findIntersections(that) { const iter = that.contents.begin; const intersections = []; if (iter.key === undefined) { return intersections; } while (iter.hasNext) { const { key, value } = iter; iter.next(); const to = iter.value ? iter.key : iter.key - 1; if (value && this.hasEntryBetween(key, to)) { intersections.push(value); } } if (iter.value && this.hasEntryBetween(iter.key, MAX_CODE_POINT)) { intersections.push(iter.value); } return intersections; } hasEntryBetween(from, to) { const before = this.contents.le(from); return (before.key !== undefined && before.value) || !this.isRangeEmpty(from + 1, to + 1); } isRangeEmpty(from, to) { let isEmpty = true; this.contents.forEach(() => (isEmpty = false), from, to); return isEmpty; } addRange(from, to, element) { const oldEntry = this.contents.le(to); const oldEnd = oldEntry.key === undefined ? undefined : this.contents.gt(oldEntry.key).key; this.contents = this.put(from, element, this.contents); const iterator = this.contents.begin; while (iterator.key !== undefined) { if (iterator.key > from && iterator.key <= to && iterator.value === undefined) { this.contents = iterator.update(element); } iterator.next(); } const next = to + 1; if (next <= MAX_CODE_POINT) { if (oldEntry.key !== undefined && oldEntry.value && (oldEnd === undefined || oldEnd > next)) { this.contents = this.put(next, oldEntry.value, this.contents); } else if (this.contents.find(next).key === undefined) { this.contents = this.put(next, undefined, this.contents); } } } put(key, value, tree) { const entry = tree.find(key); if (entry.valid) { return entry.update(value); } return tree.insert(key, value); } } SimplifiedRegexCharacterClass.Builder = class { constructor(characters) { this.characters = characters; } visit(element) { switch (element.type) { case 'Character': this.visitCharacter(element); break; case 'CharacterClassRange': this.visitCharacterClassRange(element); break; case 'CharacterSet': this.visitCharacterSet(element); break; } } visitCharacter(character) { this.addRange(character.value, character.value, character); } visitCharacterClassRange(characterRange) { this.addRange(characterRange.min.value, characterRange.max.value, characterRange); } visitCharacterSet(characterSet) { switch (characterSet.kind) { case 'digit': if (characterSet.negate) { this.characters.addRange(0x00, this.codePoint('0') - 1, characterSet); if (this.characters.flags.unicode) { this.characters.addRange(this.codePoint('9') + 1, 0xff, characterSet); } else { this.characters.addRange(this.codePoint('9') + 1, MAX_CODE_POINT, characterSet); } } else { this.characters.addRange(this.codePoint('0'), this.codePoint('9'), characterSet); } break; case 'space': if (characterSet.negate) { this.characters.addRange(0x00, this.codePoint('\t') - 1, characterSet); this.characters.addRange(this.codePoint('\r') + 1, this.codePoint(' ') - 1, characterSet); if (this.characters.flags.unicode) { this.characters.addRange(this.codePoint(' ') + 1, 0x84, characterSet); this.characters.addRange(0x86, 0x9f, characterSet); this.characters.addRange(0xa1, 0x167f, characterSet); this.characters.addRange(0x1681, 0x1fff, characterSet); this.characters.addRange(0x200b, 0x2027, characterSet); this.characters.addRange(0x202a, 0x202e, characterSet); this.characters.addRange(0x2030, 0x205e, characterSet); this.characters.addRange(0x2060, 0x2fff, characterSet); this.characters.addRange(0x3001, MAX_CODE_POINT, characterSet); } else { this.characters.addRange(this.codePoint(' ') + 1, MAX_CODE_POINT, characterSet); } } else { this.characters.addRange(this.codePoint('\t'), this.codePoint('\r'), characterSet); this.characters.addRange(this.codePoint(' '), this.codePoint(' '), characterSet); if (this.characters.flags.unicode) { this.characters.addRange(0x85, 0x85, characterSet); this.characters.addRange(0xa0, 0xa0, characterSet); this.characters.addRange(0x1680, 0x1680, characterSet); this.characters.addRange(0x2000, 0x200a, characterSet); this.characters.addRange(0x2028, 0x2029, characterSet); this.characters.addRange(0x202f, 0x202f, characterSet); this.characters.addRange(0x205f, 0x205f, characterSet); this.characters.addRange(0x3000, 0x3000, characterSet); } } break; case 'word': if (characterSet.negate) { this.characters.addRange(0x00, this.codePoint('0') - 1, characterSet); this.characters.addRange(this.codePoint('9') + 1, this.codePoint('A') - 1, characterSet); this.characters.addRange(this.codePoint('Z') + 1, this.codePoint('_') - 1, characterSet); this.characters.addRange(this.codePoint('`'), this.codePoint('`'), characterSet); if (this.characters.flags.unicode) { this.characters.addRange(this.codePoint('z') + 1, this.codePoint('µ') - 1, characterSet); } else { this.characters.addRange(this.codePoint('z') + 1, MAX_CODE_POINT, characterSet); } } else { this.characters.addRange(this.codePoint('0'), this.codePoint('9'), characterSet); this.characters.addRange(this.codePoint('A'), this.codePoint('Z'), characterSet); this.characters.addRange(this.codePoint('_'), this.codePoint('_'), characterSet); this.characters.addRange(this.codePoint('a'), this.codePoint('z'), characterSet); } break; } } addRange(from, to, element) { const upperCaseFrom = this.codePoint(String.fromCodePoint(from).toUpperCase()); const upperCaseTo = this.codePoint(String.fromCodePoint(to).toUpperCase()); const lowerCaseFrom = this.codePoint(String.fromCodePoint(upperCaseFrom).toLowerCase()); const lowerCaseTo = this.codePoint(String.fromCodePoint(upperCaseTo).toLowerCase()); if (this.characters.flags.ignoreCase && lowerCaseFrom !== upperCaseFrom && lowerCaseTo !== upperCaseTo && ((this.isAscii(from) && this.isAscii(to)) || this.characters.flags.unicode)) { this.characters.addRange(upperCaseFrom, upperCaseTo, element); this.characters.addRange(lowerCaseFrom, lowerCaseTo, element); } else { this.characters.addRange(from, to, element); } } isAscii(c) { return c < 128; } codePoint(c) { const cp = c.codePointAt(0); if (cp === undefined) { throw new Error(`failed to compute code point for: ${c}`); } return cp; } }; var Position; (function (Position) { Position[Position["BEGINNING"] = 0] = "BEGINNING"; Position[Position["END"] = 1] = "END"; })(Position || (Position = {})); const rule$4z = createRegExpRule(context => { return { onPatternEnter: (pattern) => { const { alternatives } = pattern; if (alternatives.length > 1 && (anchoredAt(alternatives, Position.BEGINNING) || anchoredAt(alternatives, Position.END)) && notAnchoredElseWhere(alternatives)) { context.reportRegExpNode({ message: 'Group parts of the regex together to make the intended operator precedence explicit.', node: context.node, regexpNode: pattern, }); } }, }; }); function anchoredAt(alternatives, position) { const itemIndex = position === Position.BEGINNING ? 0 : alternatives.length - 1; const firstOrLast = alternatives[itemIndex]; return isAnchored(firstOrLast, position); } function notAnchoredElseWhere(alternatives) { if (isAnchored(alternatives[0], Position.END) || isAnchored(alternatives[alternatives.length - 1], Position.BEGINNING)) { return false; } for (const alternative of alternatives.slice(1, alternatives.length - 1)) { if (isAnchored(alternative, Position.BEGINNING) || isAnchored(alternative, Position.END)) { return false; } } return true; } function isAnchored(alternative, position) { const { elements } = alternative; if (elements.length === 0) { return false; } const index = position === Position.BEGINNING ? 0 : elements.length - 1; const firstOrLast = elements[index]; return isAnchor(firstOrLast); } function isAnchor(element) { return element.type === 'Assertion' && (element.kind === 'start' || element.kind === 'end'); } const rule$4y = { create(context) { const services = context.sourceCode.parserServices; if (!isRequiredParserServices(services)) { return {}; } const tc = services.program.getTypeChecker(); function isBuiltInMethod(symbol) { var _a; const parent = (_a = symbol.valueDeclaration) === null || _a === void 0 ? void 0 : _a.parent; if (!parent || parent.kind !== ts.SyntaxKind.InterfaceDeclaration) { return false; } const parentSymbol = tc.getSymbolAtLocation(parent.name); if (!parentSymbol) { return false; } const fqn = tc.getFullyQualifiedName(parentSymbol); return ['String', 'Math', 'Array', 'Number', 'Date'].includes(fqn); } function isVarArg(param) { return !!param.dotDotDotToken; } function isTypeParameter(type) { return type.getFlags() & ts.TypeFlags.TypeParameter; } function declarationMismatch(declaration, callExpression) { const parameters = declaration.parameters; for (let i = 0; i < Math.min(parameters.length, callExpression.arguments.length); i++) { const parameterType = parameters[i].type; if (!parameterType) { return null; } const declaredType = tc.getTypeFromTypeNode(parameterType); const actualType = getTypeFromTreeNode$1(callExpression.arguments[i], services); if (!tc.isTypeAssignableTo(actualType, declaredType) && !isTypeParameter(declaredType) && !ts.isFunctionTypeNode(parameterType) && !isVarArg(parameters[i])) { return { actualType, declaredType, node: callExpression.arguments[i] }; } } return null; } function typeToString(type) { return tc.typeToString(tc.getBaseTypeOfLiteralType(type)); } return { CallExpression: (node) => { const callExpression = node; const tsCallExpr = services.esTreeNodeToTSNodeMap.get(callExpression.callee); const symbol = tc.getSymbolAtLocation(tsCallExpr); if ((symbol === null || symbol === void 0 ? void 0 : symbol.declarations) && isBuiltInMethod(symbol)) { let mismatch = null; for (const declaration of symbol.declarations) { mismatch = declarationMismatch(declaration, callExpression); if (!mismatch) { return; } } if (mismatch) { context.report({ node: mismatch.node, message: `Verify that argument is of correct type: expected '${typeToString(mismatch.declaredType)}' instead of '${typeToString(mismatch.actualType)}'.`, }); } } }, }; }, }; const rule$4x = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { const services = context.sourceCode.parserServices; const canResolveType = isRequiredParserServices(services); function checkArguments(functionCall) { const resolvedFunction = resolveFunctionDeclaration(functionCall); if (!resolvedFunction) { return; } const { params: functionParameters, declaration: functionDeclaration } = resolvedFunction; const argumentNames = functionCall.arguments.map(arg => { const argument = arg; return argument.type === 'Identifier' ? argument.name : undefined; }); for (let argumentIndex = 0; argumentIndex < argumentNames.length; argumentIndex++) { const argumentName = argumentNames[argumentIndex]; if (argumentName) { const swappedArgumentName = getSwappedArgumentName(argumentNames, functionParameters, argumentName, argumentIndex, functionCall); if (swappedArgumentName && !areComparedArguments([argumentName, swappedArgumentName], functionCall)) { raiseIssue(argumentName, swappedArgumentName, functionDeclaration, functionCall); return; } } } } function areComparedArguments(argumentNames, node) { function getName(node) { switch (node.type) { case 'Identifier': return node.name; case 'CallExpression': return getName(node.callee); case 'MemberExpression': return getName(node.object); default: return undefined; } } function checkComparedArguments(lhs, rhs) { return ([lhs, rhs].map(getName).filter(name => name && argumentNames.includes(name)).length === argumentNames.length); } const maybeIfStmt = context.sourceCode .getAncestors(node) .reverse() .find(ancestor => ancestor.type === 'IfStatement'); if (maybeIfStmt) { const { test } = maybeIfStmt; switch (test.type) { case 'BinaryExpression': { const binExpr = test; if (['==', '!=', '===', '!==', '<', '<=', '>', '>='].includes(binExpr.operator)) { const { left: lhs, right: rhs } = binExpr; return checkComparedArguments(lhs, rhs); } break; } case 'CallExpression': { const callExpr = test; if (callExpr.arguments.length === 1 && callExpr.callee.type === 'MemberExpression') { const [lhs, rhs] = [callExpr.callee.object, callExpr.arguments[0]]; return checkComparedArguments(lhs, rhs); } break; } } } return false; } function resolveFunctionDeclaration(node) { if (canResolveType) { return resolveFromTSSignature(node); } let functionDeclaration = null; if (isFunctionNode(node.callee)) { functionDeclaration = node.callee; } else if (node.callee.type === 'Identifier') { functionDeclaration = resolveFromFunctionReference(context, node.callee); } if (!functionDeclaration) { return null; } return { params: extractFunctionParameters(functionDeclaration), declaration: functionDeclaration, }; } function resolveFromTSSignature(node) { const signature = getSignatureFromCallee(node, services); if (signature === null || signature === void 0 ? void 0 : signature.declaration) { return { params: signature.parameters.map(param => param.name), declaration: services.tsNodeToESTreeNodeMap.get(signature.declaration), }; } return null; } function getSwappedArgumentName(argumentNames, functionParameters, argumentName, argumentIndex, node) { const indexInFunctionDeclaration = functionParameters.findIndex(functionParameterName => functionParameterName === argumentName); if (indexInFunctionDeclaration >= 0 && indexInFunctionDeclaration !== argumentIndex) { const potentiallySwappedArgument = argumentNames[indexInFunctionDeclaration]; if (potentiallySwappedArgument && potentiallySwappedArgument === functionParameters[argumentIndex] && haveCompatibleTypes(node.arguments[argumentIndex], node.arguments[indexInFunctionDeclaration])) { return potentiallySwappedArgument; } } return null; } function haveCompatibleTypes(arg1, arg2) { if (canResolveType) { const type1 = normalizeType(getTypeAsString(arg1, services)); const type2 = normalizeType(getTypeAsString(arg2, services)); return type1 === type2; } return true; } function raiseIssue(arg1, arg2, functionDeclaration, node) { const primaryMessage = `Arguments '${arg1}' and '${arg2}' have the same names but not the same order as the function parameters.`; const encodedMessage = { message: primaryMessage, secondaryLocations: getSecondaryLocations(functionDeclaration), }; context.report({ message: JSON.stringify(encodedMessage), loc: getParametersClauseLocation(node.arguments), }); } return { NewExpression: (node) => { checkArguments(node); }, CallExpression: (node) => { checkArguments(node); }, }; }, }; function extractFunctionParameters(functionDeclaration) { return functionDeclaration.params.map(param => { const identifiers = resolveIdentifiers(param); if (identifiers.length === 1 && identifiers[0]) { return identifiers[0].name; } return undefined; }); } function getSecondaryLocations(functionDeclaration) { if ((functionDeclaration === null || functionDeclaration === void 0 ? void 0 : functionDeclaration.params) && functionDeclaration.params.length > 0) { const { start, end } = getParametersClauseLocation(functionDeclaration.params); return [ { message: 'Formal parameters', line: start.line, column: start.column, endLine: end.line, endColumn: end.column, }, ]; } return []; } function getParametersClauseLocation(parameters) { const firstParam = parameters[0]; const lastParam = parameters[parameters.length - 1]; return { start: firstParam.loc.start, end: lastParam.loc.end }; } function normalizeType(typeAsString) { switch (typeAsString) { case 'String': return 'string'; case 'Boolean': return 'boolean'; case 'Number': return 'number'; default: return typeAsString; } } const MESSAGE$6 = "Use the rest syntax to declare this function's arguments."; const SECONDARY_MESSAGE = 'Replace this reference to "arguments".'; const rule$4w = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { return { 'Program:exit': (node) => context.sourceCode .getScope(node) .childScopes.forEach(child => checkArgumentsUsageInScopeRecursively(context, child)), }; }, }; function checkArgumentsUsageInScopeRecursively(context, scope) { scope.variables .filter(variable => variable.name === 'arguments') .forEach(variable => checkArgumentsVariableWithoutDefinition(context, variable)); scope.childScopes.forEach(child => checkArgumentsUsageInScopeRecursively(context, child)); } function checkArgumentsVariableWithoutDefinition(context, variable) { const isLocalVariableOrParameter = variable.defs.length > 0; const references = variable.references.filter(ref => !isFollowedByLengthProperty(ref)); if (!isLocalVariableOrParameter && references.length > 0) { const firstReference = references[0]; const secondaryLocations = references.slice(1).map(ref => ref.identifier); context.report({ node: firstReference.identifier, message: toEncodedMessage$1(MESSAGE$6, secondaryLocations, Array(secondaryLocations.length).fill(SECONDARY_MESSAGE)), }); } } function isFollowedByLengthProperty(reference) { const parent = reference.identifier.parent; return (!!parent && parent.type === 'MemberExpression' && parent.property.type === 'Identifier' && parent.property.name === 'length'); } const message$5 = `Add a "return" statement to this callback.`; const methodsWithCallback = [ 'every', 'filter', 'find', 'findLast', 'findIndex', 'findLastIndex', 'map', 'flatMap', 'reduce', 'reduceRight', 'some', 'sort', 'toSorted', ]; function hasCallBackWithoutReturn(argument, services) { const checker = services.program.getTypeChecker(); const type = checker.getTypeAtLocation(services.esTreeNodeToTSNodeMap.get(argument)); const signatures = type.getCallSignatures(); return (signatures.length > 0 && signatures.every(sig => checker.typeToString(sig.getReturnType()) === 'void')); } const rule$4v = { create(context) { const services = context.sourceCode.parserServices; if (!isRequiredParserServices(services)) { return {}; } return { 'CallExpression[callee.type="MemberExpression"]'(node) { const callExpression = node; const args = callExpression.arguments; const memberExpression = callExpression.callee; const { object } = memberExpression; const propName = extractPropName(memberExpression); if (propName === null || args.length === 0) { return; } if (methodsWithCallback.includes(propName) && (isArray(object, services) || isTypedArray$1(object, services)) && hasCallBackWithoutReturn(args[0], services)) { context.report({ message: message$5, ...getNodeToReport$1(args[0], node, context), }); } else if (isMemberExpression(callExpression.callee, 'Array', 'from') && args.length > 1 && hasCallBackWithoutReturn(args[1], services)) { context.report({ message: message$5, ...getNodeToReport$1(args[1], node, context), }); } }, }; }, }; function extractPropName(memberExpression) { if (isDotNotation(memberExpression)) { return memberExpression.property.name; } else if (isIndexNotation(memberExpression)) { return memberExpression.property.value; } else { return null; } } function getNodeToReport$1(node, parent, context) { if (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') { return { loc: locations.getMainFunctionTokenLocation(node, parent, context), }; } return { node, }; } const rule$4u = { meta: { hasSuggestions: true, }, create(context) { function checkNewExpression(node) { const newExpression = node; if (newExpression.callee.type === 'Identifier' && newExpression.callee.name === 'Array') { let message = 'Use either a literal or "Array.from()" instead of the "Array" constructor.'; let suggest = [ { desc: 'Replace with a literal', fix: replaceWithLiteralFix(newExpression, context), }, ]; if (newExpression.arguments.length === 1 && newExpression.arguments[0].type === 'Literal' && typeof newExpression.arguments[0].value === 'number') { message = 'Use "Array.from()" instead of the "Array" constructor.'; } if (newExpression.arguments.length === 1) { suggest = [ { desc: 'Replace with "Array.from()"', fix: replaceWithArrayFromFix(newExpression, context), }, ]; } context.report({ node, message, suggest }); } } return { NewExpression: checkNewExpression, }; }, }; function replaceWithLiteralFix(newExpression, context) { const argText = newExpression.arguments .map((arg) => context.sourceCode.getText(arg)) .join(', '); return fixer => fixer.replaceText(newExpression, `[${argText}]`); } function replaceWithArrayFromFix(newExpression, context) { const argText = context.sourceCode.getText(newExpression.arguments[0]); return fixer => fixer.replaceText(newExpression, `Array.from({length: ${argText}})`); } const MESSAGE_ADD_PARAMETER = 'Add parentheses around the parameter of this arrow function.'; const MESSAGE_REMOVE_PARAMETER = 'Remove parentheses around the parameter of this arrow function.'; const MESSAGE_ADD_BODY = 'Add curly braces and "return" to this arrow function body.'; const MESSAGE_REMOVE_BODY = 'Remove curly braces and "return" from this arrow function body.'; const rule$4t = { meta: { schema: [ { type: 'object', properties: { requireParameterParentheses: { type: 'boolean', }, requireBodyBraces: { type: 'boolean', }, }, }, ], }, create(context) { const options = context.options[0] || {}; const requireParameterParentheses = !!options.requireParameterParentheses; const requireBodyBraces = !!options.requireBodyBraces; return { ArrowFunctionExpression(node) { const arrowFunction = node; checkParameters(context, requireParameterParentheses, arrowFunction); checkBody(context, requireBodyBraces, arrowFunction); }, }; }, }; function checkParameters(context, requireParameterParentheses, arrowFunction) { if (arrowFunction.params.length !== 1) { return; } const parameter = arrowFunction.params[0]; const tokenAfterParameter = context.sourceCode.getTokenAfter(parameter); const hasParameterParentheses = tokenAfterParameter && tokenAfterParameter.value === ')'; if (requireParameterParentheses && !hasParameterParentheses) { context.report({ node: parameter, message: MESSAGE_ADD_PARAMETER }); } else if (!requireParameterParentheses && !hasGeneric(context, arrowFunction) && hasParameterParentheses) { const arrowFunctionComments = context.sourceCode.getCommentsInside(arrowFunction); const arrowFunctionBodyComments = context.sourceCode.getCommentsInside(arrowFunction.body); const hasArrowFunctionParamsComments = arrowFunctionComments.filter(comment => !arrowFunctionBodyComments.includes(comment)).length > 0; if (parameter.type === 'Identifier' && !hasArrowFunctionParamsComments && !parameter.typeAnnotation && !arrowFunction.returnType) { context.report({ node: parameter, message: MESSAGE_REMOVE_PARAMETER }); } } } function hasGeneric(context, arrowFunction) { const offset = arrowFunction.async ? 1 : 0; const firstTokenIgnoreAsync = context.sourceCode.getFirstToken(arrowFunction, offset); return firstTokenIgnoreAsync && firstTokenIgnoreAsync.value === '<'; } function checkBody(context, requireBodyBraces, arrowFunction) { const hasBodyBraces = arrowFunction.body.type === 'BlockStatement'; if (requireBodyBraces && !hasBodyBraces) { context.report({ node: arrowFunction.body, message: MESSAGE_ADD_BODY }); } else if (!requireBodyBraces && hasBodyBraces) { const statements = arrowFunction.body.body; if (statements.length === 1) { const statement = statements[0]; if (isRemovableReturn(statement)) { context.report({ node: arrowFunction.body, message: MESSAGE_REMOVE_BODY }); } } } } function isRemovableReturn(statement) { if (statement.type === 'ReturnStatement') { const returnStatement = statement; const returnExpression = returnStatement.argument; if (returnExpression && returnExpression.type !== 'ObjectExpression') { const location = returnExpression.loc; return location && location.start.line === location.end.line; } } return false; } ({ ruleId: 'internal-cognitive-complexity', ruleModule: sonarjs.rules['cognitive-complexity'], ruleConfig: ['metric'], }); function childrenOf$1(node, visitorKeys) { const keys = visitorKeys[node.type]; const children = []; if (keys) { for (const key of keys) { const child = node[key]; if (Array.isArray(child)) { children.push(...child); } else { children.push(child); } } } return children.filter(Boolean); } function sanitize(rule) { return { ...(!!rule.meta && { meta: rule.meta }), create(context) { var _a; if (((_a = rule.meta) === null || _a === void 0 ? void 0 : _a.docs) && rule.meta.docs.requiresTypeChecking === true && !isRequiredParserServices(context.sourceCode.parserServices)) { return {}; } return rule.create(context); }, }; } const sanitized = {}; for (const ruleKey of Object.keys(tsEslint.rules)) { sanitized[ruleKey] = sanitize(tsEslint.rules[ruleKey]); } const tsEslintRules = sanitized; var Supertest; (function (Supertest) { function isImported(context) { return (getRequireCalls(context).some(r => r.arguments[0].type === 'Literal' && r.arguments[0].value === 'supertest') || getImportDeclarations(context).some(i => i.source.value === 'supertest')); } Supertest.isImported = isImported; function isAssertion(context, node) { const fqn = extractFQNForCallExpression(context, node); if (!fqn) { return false; } const names = fqn.split('.'); return names.length >= 3 && names[0] === 'supertest' && names[2] === 'expect'; } Supertest.isAssertion = isAssertion; function extractFQNForCallExpression(context, node) { if (node.type !== 'CallExpression') { return undefined; } return getFullyQualifiedName(context, node); } })(Supertest || (Supertest = {})); const rule$4s = { create(context) { const visitedNodes = new Set(); const potentialIssues = []; return { 'CallExpression:exit': (node) => { const testCase = Mocha.extractTestCase(node); if (testCase !== null) { checkAssertions(testCase, context, potentialIssues, visitedNodes); } }, 'Program:exit': () => { if (Chai.isImported(context) || Sinon.isImported(context) || Vitest.isImported(context) || Supertest.isImported(context)) { potentialIssues.forEach(issue => { context.report(issue); }); } }, }; }, }; function checkAssertions(testCase, context, potentialIssues, visitedNodes) { const { node, callback } = testCase; const visitor = new TestCaseAssertionVisitor(context); visitor.visit(context, callback.body, visitedNodes); if (visitor.missingAssertions()) { potentialIssues.push({ node, message: 'Add at least one assertion to this test case.' }); } } class TestCaseAssertionVisitor { constructor(context) { this.context = context; this.visitorKeys = context.sourceCode.visitorKeys; this.hasAssertions = false; } visit(context, node, visitedNodes) { if (visitedNodes.has(node)) { return; } visitedNodes.add(node); if (this.hasAssertions) { return; } if (Chai.isAssertion(context, node) || Sinon.isAssertion(context, node) || Vitest.isAssertion(context, node) || Supertest.isAssertion(context, node)) { this.hasAssertions = true; return; } if (isFunctionCall(node)) { const { callee } = node; if (callee.name === 'expect') { this.hasAssertions = true; return; } const functionDef = resolveFunction(this.context, callee); if (functionDef) { this.visit(context, functionDef.body, visitedNodes); } } for (const child of childrenOf$1(node, this.visitorKeys)) { this.visit(context, child, visitedNodes); } } missingAssertions() { return !this.hasAssertions; } } const AWS_OPTIONS_ARGUMENT_POSITION = 2; function AwsCdkTemplate(mapOrFactory, metadata = { meta: {} }) { return { ...metadata, create(ctx) { const consumers = typeof mapOrFactory === 'function' ? mapOrFactory(ctx) : mapOrFactory; return { 'NewExpression, CallExpression'(node) { if (node.arguments.some(arg => arg.type === 'SpreadElement')) { return; } for (const fqn in consumers) { const normalizedExpectedFQN = normalizeFQN(fqn); const callback = consumers[fqn]; if (typeof callback === 'object' || node.type === 'CallExpression') { executeIfMatching(node, normalizedExpectedFQN, callback); continue; } const normalizedActualFQN = normalizeFQN(getFullyQualifiedName(ctx, node.callee)); if (normalizedActualFQN === normalizedExpectedFQN) { callback(node, ctx); } } }, }; function executeIfMatching(node, expected, callback) { var _a; if (typeof callback === 'function') { return; } const fqn = normalizeFQN(getFullyQualifiedName(ctx, node.callee)); if (node.type === 'NewExpression' && fqn === expected) { (_a = callback.newExpression) === null || _a === void 0 ? void 0 : _a.call(callback, node, ctx); } else if (isMethodCall(callback, fqn, expected)) { callback.callExpression(node, ctx, fqn); } } function isMethodCall(callback, fqn, expected) { if (callback.functionName) { return fqn === `${expected}.${callback.functionName}`; } else if (callback.methods && (fqn === null || fqn === void 0 ? void 0 : fqn.startsWith(expected))) { const methodNames = fqn.substring(expected.length).split('.'); const methods = callback.methods; return methodNames.every(name => name === '' || methods.includes(name)); } else { return fqn === expected; } } }, }; } function getMessageAtPos(messageId, pos = 0) { if (typeof messageId === 'string') { return messageId; } return messageId[pos]; } function AwsCdkCheckArguments(messageId, needsProps, propertyName, values, silent = false, position = AWS_OPTIONS_ARGUMENT_POSITION) { return (expr, ctx) => { const argument = expr.arguments[position]; if (!argument || isUndefined(argument)) { if (needsProps) { if (silent) { return expr.callee; } ctx.report({ messageId: getMessageAtPos(messageId, 0), node: expr.callee }); } return; } const properties = traverseProperties({ node: argument, nodeToReport: argument }, typeof propertyName === 'string' ? [propertyName] : propertyName, ctx, getMessageAtPos(messageId, 0), needsProps, silent); if (!Array.isArray(properties)) { return properties; } if (!(properties === null || properties === void 0 ? void 0 : properties.length)) { return; } for (const property of properties) { const propertyValue = getUniqueWriteUsageOrNode(ctx, property.node.value, true); if (isUnresolved(propertyValue, ctx)) { continue; } if (isUndefined(propertyValue) || (propertyValue.type === 'ArrayExpression' && !propertyValue.elements.length)) { if (needsProps) { if (silent) { return getNodeToReport(property); } ctx.report({ messageId: getMessageAtPos(messageId, 0), node: getNodeToReport(property) }); } continue; } if ((values === null || values === void 0 ? void 0 : values.primitives) && disallowedValue(ctx, propertyValue, values.primitives)) { if (silent) { return getNodeToReport(property); } ctx.report({ messageId: getMessageAtPos(messageId, 1), node: getNodeToReport(property) }); } if ((values === null || values === void 0 ? void 0 : values.fqns) && disallowedFQNs(ctx, propertyValue, values.fqns)) { if (silent) { return getNodeToReport(property); } ctx.report({ messageId: getMessageAtPos(messageId, 1), node: getNodeToReport(property) }); } if ((values === null || values === void 0 ? void 0 : values.customChecker) && values.customChecker(ctx, propertyValue)) { if (silent) { return getNodeToReport(property); } ctx.report({ messageId: getMessageAtPos(messageId, 1), node: getNodeToReport(property) }); } } }; } function getNodeToReport(property) { if (property.nodeToReport.type === 'Property') { return property.nodeToReport.value; } return property.nodeToReport; } function traverseProperties(node, propertyPath, ctx, messageId, needsProp, silent) { const [propertyName, ...nextElements] = propertyPath; const properties = []; const children = []; if (isUnresolved(node.node, ctx)) { return []; } const objExpr = getValueOfExpression(ctx, node.node, 'ObjectExpression', true); if (objExpr === undefined) { const arrayExpr = getValueOfExpression(ctx, node.node, 'ArrayExpression', true); if (arrayExpr === undefined || !arrayExpr.elements.length) { if (needsProp) { if (silent) { return node.nodeToReport; } ctx.report({ messageId, node: node.nodeToReport }); } return []; } for (const element of arrayExpr.elements) { const elemObjExpr = getValueOfExpression(ctx, element, 'ObjectExpression', true); if (elemObjExpr && element) { children.push({ node: elemObjExpr, nodeToReport: element }); } } } else { children.push({ node: objExpr, nodeToReport: node.nodeToReport }); } for (const child of children) { const property = getProperty$1(child.node, propertyName, ctx); if (property === undefined) { continue; } if (!property) { if (needsProp) { if (silent) { return node.nodeToReport; } ctx.report({ messageId, node: node.nodeToReport }); } continue; } if (nextElements.length) { if (child.node === child.nodeToReport && child.node.properties.includes(property)) { child.nodeToReport = property.value; } child.node = property.value; const nextElementChildren = traverseProperties(child, nextElements, ctx, messageId, needsProp, silent); if (!Array.isArray(nextElementChildren)) { return nextElementChildren; } properties.push(...nextElementChildren); } else { if (child.node === child.nodeToReport && child.node.properties.includes(property)) { child.nodeToReport = property; } child.node = property; properties.push(child); } } return properties; } function disallowedValue(ctx, node, values) { var _a, _b; const literal = getLiteralValue$1(ctx, node); if (literal) { if ((_a = values.valid) === null || _a === void 0 ? void 0 : _a.length) { const found = values.valid.some(value => { if (values.case_insensitive && typeof literal.value === 'string') { return value.toLowerCase() === literal.value.toLowerCase(); } return value === literal.value; }); if (!found) { return true; } } if ((_b = values.invalid) === null || _b === void 0 ? void 0 : _b.length) { const found = values.invalid.some(value => { if (values.case_insensitive && typeof literal.value === 'string') { return value.toLowerCase() === literal.value.toLowerCase(); } return value === literal.value; }); if (found) { return true; } } } return false; } function getLiteralValue$1(ctx, node) { if (isLiteral$2(node)) { return node; } else if (isIdentifier(node)) { const usage = getUniqueWriteUsage(ctx, node.name, node); if (usage) { return getLiteralValue$1(ctx, usage); } } return undefined; } function disallowedFQNs(ctx, node, values) { var _a, _b; const normalizedFQN = normalizeFQN(getFullyQualifiedName(ctx, node)); if (((_a = values.valid) === null || _a === void 0 ? void 0 : _a.length) && (!normalizedFQN || !values.valid.map(normalizeFQN).includes(normalizedFQN))) { return true; } return normalizedFQN && ((_b = values.invalid) === null || _b === void 0 ? void 0 : _b.map(normalizeFQN).includes(normalizedFQN)); } function normalizeFQN(fqn) { return fqn === null || fqn === void 0 ? void 0 : fqn.replace(/-/g, '_'); } class Result { constructor(ctx, node, status) { this.ctx = ctx; this.node = node; this.status = status; } get isFound() { return this.status === 'found'; } get isMissing() { return this.status === 'missing'; } get isTrue() { return this.isFound && isBooleanLiteral(this.node) && this.node.value; } ofType(type) { return this.isFound && this.node.type === type; } getArgument(position) { if (!this.isFound) { return this; } else if (this.node.type !== 'NewExpression' && this.node.type !== 'CallExpression') { return unknown(this.ctx, this.node); } const argument = this.node.arguments[position]; if (argument == null) { return missing(this.ctx, this.node); } else { return getResultOfExpression(this.ctx, argument); } } getProperty(propertyName) { if (!this.isFound) { return this; } else if (this.node.type !== 'ObjectExpression') { return unknown(this.ctx, this.node); } const property = getProperty$1(this.node, propertyName, this.ctx); if (property === undefined) { return unknown(this.ctx, this.node); } else if (property === null) { return missing(this.ctx, this.node); } else { return getResultOfExpression(this.ctx, property.value); } } getMemberObject() { if (!this.isFound) { return this; } else if (this.node.type !== 'MemberExpression') { return unknown(this.ctx, this.node); } else { return getResultOfExpression(this.ctx, this.node.object).filter(n => n.type !== 'Super'); } } findInArray(closure) { var _a; if (!this.isFound) { return this; } else if (!isArrayExpression(this.node)) { return unknown(this.ctx, this.node); } let isMissing = true; for (const element of this.node.elements) { const result = element != null ? closure(getResultOfExpression(this.ctx, element)) : null; if (result === null || result === void 0 ? void 0 : result.isFound) { return result; } isMissing && (isMissing = (_a = result === null || result === void 0 ? void 0 : result.isMissing) !== null && _a !== void 0 ? _a : true); } return isMissing ? missing(this.ctx, this.node) : unknown(this.ctx, this.node); } everyStringLiteral(closure) { if (!this.isFound) { return false; } else if (isStringLiteral(this.node)) { return closure(this.node); } else if (!isArrayExpression(this.node)) { return false; } for (const element of this.node.elements) { const child = element == null ? null : getResultOfExpression(this.ctx, element); if (!(child === null || child === void 0 ? void 0 : child.isFound) || !isStringLiteral(child.node) || !closure(child.node)) { return false; } } return true; } asStringLiterals() { if (!this.isFound) { return []; } const values = []; if (isArrayExpression(this.node)) { for (const arg of this.node.elements) { const result = arg == null ? null : getResultOfExpression(this.ctx, arg); if ((result === null || result === void 0 ? void 0 : result.isFound) && isStringLiteral(result.node)) { values.push(result.node); } } } else if (isStringLiteral(this.node)) { values.push(this.node); } return values; } map(closure) { return !this.isFound ? null : closure(this.node); } filter(closure) { if (!this.isFound) { return this; } return !closure(this.node, this.ctx) ? unknown(this.ctx, this.node) : this; } } function unknown(ctx, node) { return new Result(ctx, node, 'unknown'); } function missing(ctx, node) { return new Result(ctx, node, 'missing'); } function found(ctx, node) { return new Result(ctx, node, 'found'); } function getResultOfExpression(ctx, node) { const value = getUniqueWriteUsageOrNode(ctx, node, true); return isUndefined(value) ? missing(ctx, value) : found(ctx, value); } const REST_API_PROPERTIES_POSITION = 2; const RESOURCE_ADD_RESOURCE_PROPERTIES_POSITION = 1; const RESOURCE_ADD_METHOD_POSITION = 2; const REST_API_ROOT_PROPERTY = 'root'; const DEFAULT_METHOD_OPTIONS = 'defaultMethodOptions'; const AUTHORIZATION_TYPE = 'authorizationType'; const NONE_AUTHORIZATION_TYPE = 'aws_cdk_lib.aws_apigateway.AuthorizationType.NONE'; const ADD_METHOD = 'addMethod'; const ADD_RESOURCE = 'addResource'; const GET_RESOURCE = 'getResource'; const PARENT_RESOURCE = 'parentResource'; const messages$5 = { publicApi: 'Make sure that creating public APIs is safe here.', omittedAuthorizationType: 'Omitting "authorizationType" disables authentication. Make sure it is safe here.', }; const apigatewayChecker = AwsCdkCheckArguments(['omittedAuthorizationType', 'publicApi'], true, AUTHORIZATION_TYPE, { primitives: { invalid: ['NONE'] } }); function consumersFactory(ctx) { const defaultAuthorizationTypes = new Map(); const restApiDefaultCollector = defaultsCollector(REST_API_PROPERTIES_POSITION); const resourceDefaultCollector = defaultsCollector(RESOURCE_ADD_RESOURCE_PROPERTIES_POSITION); return { 'aws_cdk_lib.aws_apigateway.CfnMethod': apigatewayChecker, 'aws_cdk_lib.aws_apigatewayv2.CfnRoute': apigatewayChecker, 'aws_cdk_lib.aws_apigateway.RestApi': restApiDefaultCollector, 'aws_cdk_lib.aws_apigateway.RestApi.root': { methods: [ADD_METHOD, ADD_RESOURCE, GET_RESOURCE, PARENT_RESOURCE], callExpression: (expr, _ctx, fqn) => { if (fqn.endsWith(ADD_METHOD)) { checkResourceMethod(expr); } else if (fqn.endsWith(ADD_RESOURCE)) { resourceDefaultCollector(expr); } }, }, }; function checkResourceMethod(expr) { const properties = getResultOfExpression(ctx, expr).getArgument(RESOURCE_ADD_METHOD_POSITION); const authorizationType = properties.getProperty(AUTHORIZATION_TYPE); if (authorizationType.isFound && isSensitiveAuthorizationType(authorizationType.node)) { ctx.report({ messageId: 'publicApi', node: authorizationType.node, }); } else if (authorizationType.isMissing) { const defaultAuthorizationType = getDefaultAuthorizationType(expr.callee); if (defaultAuthorizationType == null) { ctx.report({ messageId: 'omittedAuthorizationType', node: authorizationType.node, }); } else if (isSensitiveAuthorizationType(defaultAuthorizationType)) { ctx.report({ messageId: 'publicApi', node: expr, }); } } } function getDefaultAuthorizationType(node) { const resource = getUniqueWriteUsageOrNode(ctx, node); if (defaultAuthorizationTypes.has(resource)) { return defaultAuthorizationTypes.get(resource); } else if (isDefaultFromCallee(resource)) { return getDefaultAuthorizationType(resource.callee); } else if (isDefaultFromObject(resource, ADD_METHOD, ADD_RESOURCE, REST_API_ROOT_PROPERTY)) { return getDefaultAuthorizationType(resource.object); } else { return undefined; } } function defaultsCollector(position) { return (expr) => { const properties = getResultOfExpression(ctx, expr).getArgument(position); const defaultMethodOptions = properties.getProperty(DEFAULT_METHOD_OPTIONS); const authorizationType = defaultMethodOptions.getProperty(AUTHORIZATION_TYPE); if (authorizationType.isFound) { defaultAuthorizationTypes.set(expr, authorizationType.node); } }; } function isSensitiveAuthorizationType(node) { const fqn = normalizeFQN(getFullyQualifiedName(ctx, node)); return fqn === NONE_AUTHORIZATION_TYPE; } } function isDefaultFromObject(node, ...names) { return node.type === 'MemberExpression' && names.some(name => isMemberWithProperty$1(node, name)); } function isDefaultFromCallee(node) { return node.type === 'CallExpression' && isMethodCall(node); } const rule$4r = AwsCdkTemplate(consumersFactory, { meta: { messages: messages$5 } }); const PROPERTIES_POSITION$1 = 2; const PRIVATE_SUBNETS = [ 'aws_cdk_lib.aws_ec2.SubnetType.PRIVATE_ISOLATED', 'aws_cdk_lib.aws_ec2.SubnetType.PRIVATE_WITH_EGRESS', 'aws_cdk_lib.aws_ec2.SubnetType.PRIVATE_WITH_NAT', ]; const PUBLIC_SUBNET = 'aws_cdk_lib.aws_ec2.SubnetType.PUBLIC'; const rule$4q = AwsCdkTemplate({ 'aws-cdk-lib.aws-ec2.Instance': AwsCdkCheckArguments('publicNetwork', false, ['vpcSubnets', 'subnetType'], { fqns: { invalid: [PUBLIC_SUBNET] } }), 'aws-cdk-lib.aws-ec2.CfnInstance': checkCfnInstance, 'aws-cdk-lib.aws_rds.DatabaseInstance': checkDatabaseInstance, 'aws-cdk-lib.aws_rds.CfnDBInstance': AwsCdkCheckArguments('publicNetwork', false, 'publiclyAccessible', { primitives: { invalid: [true] } }), 'aws-cdk-lib.aws_dms.CfnReplicationInstance': AwsCdkCheckArguments('publicNetwork', true, 'publiclyAccessible', { primitives: { invalid: [true] } }), }, { meta: { messages: { publicNetwork: 'Make sure allowing public network access is safe here.', }, }, }); function checkCfnInstance(expr, ctx) { const properties = getResultOfExpression(ctx, expr).getArgument(PROPERTIES_POSITION$1); const networkInterfaces = properties.getProperty('networkInterfaces'); const sensitiveNetworkInterface = networkInterfaces.findInArray(result => getSensitiveNetworkInterface(result, ctx)); if (sensitiveNetworkInterface.isFound) { ctx.report({ messageId: 'publicNetwork', node: sensitiveNetworkInterface.node, }); } } function getSensitiveNetworkInterface(networkInterface, ctx) { const associatePublicIpAddress = networkInterface.getProperty('associatePublicIpAddress'); if (associatePublicIpAddress.isTrue && !isFoundPrivateSubnet(networkInterface, ctx)) { return associatePublicIpAddress; } else { return null; } } function isFoundPrivateSubnet(networkInterface, ctx) { const subnetId = networkInterface.getProperty('subnetId'); const selectSubnetsCall = getSelectSubnetsCall(subnetId); const argument = selectSubnetsCall.getArgument(0); const subnetType = argument.getProperty('subnetType'); return subnetType.isFound && isPrivateSubnet(subnetType.node, ctx); } function getSelectSubnetsCall(subnetId) { let current = subnetId; while (current.ofType('MemberExpression')) { current = current.getMemberObject(); } return current.filter(n => n.type === 'CallExpression' && isCallingMethod(n, 1, 'selectSubnets')); } function checkDatabaseInstance(expr, ctx) { const properties = getResultOfExpression(ctx, expr).getArgument(PROPERTIES_POSITION$1); const vpcSubnets = properties.getProperty('vpcSubnets'); const subnetType = vpcSubnets.getProperty('subnetType'); const publiclyAccessible = properties.getProperty('publiclyAccessible'); if (subnetType.isFound && isPrivateSubnet(subnetType.node, ctx)) { return; } if (publiclyAccessible.isTrue && subnetType.isFound && isPublicSubnet(subnetType.node, ctx)) { ctx.report({ messageId: 'publicNetwork', node: publiclyAccessible.node, }); } else if (!publiclyAccessible.isFound && subnetType.isFound && isPublicSubnet(subnetType.node, ctx)) { ctx.report({ messageId: 'publicNetwork', node: subnetType.node, }); } } function isPrivateSubnet(node, ctx) { return PRIVATE_SUBNETS.some(net => { var _a; return net === ((_a = getFullyQualifiedName(ctx, node)) === null || _a === void 0 ? void 0 : _a.replace(/-/g, '_')); }); } function isPublicSubnet(node, ctx) { var _a; return PUBLIC_SUBNET === ((_a = getFullyQualifiedName(ctx, node)) === null || _a === void 0 ? void 0 : _a.replace(/-/g, '_')); } const rule$4p = AwsCdkTemplate({ 'aws-cdk-lib.aws-ec2.Volume': AwsCdkCheckArguments(['encryptionOmitted', 'encryptionDisabled'], true, 'encrypted', { primitives: { invalid: [false] } }), }, { meta: { messages: { encryptionDisabled: 'Make sure that using unencrypted volumes is safe here.', encryptionOmitted: 'Omitting "encrypted" disables volumes encryption. Make sure it is safe here.', }, }, }); const rule$4o = AwsCdkTemplate({ 'aws-cdk-lib.aws_efs.FileSystem': AwsCdkCheckArguments('FSEncryptionDisabled', false, 'encrypted', { primitives: { invalid: [false] } }), 'aws-cdk-lib.aws_efs.CfnFileSystem': AwsCdkCheckArguments(['CFSEncryptionOmitted', 'CFSEncryptionDisabled'], true, 'encrypted', { primitives: { valid: [true] } }), }, { meta: { messages: { FSEncryptionDisabled: 'Make sure that using unencrypted file systems is safe here.', CFSEncryptionDisabled: 'Make sure that using unencrypted file systems is safe here.', CFSEncryptionOmitted: 'Omitting "encrypted" disables EFS encryption. Make sure it is safe here.', }, }, }); const PROPERTIES_POSITION = 0; const POLICY_DOCUMENT_STATEMENT_PROPERTY = 'Statement'; const ARN_PRINCIPAL$1 = 'aws_cdk_lib.aws_iam.ArnPrincipal'; const STAR_PRINCIPAL = 'aws_cdk_lib.aws_iam.StarPrincipal'; const ANY_PRINCIPAL = 'aws_cdk_lib.aws_iam.AnyPrincipal'; const ANY_LITERAL = '*'; const PROPERTIES_OPTIONS = { effect: { property: 'effect', type: 'FullyQualifiedName', allowValue: 'aws_cdk_lib.aws_iam.Effect.ALLOW', }, actions: { property: 'actions', }, resources: { property: 'resources', }, conditions: { property: 'conditions', }, principals: { property: 'principals', type: 'FullyQualifiedName', anyValues: [STAR_PRINCIPAL, ANY_PRINCIPAL, ARN_PRINCIPAL$1], }, }; const JSON_OPTIONS = { effect: { property: 'Effect', type: 'string', allowValue: 'Allow', }, actions: { property: 'Action', }, resources: { property: 'Resource', }, conditions: { property: 'Condition', }, principals: { property: 'Principal', type: 'json', }, }; function AwsIamPolicyTemplate(statementChecker) { return AwsCdkTemplate({ 'aws-cdk-lib.aws-iam.PolicyStatement': { newExpression: policyStatementChecker(statementChecker, PROPERTIES_OPTIONS), functionName: 'fromJson', callExpression: policyStatementChecker(statementChecker, JSON_OPTIONS), }, 'aws-cdk-lib.aws-iam.PolicyDocument': { functionName: 'fromJson', callExpression: policyDocumentChecker(statementChecker, JSON_OPTIONS), }, }, { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, }); } function getSensitiveEffect(properties, ctx, options) { const effect = properties.getProperty(options.effect.property); return effect.filter(node => { if (options.effect.type === 'FullyQualifiedName') { const fullyQualifiedName = normalizeFQN(getFullyQualifiedName(ctx, node)); return fullyQualifiedName === options.effect.allowValue; } else { return isStringLiteral(node) && node.value === options.effect.allowValue; } }); } function isAnyLiteral(literal) { return literal.value === ANY_LITERAL; } function policyDocumentChecker(statementChecker, options) { return (expr, ctx) => { const call = getResultOfExpression(ctx, expr); const properties = call.getArgument(PROPERTIES_POSITION); const statements = properties.getProperty(POLICY_DOCUMENT_STATEMENT_PROPERTY); if (statements.isFound) { for (const node of flattenArgs(ctx, [statements.node])) { statementChecker(node, ctx, options); } } }; } function policyStatementChecker(statementChecker, options) { return (expr, ctx) => { const call = getResultOfExpression(ctx, expr); const properties = call.getArgument(PROPERTIES_POSITION); if (properties.isFound) { statementChecker(properties.node, ctx, options); } }; } const MESSAGES$3 = { message: 'Make sure granting all privileges is safe here.', secondary: 'Related effect', }; const rule$4n = AwsIamPolicyTemplate(allPrivilegesStatementChecker); function allPrivilegesStatementChecker(expr, ctx, options) { const properties = getResultOfExpression(ctx, expr); const effect = getSensitiveEffect(properties, ctx, options); const action = getSensitiveAction$1(properties, options); if (effect.isMissing && action) { ctx.report({ message: toEncodedMessage$1(MESSAGES$3.message), node: action, }); } else if (effect.isFound && action) { ctx.report({ message: toEncodedMessage$1(MESSAGES$3.message, [effect.node], [MESSAGES$3.secondary]), node: action, }); } } function getSensitiveAction$1(properties, options) { return getActionLiterals(properties, options).find(isAnyLiteral); } function getActionLiterals(properties, options) { return properties.getProperty(options.actions.property).asStringLiterals(); } const MESSAGES$2 = { message: 'Make sure granting access to all resources is safe here.', secondary: 'Related effect', }; const KMS_PREFIX = 'kms:'; const rule$4m = AwsIamPolicyTemplate(allResourcesAccessibleStatementCheck); function allResourcesAccessibleStatementCheck(expr, ctx, options) { const properties = getResultOfExpression(ctx, expr); const effect = getSensitiveEffect(properties, ctx, options); const resource = getSensitiveResource$1(properties, options); if (isException$3(properties, options)) { return; } if (effect.isMissing && resource) { ctx.report({ message: toEncodedMessage$1(MESSAGES$2.message), node: resource, }); } else if (effect.isFound && resource) { ctx.report({ message: toEncodedMessage$1(MESSAGES$2.message, [effect.node], [MESSAGES$2.secondary]), node: resource, }); } } function isException$3(properties, options) { return properties.getProperty(options.actions.property).everyStringLiteral(isKmsAction); } function isKmsAction(action) { return action.value.startsWith(KMS_PREFIX); } function getSensitiveResource$1(properties, options) { return getSensitiveResources(properties, options).find(isAnyLiteral); } function getSensitiveResources(properties, options) { return properties.getProperty(options.resources.property).asStringLiterals(); } const SENSITIVE_RESOURCE = /^(\*|arn:[^:]*:[^:]*:[^:]*:[^:]*:(role|user|group)\/\*)$/; const SENSITIVE_ACTIONS = [ 'cloudformation:CreateStack', 'datapipeline:CreatePipeline', 'datapipeline:PutPipelineDefinition', 'ec2:RunInstances', 'glue:CreateDevEndpoint', 'glue:UpdateDevEndpoint', 'iam:AddUserToGroup', 'iam:AttachGroupPolicy', 'iam:AttachRolePolicy', 'iam:AttachUserPolicy', 'iam:CreateAccessKey', 'iam:CreateLoginProfile', 'iam:CreatePolicyVersion', 'iam:PassRole', 'iam:PutGroupPolicy', 'iam:PutRolePolicy', 'iam:PutUserPolicy', 'iam:SetDefaultPolicyVersion', 'iam:UpdateAssumeRolePolicy', 'iam:UpdateLoginProfile', 'lambda:AddPermission', 'lambda:CreateEventSourceMapping', 'lambda:CreateFunction', 'lambda:InvokeFunction', 'lambda:UpdateFunctionCode', 'sts:AssumeRole', ]; const MESSAGES$1 = { message: (attackVectorName) => `This policy is vulnerable to the "${attackVectorName}" privilege escalation vector. ` + 'Remove permissions or restrict the set of resources they apply to.', secondary: 'Permissions are granted on all resources.', }; const rule$4l = AwsIamPolicyTemplate(privilegeEscalationStatementChecker); function privilegeEscalationStatementChecker(expr, ctx, options) { const properties = getResultOfExpression(ctx, expr); const effect = getSensitiveEffect(properties, ctx, options); const resource = getSensitiveResource(properties, options); const action = getSensitiveAction(properties, options); if (!hasExceptionProperties(properties, options) && (effect.isFound || effect.isMissing) && resource && action) { ctx.report({ message: toEncodedMessage$1(MESSAGES$1.message(action.value), [action], [MESSAGES$1.secondary]), node: resource, }); } } function getSensitiveAction(properties, options) { const actions = properties.getProperty(options.actions.property); return actions.asStringLiterals().find(isSensitiveAction); } function getSensitiveResource(properties, options) { const resources = properties.getProperty(options.resources.property); return resources.asStringLiterals().find(isSensitiveResource); } function isSensitiveAction(action) { return SENSITIVE_ACTIONS.includes(action.value); } function isSensitiveResource(resource) { return SENSITIVE_RESOURCE.test(resource.value); } function hasExceptionProperties(properties, options) { const exceptionProperties = [options.principals.property, options.conditions.property]; return exceptionProperties.some(prop => !properties.getProperty(prop).isMissing); } const AWS_PRINCIPAL_PROPERTY = 'AWS'; const ARN_PRINCIPAL = 'aws_cdk_lib.aws_iam.ArnPrincipal'; const MESSAGES = { message: 'Make sure granting public access is safe here.', secondary: 'Related effect', }; const rule$4k = AwsIamPolicyTemplate(publicAccessStatementChecker); function publicAccessStatementChecker(expr, ctx, options) { const properties = getResultOfExpression(ctx, expr); const effect = getSensitiveEffect(properties, ctx, options); const principal = getSensitivePrincipal(properties, ctx, options); if (effect.isMissing && principal) { ctx.report({ message: toEncodedMessage$1(MESSAGES.message), node: principal, }); } else if (effect.isFound && principal) { ctx.report({ message: toEncodedMessage$1(MESSAGES.message, [effect.node], [MESSAGES.secondary]), node: principal, }); } } function getSensitivePrincipal(properties, ctx, options) { const principal = properties.getProperty(options.principals.property); if (!principal.isFound) { return null; } else if (options.principals.type === 'FullyQualifiedName') { return getSensitivePrincipalFromFullyQualifiedName(ctx, principal.node, options); } else { return getSensitivePrincipalFromJson(ctx, principal.node); } } function getSensitivePrincipalFromFullyQualifiedName(ctx, node, options) { return getPrincipalNewExpressions(node).find(expr => isSensitivePrincipalNewExpression(ctx, expr, options)); } function getPrincipalNewExpressions(node) { const newExpressions = []; if (isArrayExpression(node)) { for (const element of node.elements) { if ((element === null || element === void 0 ? void 0 : element.type) === 'NewExpression') { newExpressions.push(element); } } } return newExpressions; } function getSensitivePrincipalFromJson(ctx, node) { return getPrincipalLiterals(node, ctx).find(isAnyLiteral); } function isSensitivePrincipalNewExpression(ctx, newExpression, options) { var _a; return ((_a = options.principals.anyValues) !== null && _a !== void 0 ? _a : []).some(anyValue => { if (anyValue === ARN_PRINCIPAL) { const argument = newExpression.arguments[0]; return isStringLiteral(argument) && isAnyLiteral(argument); } else { return anyValue === normalizeFQN(getFullyQualifiedName(ctx, newExpression.callee)); } }); } function getPrincipalLiterals(node, ctx) { const literals = []; if (isStringLiteral(node)) { literals.push(node); } else { const awsLiterals = getResultOfExpression(ctx, node) .getProperty(AWS_PRINCIPAL_PROPERTY) .asStringLiterals(); literals.push(...awsLiterals); } return literals; } const DOMAIN_PROPS_POSITION = 2; const ENABLED_PROPERTY = 'enabled'; const OPEN_SEARCH = 'OpenSearch'; const ELASTIC_SEARCH = 'Elasticsearch'; const rule$4j = AwsCdkTemplate({ 'aws-cdk-lib.aws-opensearchservice.Domain': domainChecker({ encryptionProperty: 'encryptionAtRest', version: { valueType: 'EngineVersion', property: 'version', defaultValue: OPEN_SEARCH, }, }), 'aws-cdk-lib.aws-opensearchservice.CfnDomain': domainChecker({ encryptionProperty: 'encryptionAtRestOptions', version: { valueType: 'string', property: 'engineVersion', defaultValue: OPEN_SEARCH, }, }), 'aws-cdk-lib.aws-elasticsearch.Domain': domainChecker({ encryptionProperty: 'encryptionAtRest', version: { valueType: 'ElasticsearchVersion', property: 'version', defaultValue: ELASTIC_SEARCH, }, }), 'aws-cdk-lib.aws-elasticsearch.CfnDomain': domainChecker({ encryptionProperty: 'encryptionAtRestOptions', version: { valueType: 'string', property: 'elasticsearchVersion', defaultValue: ELASTIC_SEARCH, }, }), }, { meta: { messages: { encryptionDisabled: 'Make sure that using unencrypted {{search}} domains is safe here.', encryptionOmitted: 'Omitting {{encryptionPropertyName}} causes encryption of data at rest to be ' + 'disabled for this {{search}} domain. Make sure it is safe here.', }, }, }); function domainChecker(options) { return (expr, ctx) => { var _a; const call = getResultOfExpression(ctx, expr); const argument = call.getArgument(DOMAIN_PROPS_POSITION); const encryption = argument.getProperty(options.encryptionProperty); const version = argument.getProperty(options.version.property); const isEnabled = encryption.getProperty(ENABLED_PROPERTY); const search = (_a = version.map(getSearchEngine)) !== null && _a !== void 0 ? _a : options.version.defaultValue; if (isEnabled.isMissing) { ctx.report({ messageId: 'encryptionOmitted', node: isEnabled.node, data: { encryptionPropertyName: options.encryptionProperty, search, }, }); } else if (isEnabled.isFound && isUnencrypted(isEnabled.node)) { ctx.report({ messageId: 'encryptionDisabled', node: isEnabled.node, data: { search, }, }); } function isUnencrypted(node) { return isBooleanLiteral(node) && !node.value; } function getSearchEngine(node) { var _a; let version; if (options.version.valueType === 'string' && isStringLiteral(node)) { version = `${options.version.property}.${node.value}`; } else { version = getFullyQualifiedName(ctx, node); } for (const name of (_a = version === null || version === void 0 ? void 0 : version.toLowerCase().split('.').reverse()) !== null && _a !== void 0 ? _a : []) { if (name.includes('opensearch')) { return OPEN_SEARCH; } else if (name.includes('elasticsearch')) { return ELASTIC_SEARCH; } } return null; } }; } const CfnDBCluster = 'CfnDBCluster'; const CfnDBInstance = 'CfnDBInstance'; const DatabaseCluster = 'DatabaseCluster'; const DatabaseClusterFromSnapshot = 'DatabaseClusterFromSnapshot'; const DatabaseInstance = 'DatabaseInstance'; const DatabaseInstanceReadReplica = 'DatabaseInstanceReadReplica'; const rule$4i = AwsCdkTemplate({ 'aws-cdk-lib.aws_rds.CfnDBCluster': checkStorage(CfnDBCluster), 'aws-cdk-lib.aws_rds.CfnDBInstance': checkStorage(CfnDBInstance), 'aws-cdk-lib.aws_rds.DatabaseCluster': checkStorage(DatabaseCluster), 'aws-cdk-lib.aws_rds.DatabaseClusterFromSnapshot': checkStorage(DatabaseClusterFromSnapshot), 'aws-cdk-lib.aws_rds.DatabaseInstance': checkStorage(DatabaseInstance), 'aws-cdk-lib.aws_rds.DatabaseInstanceReadReplica': checkStorage(DatabaseInstanceReadReplica), }, { meta: { messages: { unsafe: 'Make sure that using unencrypted storage is safe here.', omitted: 'Omitting storageEncrypted disables RDS encryption. Make sure it is safe here.', }, }, }); const PROPS_ARGUMENT_POSITION = 2; function checkStorage(storage) { return (expr, ctx) => { const argument = expr.arguments[PROPS_ARGUMENT_POSITION]; const props = getValueOfExpression(ctx, argument, 'ObjectExpression'); if (isUnresolved(argument, props)) { return; } if (props === undefined) { report(expr.callee, 'omitted'); return; } if (isException(storage, props)) { return; } const propertyKey = getProperty$1(props, 'storageEncrypted', ctx); if (propertyKey === null) { report(props, 'omitted'); } if (!propertyKey) { return; } const propertyValue = getUniqueWriteUsageOrNode(ctx, propertyKey.value); if (isFalseLiteral(propertyValue)) { report(propertyKey.value, 'unsafe'); return; } function isUnresolved(node, value) { return (node === null || node === void 0 ? void 0 : node.type) === 'Identifier' && !isUndefined(node) && value === undefined; } function isException(storage, props) { if (![ DatabaseCluster, DatabaseClusterFromSnapshot, DatabaseInstance, DatabaseInstanceReadReplica, ].includes(storage)) { return false; } const exceptionKey = getProperty$1(props, 'storageEncryptionKey', ctx); if (exceptionKey == null) { return false; } const exceptionValue = getUniqueWriteUsageOrNode(ctx, exceptionKey.value); if (exceptionValue.type !== 'NewExpression') { return false; } const fqn = normalizeFQN(getFullyQualifiedName(ctx, exceptionValue.callee)); return fqn === 'aws_cdk_lib.aws_kms.Key' || fqn === 'aws_cdk_lib.aws_kms.Alias'; } function report(node, messageId) { ctx.report({ messageId, node, }); } }; } const TYPES_WITH_CONNECTIONS = [ 'aws_cdk_lib.aws_docdb.DatabaseCluster.connections', 'aws_cdk_lib.aws_lambdaPythonAlpha.PythonFunction.connections', 'aws_cdk_lib.aws_batchAlpha.ComputeEnvironment.connections', 'aws_cdk_lib.aws_efs.FileSystem.connections', 'aws_cdk_lib.aws_lambdaGoAlpha.GoFunction.connections', 'aws_cdk_lib.aws_ecs.ExternalService.connections', 'aws_cdk_lib.aws_ecs.FargateService.connections', 'aws_cdk_lib.aws_ecs.Cluster.connections', 'aws_cdk_lib.aws_ecs.Ec2Service.connections', 'aws_cdk_lib.aws_elasticsearch.Domain.connections', 'aws_cdk_lib.aws_neptuneAlpha.DatabaseCluster.connections', 'aws_cdk_lib.aws_eks.FargateCluster.connections', 'aws_cdk_lib.aws_eks.Cluster.connections', 'aws_cdk_lib.aws_codebuild.PipelineProject.connections', 'aws_cdk_lib.aws_codebuild.Project.connections', 'aws_cdk_lib.aws_rds.DatabaseInstance.connections', 'aws_cdk_lib.aws_rds.DatabaseInstanceReadReplica.connections', 'aws_cdk_lib.aws_rds.DatabaseCluster.connections', 'aws_cdk_lib.aws_rds.ServerlessClusterFromSnapshot.connections', 'aws_cdk_lib.aws_rds.DatabaseProxy.connections', 'aws_cdk_lib.aws_rds.DatabaseInstanceFromSnapshot.connections', 'aws_cdk_lib.aws_rds.ServerlessCluster.connections', 'aws_cdk_lib.aws_rds.DatabaseClusterFromSnapshot.connections', 'aws_cdk_lib.aws_lambdaNodejs.NodejsFunction.connections', 'aws_cdk_lib.aws_fsx.LustreFileSystem.connections', 'aws_cdk_lib.aws_ec2.BastionHostLinux.connections', 'aws_cdk_lib.aws_ec2.ClientVpnEndpoint.connections', 'aws_cdk_lib.aws_ec2.Instance.connections', 'aws_cdk_lib.aws_ec2.LaunchTemplate.connections', 'aws_cdk_lib.aws_ec2.SecurityGroup.connections', 'aws_cdk_lib.aws_kinesisfirehoseAlpha.DeliveryStream.connections', 'aws_cdk_lib.aws_stepfunctionsTasks.SageMakerCreateTrainingJob.connections', 'aws_cdk_lib.aws_stepfunctionsTasks.SageMakerCreateModel.connections', 'aws_cdk_lib.aws_stepfunctionsTasks.EcsRunTask.connections', 'aws_cdk_lib.aws_redshiftAlpha.Cluster.connections', 'aws_cdk_lib.aws_opensearchservice.Domain.connections', 'aws_cdk_lib.aws_secretsmanager.HostedRotation.connections', 'aws_cdk_lib.aws_mskAlpha.Cluster.connections', 'aws_cdk_lib.triggers.TriggerFunction.connections', 'aws_cdk_lib.aws_autoscaling.AutoScalingGroup.connections', 'aws_cdk_lib.aws_syntheticsAlpha.Canary.connections', 'aws_cdk_lib.aws_cloudfront.experimental.EdgeFunction.connections', 'aws_cdk_lib.aws_lambda.Function.connections', 'aws_cdk_lib.aws_lambda.DockerImageFunction.connections', 'aws_cdk_lib.aws_lambda.SingletonFunction.connections', 'aws_cdk_lib.aws_lambda.Alias.connections', 'aws_cdk_lib.aws_lambda.Version.connections', 'aws_cdk_lib.aws_ec2.Connections', ]; const badPorts = [22, 3389]; const badIpsV4 = ['0.0.0.0/0']; const badIpsV6 = ['::/0']; const badFQNProtocols = [ 'aws_cdk_lib.aws_ec2.Protocol.ALL', 'aws_cdk_lib.aws_ec2.Protocol.TCP', ]; const badProtocols = ['6', 'tcp', 'TCP']; const templateCallback = {}; for (const type of TYPES_WITH_CONNECTIONS) { templateCallback[`${type}.allowFrom`] = { callExpression: checkAllowFrom }; templateCallback[`${type}.allowFromAnyIpv4`] = { callExpression: checkAllowFromAnyIpv4 }; } templateCallback['aws_cdk_lib.aws_ec2.Connections.allowDefaultPortFrom'] = { callExpression: (expr, ctx) => { if (isBadEc2Peer(ctx, expr.arguments[0])) { checkConstructorDefaultPort(ctx, expr); } }, }; templateCallback['aws_cdk_lib.aws_ec2.Connections.allowDefaultPortFromAnyIpv4'] = { callExpression: (expr, ctx) => { checkConstructorDefaultPort(ctx, expr); }, }; templateCallback['aws_cdk_lib.aws_ec2.SecurityGroup.addIngressRule'] = { callExpression: checkAllowFrom, }; templateCallback['aws_cdk_lib.aws_ec2.CfnSecurityGroup'] = (expr, ctx) => { const params = expr.arguments[2]; const objExpr = getValueOfExpression(ctx, params, 'ObjectExpression', true); if (!objExpr) { return; } const ingressProp = getProperty$1(objExpr, 'securityGroupIngress', ctx); if (!ingressProp) { return; } const arrExpr = getValueOfExpression(ctx, ingressProp.value, 'ArrayExpression', true); if (arrExpr) { for (const ingressGroup of arrExpr.elements) { if (ingressGroup) { checkIngressObject(ctx, ingressGroup); } } } }; templateCallback['aws_cdk_lib.aws_ec2.CfnSecurityGroupIngress'] = (expr, ctx) => { checkIngressObject(ctx, expr.arguments[2]); }; const rule$4h = AwsCdkTemplate(templateCallback, { meta: { messages: { allowFromAnyIpv4: 'Change this method for "allowFrom" and set "other" to a subset of trusted IP addresses.', allowFrom: 'Change this IP range to a subset of trusted IP addresses.', }, }, }); const invalidDefaultPortChecker = AwsCdkCheckArguments('allowFrom', false, 'defaultPort', { customChecker: isBadEc2Port }, true, 0); function checkConstructorDefaultPort(ctx, node) { const newExpr = getValueOfExpression(ctx, reduceToIdentifier(node.callee), 'NewExpression', true); if (newExpr && invalidDefaultPortChecker(newExpr, ctx)) { ctx.report({ messageId: 'allowFromAnyIpv4', node: node.callee }); } } function checkAllowFrom(expr, ctx) { const badPeer = isBadEc2Peer(ctx, expr.arguments[0]); const badPort = isBadEc2Port(ctx, expr.arguments[1]); if (badPort && badPeer) { ctx.report({ messageId: 'allowFrom', node: expr.arguments[0] }); } } function checkAllowFromAnyIpv4(expr, ctx) { const badPort = isBadEc2Port(ctx, expr.arguments[0]); if (badPort) { ctx.report({ messageId: 'allowFromAnyIpv4', node: expr.callee }); } } function checkIngressObject(ctx, node) { var _a, _b, _c; const objExpr = getValueOfExpression(ctx, node, 'ObjectExpression', true); if (!objExpr) { return; } const ipPropertyV4 = getPropertyValue(ctx, objExpr, 'cidrIp'); const ipPropertyV6 = getPropertyValue(ctx, objExpr, 'cidrIpv6'); const ipProtocol = (_a = getPropertyValue(ctx, objExpr, 'ipProtocol')) === null || _a === void 0 ? void 0 : _a.value; const cidrIpV4 = ipPropertyV4 === null || ipPropertyV4 === void 0 ? void 0 : ipPropertyV4.value; const cidrIpV6 = ipPropertyV6 === null || ipPropertyV6 === void 0 ? void 0 : ipPropertyV6.value; const fromPort = Number.parseInt((_b = getPropertyValue(ctx, objExpr, 'fromPort')) === null || _b === void 0 ? void 0 : _b.value); const toPort = Number.parseInt((_c = getPropertyValue(ctx, objExpr, 'toPort')) === null || _c === void 0 ? void 0 : _c.value); if (disallowedIpV4(cidrIpV4) && (ipProtocol === '-1' || (disallowedProtocol(ipProtocol) && disallowedPort(fromPort, toPort)))) { ctx.report({ messageId: 'allowFrom', node: ipPropertyV4 }); } if (disallowedIpV6(cidrIpV6) && (ipProtocol === '-1' || (disallowedProtocol(ipProtocol) && disallowedPort(fromPort, toPort)))) { ctx.report({ messageId: 'allowFrom', node: ipPropertyV6 }); } } function disallowedPortObject(ctx, node) { var _a, _b; const objExpr = getValueOfExpression(ctx, node, 'ObjectExpression', true); if (!objExpr) { return false; } const protocol = getProperty$1(objExpr, 'protocol', ctx); if (!protocol) { return false; } const protocolValue = getUniqueWriteUsageOrNode(ctx, protocol.value, true); if (isUnresolved(protocolValue, ctx) || isUndefined(protocolValue)) { return false; } const protocolFQN = normalizeFQN(getFullyQualifiedName(ctx, protocolValue)); if (protocolFQN && badFQNProtocols.includes(protocolFQN)) { const fromPort = Number.parseInt((_a = getPropertyValue(ctx, objExpr, 'fromPort')) === null || _a === void 0 ? void 0 : _a.value); const toPort = Number.parseInt((_b = getPropertyValue(ctx, objExpr, 'toPort')) === null || _b === void 0 ? void 0 : _b.value); return disallowedPort(fromPort, toPort); } return false; } function isBadEc2Peer(ctx, node) { var _a, _b; const fqn = normalizeFQN(getFullyQualifiedName(ctx, node)); if (fqn === 'aws_cdk_lib.aws_ec2.Peer.anyIpv4' || fqn === 'aws_cdk_lib.aws_ec2.Peer.anyIpv6') { return true; } if (fqn === 'aws_cdk_lib.aws_ec2.Peer.ipv4') { return disallowedIpV4((_a = getArgumentValue(ctx, node)) === null || _a === void 0 ? void 0 : _a.value); } if (fqn === 'aws_cdk_lib.aws_ec2.Peer.ipv6') { return disallowedIpV6((_b = getArgumentValue(ctx, node)) === null || _b === void 0 ? void 0 : _b.value); } return false; } function isBadEc2Port(ctx, node) { var _a, _b, _c; const fqn = normalizeFQN(getFullyQualifiedName(ctx, node)); if (fqn === 'aws_cdk_lib.aws_ec2.Port.allTcp' || fqn === 'aws_cdk_lib.aws_ec2.Port.allTraffic') { return true; } if (fqn === 'aws_cdk_lib.aws_ec2.Port.tcp') { return disallowedPort((_a = getArgumentValue(ctx, node)) === null || _a === void 0 ? void 0 : _a.value); } if (fqn === 'aws_cdk_lib.aws_ec2.Port.tcpRange') { const startRange = (_b = getArgumentValue(ctx, node)) === null || _b === void 0 ? void 0 : _b.value; const endRange = (_c = getArgumentValue(ctx, node, 1)) === null || _c === void 0 ? void 0 : _c.value; return disallowedPort(startRange, endRange); } if (fqn === 'aws_cdk_lib.aws_ec2.Port') { const portParams = getArgument(ctx, node); if (portParams) { return disallowedPortObject(ctx, portParams); } } return false; } function getArgument(ctx, node, position = 0) { if (!node || isUndefined(node) || isUnresolved(node, ctx)) { return undefined; } const callExpr = getUniqueWriteUsageOrNode(ctx, node, true); if (isUnresolved(callExpr, ctx) || isUndefined(callExpr) || (callExpr.type !== 'CallExpression' && callExpr.type !== 'NewExpression')) { return undefined; } const argument = callExpr.arguments[position]; const argumentValue = getUniqueWriteUsageOrNode(ctx, argument, true); if (isUnresolved(argumentValue, ctx) || isUndefined(argumentValue)) { return undefined; } return argumentValue; } function getArgumentValue(ctx, node, position = 0) { const argument = getArgument(ctx, node, position); return argument ? getLiteralValue$1(ctx, argument) : undefined; } function getPropertyValue(ctx, node, propertyName) { const property = getProperty$1(node, propertyName, ctx); if (!property) { return undefined; } const propertyValue = getUniqueWriteUsageOrNode(ctx, property.value, true); if (isUnresolved(propertyValue, ctx) || isUndefined(propertyValue)) { return undefined; } return getLiteralValue$1(ctx, propertyValue); } function disallowedPort(startRange, endRange) { if (startRange != null && endRange != null) { return badPorts.some(port => port >= startRange && port <= endRange); } if (startRange != null && endRange == null) { return badPorts.some(port => port === startRange); } return false; } function disallowedIpV4(ip) { return ip ? badIpsV4.includes(ip) : false; } function disallowedIpV6(ip) { return ip ? badIpsV6.includes(ip) : false; } function disallowedProtocol(protocol) { return protocol ? badProtocols.includes(protocol) : false; } function S3BucketTemplate(callback, metadata = { meta: {} }) { return { ...metadata, create(context) { return { NewExpression: (node) => { if (isS3BucketConstructor(context, node)) { callback(node, context); } }, }; }, }; } function isS3BucketConstructor(context, node) { return normalizeFQN(getFullyQualifiedName(context, node)) === 'aws_cdk_lib.aws_s3.Bucket'; } function isS3BucketDeploymentConstructor(context, node) { return (normalizeFQN(getFullyQualifiedName(context, node)) === 'aws_cdk_lib.aws_s3_deployment.BucketDeployment'); } function getProperty(context, bucket, key) { const args = bucket.arguments; const optionsArg = args[2]; const options = getValueOfExpression(context, optionsArg, 'ObjectExpression'); if (options == null) { return null; } return options.properties.find(property => isProperty(property) && isIdentifier(property.key, key)); } function findPropagatedSetting(sensitiveProperty, propagatedValue) { const propagated = { locations: [], messages: [] }; const isPropagatedProperty = sensitiveProperty.value !== propagatedValue; if (isPropagatedProperty) { propagated.locations = [getNodeParent(propagatedValue)]; propagated.messages = ['Propagated setting.']; } return propagated; } const messages$4 = { accessLevel: (param) => `Make sure granting ${param} access is safe here.`, unrestricted: 'Make sure allowing unrestricted access to objects from this bucket is safe here.', }; const ACCESS_CONTROL_KEY = 'accessControl'; const INVALID_ACCESS_CONTROL_VALUES = ['PUBLIC_READ', 'PUBLIC_READ_WRITE', 'AUTHENTICATED_READ']; const PUBLIC_READ_ACCESS_KEY = 'publicReadAccess'; const INVALID_PUBLIC_READ_ACCESS_VALUE = true; const rule$4g = { create(context) { return mergeRules(s3BucketConstructorRule.create(context), s3BucketDeploymentConstructorRule.create(context), handleGrantPublicAccess.create(context)); }, meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, }; const s3BucketConstructorRule = S3BucketTemplate((bucketConstructor, context) => { for (const value of INVALID_ACCESS_CONTROL_VALUES) { checkConstantParam(context, bucketConstructor, ACCESS_CONTROL_KEY, [ 'BucketAccessControl', value, ]); } checkBooleanParam(context, bucketConstructor, PUBLIC_READ_ACCESS_KEY, INVALID_PUBLIC_READ_ACCESS_VALUE); }); const s3BucketDeploymentConstructorRule = { create(context) { return { NewExpression: (node) => { if (isS3BucketDeploymentConstructor(context, node)) { for (const value of INVALID_ACCESS_CONTROL_VALUES) { checkConstantParam(context, node, ACCESS_CONTROL_KEY, ['BucketAccessControl', value]); } } }, }; }, }; function checkBooleanParam(context, bucketConstructor, propName, propValue) { const property = getProperty(context, bucketConstructor, propName); if (property == null) { return; } const propertyLiteralValue = getValueOfExpression(context, property.value, 'Literal'); if ((propertyLiteralValue === null || propertyLiteralValue === void 0 ? void 0 : propertyLiteralValue.value) === propValue) { const secondary = findPropagatedSetting(property, propertyLiteralValue); context.report({ message: toEncodedMessage$1(messages$4.unrestricted, secondary.locations, secondary.messages), node: property, }); } } function checkConstantParam(context, bucketConstructor, propName, paramQualifiers) { const property = getProperty(context, bucketConstructor, propName); if (property == null) { return; } const propertyLiteralValue = getValueOfExpression(context, property.value, 'MemberExpression'); if (propertyLiteralValue !== undefined && normalizeFQN(getFullyQualifiedName(context, propertyLiteralValue)) === `aws_cdk_lib.aws_s3.${paramQualifiers.join('.')}`) { const secondary = findPropagatedSetting(property, propertyLiteralValue); context.report({ message: toEncodedMessage$1(messages$4.accessLevel(paramQualifiers[paramQualifiers.length - 1]), secondary.locations, secondary.messages), node: property, }); } } const handleGrantPublicAccess = { create(context) { return { CallExpression: (node) => { if (!isMethodCall(node)) { return; } const { object, property } = node.callee; const isGrantPublicAccessMethodCall = isIdentifier(property, 'grantPublicAccess'); if (!isGrantPublicAccessMethodCall) { return; } const variableAssignment = getUniqueWriteUsageOrNode(context, object); const isS3bucketInstance = variableAssignment.type === 'NewExpression' && isS3BucketConstructor(context, variableAssignment); if (!isS3bucketInstance) { return; } context.report({ message: toEncodedMessage$1(messages$4.unrestricted), node: property, }); }, }; }, }; const ENFORCE_SSL_KEY = 'enforceSSL'; const messages$3 = { authorized: 'Make sure authorizing HTTP requests is safe here.', omitted: "Omitting 'enforceSSL' authorizes HTTP requests. Make sure it is safe here.", }; const rule$4f = S3BucketTemplate((bucket, context) => { const enforceSSLProperty = getProperty(context, bucket, ENFORCE_SSL_KEY); if (enforceSSLProperty == null) { context.report({ message: messages$3['omitted'], node: bucket.callee, }); return; } const enforceSSLValue = getValueOfExpression(context, enforceSSLProperty.value, 'Literal'); if ((enforceSSLValue === null || enforceSSLValue === void 0 ? void 0 : enforceSSLValue.value) === false) { context.report({ message: messages$3['authorized'], node: enforceSSLProperty, }); } }); const BLOCK_PUBLIC_ACCESS_KEY = 'blockPublicAccess'; const BLOCK_PUBLIC_ACCESS_PROPERTY_KEYS = [ 'blockPublicAcls', 'blockPublicPolicy', 'ignorePublicAcls', 'restrictPublicBuckets', ]; const messages$2 = { omitted: 'No Public Access Block configuration prevents public ACL/policies ' + 'to be set on this S3 bucket. Make sure it is safe here.', public: 'Make sure allowing public ACL/policies to be set is safe here.', }; const rule$4e = S3BucketTemplate((bucket, context) => { const blockPublicAccess = getProperty(context, bucket, BLOCK_PUBLIC_ACCESS_KEY); if (blockPublicAccess == null) { context.report({ message: toEncodedMessage$1(messages$2['omitted']), node: bucket.callee, }); } else { checkBlockPublicAccessValue(blockPublicAccess); checkBlockPublicAccessConstructor(blockPublicAccess); } function checkBlockPublicAccessValue(blockPublicAccess) { const blockPublicAccessMember = getValueOfExpression(context, blockPublicAccess.value, 'MemberExpression'); if (blockPublicAccessMember !== undefined && normalizeFQN(getFullyQualifiedName(context, blockPublicAccessMember)) === 'aws_cdk_lib.aws_s3.BlockPublicAccess.BLOCK_ACLS') { const propagated = findPropagatedSetting(blockPublicAccess, blockPublicAccessMember); context.report({ message: toEncodedMessage$1(messages$2['public'], propagated.locations, propagated.messages), node: blockPublicAccess, }); } } function checkBlockPublicAccessConstructor(blockPublicAccess) { const blockPublicAccessNew = getValueOfExpression(context, blockPublicAccess.value, 'NewExpression'); if (blockPublicAccessNew !== undefined && isS3BlockPublicAccessConstructor(blockPublicAccessNew)) { const blockPublicAccessConfig = getValueOfExpression(context, blockPublicAccessNew.arguments[0], 'ObjectExpression'); if (blockPublicAccessConfig === undefined) { context.report({ message: toEncodedMessage$1(messages$2['omitted']), node: blockPublicAccessNew, }); } else { BLOCK_PUBLIC_ACCESS_PROPERTY_KEYS.forEach(key => checkBlockPublicAccessConstructorProperty(blockPublicAccessConfig, key)); } } function checkBlockPublicAccessConstructorProperty(blockPublicAccessConfig, key) { const blockPublicAccessProperty = blockPublicAccessConfig.properties.find(property => isProperty(property) && isIdentifier(property.key, key)); if (blockPublicAccessProperty !== undefined) { const blockPublicAccessValue = getValueOfExpression(context, blockPublicAccessProperty.value, 'Literal'); if ((blockPublicAccessValue === null || blockPublicAccessValue === void 0 ? void 0 : blockPublicAccessValue.value) === false) { const propagated = findPropagatedSetting(blockPublicAccessProperty, blockPublicAccessValue); context.report({ message: toEncodedMessage$1(messages$2['public'], propagated.locations, propagated.messages), node: blockPublicAccessProperty, }); } } } function isS3BlockPublicAccessConstructor(expr) { return (expr.callee.type === 'MemberExpression' && normalizeFQN(getFullyQualifiedName(context, expr.callee)) === 'aws_cdk_lib.aws_s3.BlockPublicAccess'); } } }, { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, }); const ENCRYPTED_KEY = 'encryption'; const messages$1 = { unencrypted: 'Objects in the bucket are not encrypted. Make sure it is safe here.', omitted: 'Omitting "encryption" disables server-side encryption. Make sure it is safe here.', }; const rule$4d = S3BucketTemplate((bucket, context) => { const encryptedProperty = getProperty(context, bucket, ENCRYPTED_KEY); if (encryptedProperty == null) { context.report({ message: toEncodedMessage$1(messages$1['omitted'], [], []), node: bucket.callee, }); return; } const encryptedValue = getValueOfExpression(context, encryptedProperty.value, 'MemberExpression'); if (encryptedValue && isUnencrypted(encryptedValue)) { const propagated = findPropagatedSetting(encryptedProperty, encryptedValue); context.report({ message: toEncodedMessage$1(messages$1['unencrypted'], propagated.locations, propagated.messages), node: encryptedProperty, }); } function isUnencrypted(encrypted) { return (normalizeFQN(getFullyQualifiedName(context, encrypted)) === 'aws_cdk_lib.aws_s3.BucketEncryption.UNENCRYPTED'); } }, { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, }); const VERSIONED_KEY = 'versioned'; const messages = { unversioned: 'Make sure using unversioned S3 bucket is safe here.', omitted: 'Omitting the "versioned" argument disables S3 bucket versioning. Make sure it is safe here.', secondary: 'Propagated setting', }; const rule$4c = S3BucketTemplate((bucketConstructor, context) => { const versionedProperty = getProperty(context, bucketConstructor, VERSIONED_KEY); if (versionedProperty == null) { context.report({ message: toEncodedMessage$1(messages.omitted), node: bucketConstructor.callee, }); return; } const propertyLiteralValue = getValueOfExpression(context, versionedProperty.value, 'Literal'); if ((propertyLiteralValue === null || propertyLiteralValue === void 0 ? void 0 : propertyLiteralValue.value) === false) { const secondary = { locations: [], messages: [] }; const isPropagatedProperty = versionedProperty.value !== propertyLiteralValue; if (isPropagatedProperty) { secondary.locations = [getNodeParent(propertyLiteralValue)]; secondary.messages = [messages.secondary]; } context.report({ message: toEncodedMessage$1(messages.unversioned, secondary.locations, secondary.messages), node: versionedProperty, }); } }, { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, }); const rule$4b = AwsCdkTemplate({ 'aws-cdk-lib.aws_sagemaker.CfnNotebookInstance': AwsCdkCheckArguments('CfnNotebookInstance', true, 'kmsKeyId'), }, { meta: { messages: { CfnNotebookInstance: 'Omitting "kmsKeyId" disables encryption of SageMaker notebook instances. Make sure it is safe here.', }, }, }); const rule$4a = AwsCdkTemplate({ 'aws-cdk-lib.aws_sns.Topic': AwsCdkCheckArguments('SNSTopic', true, 'masterKey'), 'aws-cdk-lib.aws_sns.CfnTopic': AwsCdkCheckArguments('SNSCfnTopic', true, 'kmsMasterKeyId'), }, { meta: { messages: { SNSTopic: 'Omitting "masterKey" disables SNS topics encryption. Make sure it is safe here.', SNSCfnTopic: 'Omitting "kmsMasterKeyId" disables SNS topics encryption. Make sure it is safe here.', }, }, }); const rule$49 = AwsCdkTemplate({ 'aws-cdk-lib.aws-sqs.Queue': AwsCdkCheckArguments(['OmittedQueue', 'DisabledQueue'], true, 'encryption', { fqns: { invalid: ['aws-cdk-lib.aws-sqs.QueueEncryption.UNENCRYPTED'] } }), 'aws-cdk-lib.aws-sqs.CfnQueue': AwsCdkCheckArguments('CfnQueue', true, 'kmsMasterKeyId'), }, { meta: { messages: { CfnQueue: 'Omitting "kmsMasterKeyId" disables SQS queues encryption. Make sure it is safe here.', OmittedQueue: 'Omitting "encryption" disables SQS queues encryption. Make sure it is safe here.', DisabledQueue: 'Setting "encryption" to "QueueEncryption.UNENCRYPTED" disables SQS queues encryption.' + 'Make sure it is safe here.', }, }, }); const BITWISE_AND_OR = ['&', '|']; const BITWISE_OPERATORS = [ '&', '|', '^', '~', '<<', '>>', '>>>', '&=', '|=', '^=', '<<=', '>>=', '>>>=', ]; const rule$48 = { create(context) { const isNumeric = getNumericTypeChecker(context); let lonelyBitwiseAndOr = null; let lonelyBitwiseAndOrAncestors = []; let fileContainsSeveralBitwiseOperations = false; return { BinaryExpression(node) { const expression = node; if (!lonelyBitwiseAndOr && BITWISE_AND_OR.includes(expression.operator) && !isNumeric(expression.left) && !isNumeric(expression.right)) { lonelyBitwiseAndOr = expression; lonelyBitwiseAndOrAncestors = [...context.sourceCode.getAncestors(node)]; } else if (BITWISE_OPERATORS.includes(expression.operator)) { fileContainsSeveralBitwiseOperations = true; } }, 'Program:exit'() { if (!fileContainsSeveralBitwiseOperations && lonelyBitwiseAndOr && insideCondition(lonelyBitwiseAndOr, lonelyBitwiseAndOrAncestors)) { const op = lonelyBitwiseAndOr.operator; const operatorToken = context.sourceCode.getTokenAfter(lonelyBitwiseAndOr.left); if (operatorToken) { context.report({ loc: operatorToken.loc, message: `Review this use of bitwise "${op}" operator; conditional "${op}${op}" might have been intended.`, }); } } }, }; }, }; function insideCondition(node, ancestors) { let child = node; for (let i = ancestors.length - 1; i >= 0; i--) { const parent = ancestors[i]; if (parent.type === 'IfStatement' || parent.type === 'ForStatement' || parent.type === 'WhileStatement' || parent.type === 'DoWhileStatement' || parent.type === 'ConditionalExpression') { return parent.test === child; } child = parent; } return false; } function getNumericTypeChecker(context) { const services = context.sourceCode.parserServices; if (!!services && !!services.program && !!services.esTreeNodeToTSNodeMap) { return (node) => isNumericType(getTypeFromTreeNode$1(node, services)); } else { const numericTypes = ['number', 'bigint']; return (node) => node.type === 'Literal' ? numericTypes.includes(typeof node.value) : false; } function isNumericType(type) { return ((type.getFlags() & (ts__namespace.TypeFlags.NumberLike | ts__namespace.TypeFlags.BigIntLike)) !== 0 || (type.isUnionOrIntersection() && !!type.types.find(isNumericType))); } } const rule$47 = { meta: { messages: { provideDefault: "Provide a default value for '{{parameter}}' so that " + 'the logic of the function is more evident when this parameter is missing. ' + 'Consider defining another function if providing default value is not possible.', }, }, create(context) { return { 'FunctionDeclaration, FunctionExpression, ArrowFunctionExpression': (node) => { const functionLike = node; for (const param of functionLike.params) { if (param.type === 'Identifier' && isOptionalBoolean(param)) { context.report({ messageId: 'provideDefault', data: { parameter: param.name, }, node: param, }); } } }, }; }, }; function isOptionalBoolean(node) { return usesQuestionOptionalSyntax(node) || usesUnionUndefinedOptionalSyntax(node); } function usesQuestionOptionalSyntax(node) { return (!!node.optional && !!node.typeAnnotation && node.typeAnnotation.typeAnnotation.type === 'TSBooleanKeyword'); } function usesUnionUndefinedOptionalSyntax(node) { if (!!node.typeAnnotation && node.typeAnnotation.typeAnnotation.type === 'TSUnionType') { const types = node.typeAnnotation.typeAnnotation.types; return (types.length === 2 && types.some(tp => tp.type === 'TSBooleanKeyword') && types.some(tp => tp.type === 'TSUndefinedKeyword')); } return false; } function decorate$H(rule) { return interceptReport(rule, reportExempting$a(isOpeningBracket)); } function reportExempting$a(exemptionCondition) { return (context, reportDescriptor) => { if (exemptionCondition(reportDescriptor.messageId)) { context.report(reportDescriptor); } }; } function isOpeningBracket(messageId) { return messageId !== 'nextLineClose'; } const rule$46 = decorate$H(eslintRules['brace-style']); const rule$45 = { meta: { messages: { moveArguments: 'Make those call arguments start on line {{line}}.', moveTemplateLiteral: 'Make this template literal start on line {{line}}.', }, }, create(context) { const sourceCode = context.sourceCode; return { CallExpression: (node) => { const call = node; if (call.callee.type !== 'CallExpression' && call.arguments.length === 1) { const callee = getCallee(call); const parenthesis = sourceCode.getLastTokenBetween(callee, call.arguments[0], isClosingParen); const calleeLastLine = (parenthesis !== null && parenthesis !== void 0 ? parenthesis : sourceCode.getLastToken(callee)).loc.end.line; const { start } = sourceCode.getTokenAfter(callee, isNotClosingParen).loc; if (calleeLastLine !== start.line) { const { end } = sourceCode.getLastToken(call).loc; if (end.line !== start.line) { reportIssue$2('moveArguments', start, calleeLastLine, context); } else { reportIssue$2('moveArguments', { start, end }, calleeLastLine, context); } } } }, TaggedTemplateExpression(node) { const { quasi } = node; const tokenBefore = sourceCode.getTokenBefore(quasi); if (tokenBefore && quasi.loc && tokenBefore.loc.end.line !== quasi.loc.start.line) { const loc = { start: quasi.loc.start, end: { line: quasi.loc.start.line, column: quasi.loc.start.column + 1, }, }; reportIssue$2('moveTemplateLiteral', loc, tokenBefore.loc.start.line, context); } }, }; }, }; function getCallee(call) { var _a; const node = call; return ((_a = node.typeArguments) !== null && _a !== void 0 ? _a : node.callee); } function isClosingParen(token) { return token.type === 'Punctuator' && token.value === ')'; } function isNotClosingParen(token) { return !isClosingParen(token); } function reportIssue$2(messageId, loc, line, context) { context.report({ messageId, data: { line: line.toString(), }, loc, }); } const HELMET$7 = 'helmet'; const EXPECT_CERTIFICATE_TRANSPARENCY = 'expectCt'; const rule$44 = Express.SensitiveMiddlewarePropertyRule(findFalseCertificateTransparencyPropertyFromHelmet, `Make sure disabling Certificate Transparency monitoring is safe here.`); function findFalseCertificateTransparencyPropertyFromHelmet(context, node) { let sensitive; const { callee, arguments: args } = node; if (getFullyQualifiedName(context, callee) === HELMET$7 && args.length === 1 && args[0].type === 'ObjectExpression') { sensitive = getPropertyWithValue(context, args[0], EXPECT_CERTIFICATE_TRANSPARENCY, false); } return sensitive ? [sensitive] : []; } const message$4 = 'Refactor this uncertain assertion; it can succeed for multiple reasons.'; const rule$43 = { create(context) { if (!Chai.isImported(context)) { return {}; } return { ExpressionStatement: (node) => { const elements = retrieveAssertionChainElements(node.expression); if (elements.length > 1 && (isIdentifier(elements[0].identifier, 'expect') || getElementIndex(elements, 'should') >= 0)) { checkNotThrow(context, elements); checkNotInclude(context, elements); checkNotHaveProperty(context, elements); checkNotHaveOwnPropertyDescriptor(context, elements); checkNotHaveMembers(context, elements); checkChangeBy(context, elements); checkNotIncDec(context, elements); checkNotBy(context, elements); checkNotFinite(context, elements); } }, }; }, }; function checkNotThrow(context, elements) { checkWithCondition(context, elements, 'not', 'throw', args => !!args && args.length > 0); } function checkNotInclude(context, elements) { checkWithCondition(context, elements, 'not', 'include', args => !!args && args.length > 0 && args[0].type === 'ObjectExpression'); } function checkNotHaveProperty(context, elements) { checkWithCondition(context, elements, 'not', 'property', args => !!args && args.length > 1); } function checkNotHaveOwnPropertyDescriptor(context, elements) { checkWithCondition(context, elements, 'not', 'ownPropertyDescriptor', args => !!args && args.length > 1); } function checkNotHaveMembers(context, elements) { checkWithCondition(context, elements, 'not', 'members'); } function checkChangeBy(context, elements) { checkWithCondition(context, elements, 'change', 'by'); } function checkNotIncDec(context, elements) { checkWithCondition(context, elements, 'not', 'increase'); checkWithCondition(context, elements, 'not', 'decrease'); } function checkNotBy(context, elements) { checkWithCondition(context, elements, 'not', 'by'); } function checkNotFinite(context, elements) { checkWithCondition(context, elements, 'not', 'finite'); } function checkWithCondition(context, elements, first, second, condition = () => true) { const firstIndex = getElementIndex(elements, first); const firstElement = elements[firstIndex]; const secondIndex = getElementIndex(elements, second); const secondElement = elements[secondIndex]; if (firstElement && secondElement && neighborIndexes(firstIndex, secondIndex, elements) && condition(secondElement.arguments)) { context.report({ message: message$4, loc: locFromTwoNodes(firstElement.identifier, secondElement.identifier), }); } } function neighborIndexes(firstIndex, secondIndex, elements) { if (firstIndex === secondIndex - 2) { return !elements[firstIndex + 1].arguments; } return firstIndex === secondIndex - 1; } function retrieveAssertionChainElements(node) { let currentNode = node; const result = []; let currentArguments = undefined; while (true) { if (isDotNotation(currentNode)) { result.push({ identifier: currentNode.property, arguments: currentArguments }); currentNode = currentNode.object; currentArguments = undefined; } else if (currentNode.type === 'CallExpression') { currentArguments = currentNode.arguments; currentNode = currentNode.callee; } else if (isIdentifier(currentNode)) { result.push({ identifier: currentNode, arguments: currentArguments }); break; } else { break; } } return result.reverse(); } function getElementIndex(elements, name) { return elements.findIndex(element => isIdentifier(element.identifier, name)); } function locFromTwoNodes(start, end) { return { start: start.loc.start, end: end.loc.end, }; } const rule$42 = { meta: { messages: { renameClass: 'Rename {{symbolType}} "{{symbol}}" to match the regular expression {{format}}.', }, schema: [ { type: 'object', properties: { format: { type: 'string', }, }, }, ], }, create(context) { return { ClassDeclaration: (node) => checkName(node, 'class', context), TSInterfaceDeclaration: (node) => checkName(node, 'interface', context), }; }, }; function checkName(node, declarationType, context) { const [{ format }] = context.options; if (node.id) { const name = node.id.name; if (!name.match(format)) { context.report({ messageId: 'renameClass', data: { symbol: name, symbolType: declarationType, format, }, node: node.id, }); } } } const rule$41 = { meta: { messages: { declareClass: 'Declare a "{{class}}" class and move this declaration of "{{declaration}}" into it.', }, }, create(context) { const services = context.sourceCode.parserServices; const isFunction = isRequiredParserServices(services) ? isFunctionType : isFunctionLike; return { AssignmentExpression: (node) => { const { left, right } = node; if (left.type === 'MemberExpression' && isFunction(right, services)) { const [member, prototype] = [left.object, left.property]; if (member.type === 'MemberExpression' && prototype.type === 'Identifier') { const [klass, property] = [member.object, member.property]; if (klass.type === 'Identifier' && property.type === 'Identifier' && property.name === 'prototype') { context.report({ messageId: 'declareClass', data: { class: klass.name, declaration: prototype.name, }, node: left, }); } } } }, }; }, }; function isFunctionType(node, services) { const type = getTypeFromTreeNode$1(node, services); return type.symbol && (type.symbol.flags & ts__namespace.SymbolFlags.Function) !== 0; } function isFunctionLike(node, _services) { return ['FunctionDeclaration', 'FunctionExpression', 'ArrowFunctionExpression'].includes(node.type); } const noScriptUrlRule = eslintRules['no-script-url']; const rule$40 = { meta: { messages: { safeCode: 'Make sure that this dynamic injection or execution of code is safe.', unexpectedScriptURL: "Make sure that 'javascript:' code is safe as it is a form of eval().", }, }, create(context) { return { CallExpression: (node) => checkCallExpression$4(node, context), NewExpression: (node) => checkCallExpression$4(node, context), ...noScriptUrlRule.create(context), }; }, }; function checkCallExpression$4(node, context) { if (node.callee.type === 'Identifier') { const { name } = node.callee; if ((name === 'eval' || name === 'Function') && hasAtLeastOneVariableArgument(node.arguments)) { context.report({ messageId: 'safeCode', node: node.callee, }); } } } function hasAtLeastOneVariableArgument(args) { return !!args.find(arg => !isLiteral$1(arg)); } function isLiteral$1(node) { if (node.type === 'Literal') { return true; } if (node.type === 'TemplateLiteral') { return node.expressions.length === 0; } return false; } const rule$3$ = { meta: { messages: { specifyCase: `Explicitly specify {{nesting}} separate cases that fall through; currently this case clause only works for "{{expression}}".`, }, }, create(context) { function reportIssue(node, clause, nestingLvl) { context.report({ messageId: 'specifyCase', data: { nesting: nestingLvl.toString(), expression: String(getTextFromNode(clause)), }, node, }); } function getTextFromNode(node) { if (node.type === 'Literal') { return node.value; } else { return context.sourceCode.getText(node); } } return { 'SwitchCase > SequenceExpression'(node) { const expressions = node.expressions; reportIssue(node, expressions[expressions.length - 1], expressions.length); }, 'SwitchCase > LogicalExpression'(node) { if (!isSwitchTrue(getEnclosingSwitchStatement(context, node))) { const firstElemAndNesting = getFirstElementAndNestingLevel(node, 0); if (firstElemAndNesting) { reportIssue(node, firstElemAndNesting[0], firstElemAndNesting[1] + 1); } } }, }; }, }; function getEnclosingSwitchStatement(context, node) { const ancestors = context.sourceCode.getAncestors(node); for (let i = ancestors.length - 1; i >= 0; i--) { if (ancestors[i].type === 'SwitchStatement') { return ancestors[i]; } } throw new Error('A switch case should have an enclosing switch statement'); } function isSwitchTrue(node) { return isLiteral$2(node.discriminant) && node.discriminant.value === true; } function getFirstElementAndNestingLevel(logicalExpression, currentLvl) { if (logicalExpression.operator === '||') { if (logicalExpression.left.type === 'LogicalExpression') { return getFirstElementAndNestingLevel(logicalExpression.left, currentLvl + 1); } else { return [logicalExpression.left, currentLvl + 1]; } } return undefined; } const rule$3_ = { meta: { schema: [ { type: 'object', properties: { regularExpression: { type: 'string', }, message: { type: 'string', }, flags: { type: 'string', }, }, }, ], }, create(context) { const options = context.options[0] || {}; const flags = options.flags || ''; const cleanedFlags = 'gimusy' .split('') .filter(c => flags.includes(c)) .join(''); const pattern = options.regularExpression ? new RegExp(options.regularExpression, cleanedFlags) : undefined; const message = options.message || 'The regular expression matches this comment.'; return { 'Program:exit': () => { context.sourceCode.getAllComments().forEach(comment => { const rawTextTrimmed = comment.value.trim(); if (pattern === null || pattern === void 0 ? void 0 : pattern.test(rawTextTrimmed)) { context.report({ message, loc: comment.loc, }); } }); }, }; }, }; const rule$3Z = createRegExpRule(context => { let flags; return { onRegExpLiteralEnter: (node) => { ({ flags } = node); }, onCharacterClassEnter: (node) => { checkBulkyAnyCharacterClass(node, flags, context); checkBulkyNumericCharacterClass(node, context); checkBulkyAlphaNumericCharacterClass(node, context); }, onQuantifierEnter: (node) => { checkBulkyQuantifier(node, context); }, }; }); function checkBulkyAnyCharacterClass(node, flags, context) { if (node.negate || node.elements.length !== 2) { return; } let hasLowerEscapeW = false; let hasUpperEscapeW = false; let hasLowerEscapeD = false; let hasUpperEscapeD = false; let hasLowerEscapeS = false; let hasUpperEscapeS = false; node.elements.forEach(element => { hasLowerEscapeW || (hasLowerEscapeW = element.type === 'CharacterSet' && element.kind === 'word' && !element.negate); hasUpperEscapeW || (hasUpperEscapeW = element.type === 'CharacterSet' && element.kind === 'word' && element.negate); hasLowerEscapeD || (hasLowerEscapeD = element.type === 'CharacterSet' && element.kind === 'digit' && !element.negate); hasUpperEscapeD || (hasUpperEscapeD = element.type === 'CharacterSet' && element.kind === 'digit' && element.negate); hasLowerEscapeS || (hasLowerEscapeS = element.type === 'CharacterSet' && element.kind === 'space' && !element.negate); hasUpperEscapeS || (hasUpperEscapeS = element.type === 'CharacterSet' && element.kind === 'space' && element.negate); }); const isBulkyAnyCharacterClass = (hasLowerEscapeW && hasUpperEscapeW) || (hasLowerEscapeD && hasUpperEscapeD) || (hasLowerEscapeS && hasUpperEscapeS && flags.dotAll); if (isBulkyAnyCharacterClass) { context.reportRegExpNode({ message: `Use concise character class syntax '.' instead of '${node.raw}'.`, node: context.node, regexpNode: node, }); } } function checkBulkyNumericCharacterClass(node, context) { if (node.elements.length === 1) { const [element] = node.elements; const hasDigit = element.type === 'CharacterClassRange' && element.raw === '0-9'; if (hasDigit) { const expected = node.negate ? '\\D' : '\\d'; const actual = node.raw; context.reportRegExpNode({ message: `Use concise character class syntax '${expected}' instead of '${actual}'.`, node: context.node, regexpNode: node, }); } } } function checkBulkyAlphaNumericCharacterClass(node, context) { if (node.elements.length === 4) { let hasDigit = false, hasLowerCase = false, hasUpperCase = false, hasUnderscore = false; for (const element of node.elements) { hasDigit || (hasDigit = element.type === 'CharacterClassRange' && element.raw === '0-9'); hasLowerCase || (hasLowerCase = element.type === 'CharacterClassRange' && element.raw === 'a-z'); hasUpperCase || (hasUpperCase = element.type === 'CharacterClassRange' && element.raw === 'A-Z'); hasUnderscore || (hasUnderscore = element.type === 'Character' && element.raw === '_'); } if (hasDigit && hasLowerCase && hasUpperCase && hasUnderscore) { const expected = node.negate ? '\\W' : '\\w'; const actual = node.raw; context.reportRegExpNode({ message: `Use concise character class syntax '${expected}' instead of '${actual}'.`, node: context.node, regexpNode: node, }); } } } function checkBulkyQuantifier(node, context) { const { raw } = node; let message; let bulkyQuantifier; if (/\{0,1\}\??$/.test(raw)) { bulkyQuantifier = { concise: '?', verbose: '{0,1}' }; } else if (/\{0,0\}\??$/.test(raw)) { message = `Remove redundant ${node.element.raw}{0,0}.`; } else if (/\{0\}\??$/.test(raw)) { message = `Remove redundant ${node.element.raw}{0}.`; } else if (/\{1,1\}\??$/.test(raw)) { message = 'Remove redundant quantifier {1,1}.'; } else if (/\{1\}\??$/.test(raw)) { message = 'Remove redundant quantifier {1}.'; } else if (/\{0,\}\??$/.test(raw)) { bulkyQuantifier = { concise: '*', verbose: '{0,}' }; } else if (/\{1,\}\??$/.test(raw)) { bulkyQuantifier = { concise: '+', verbose: '{1,}' }; } else if (/\{(\d+),\1\}\??$/.test(raw)) { bulkyQuantifier = { concise: `{${node.min}}`, verbose: `{${node.min},${node.min}}` }; } if (bulkyQuantifier) { message = `Use concise quantifier syntax '${bulkyQuantifier.concise}' instead of '${bulkyQuantifier.verbose}'.`; } if (message) { context.reportRegExpNode({ message, node: context.node, regexpNode: node, }); } } const rule$3Y = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { const sourceCode = context.sourceCode; return { IfStatement: (node) => { var _a; const ifStatement = node; const parent = getParent(context, node); if (parent && parent.type !== 'IfStatement') { const firstToken = sourceCode.getFirstToken(node); checkIndentation(firstToken, ifStatement.consequent, context); } if (ifStatement.alternate) { const elseToken = sourceCode.getTokenBefore(ifStatement.alternate, token => token.type === 'Keyword' && token.value === 'else'); const alternate = ifStatement.alternate; if (alternate.type === 'IfStatement') { checkIndentation(elseToken, alternate.consequent, context); } else { checkIndentation((_a = getPrecedingBrace(elseToken, sourceCode)) !== null && _a !== void 0 ? _a : elseToken, alternate, context, elseToken); } } }, 'WhileStatement, ForStatement, ForInStatement, ForOfStatement': (node) => { const firstToken = sourceCode.getFirstToken(node); checkIndentation(firstToken, node.body, context); }, }; }, }; function checkIndentation(firstToken, statement, context, tokenToReport = firstToken) { if (firstToken && tokenToReport && statement.type !== 'BlockStatement') { const firstStatementToken = context.sourceCode.getFirstToken(statement); if (firstStatementToken && firstToken.loc.start.column >= firstStatementToken.loc.start.column) { const message = `Use curly braces or indentation to denote the code conditionally ` + `executed by this "${tokenToReport.value}".`; context.report({ message: toEncodedMessage$1(message, [firstStatementToken]), loc: tokenToReport.loc, }); } } } function getPrecedingBrace(elseToken, sourceCode) { if (elseToken) { const tokenBeforeElse = sourceCode.getTokenBefore(elseToken); if ((tokenBeforeElse === null || tokenBeforeElse === void 0 ? void 0 : tokenBeforeElse.value) === '}' && tokenBeforeElse.loc.start.line === elseToken.loc.start.line) { return tokenBeforeElse; } } return undefined; } const MESSAGE$5 = 'Make sure confidential information is not logged here.'; const rule$3X = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { return { NewExpression: (node) => { const newExpression = node; const { callee } = newExpression; if (getFullyQualifiedName(context, callee) !== 'signale.Signale') { return; } if (newExpression.arguments.length === 0) { context.report({ node: callee, message: toEncodedMessage$1(MESSAGE$5, []) }); return; } const firstArgument = getValueOfExpression(context, newExpression.arguments[0], 'ObjectExpression'); if (!firstArgument) { return; } const secrets = getProperty$1(firstArgument, 'secrets', context); if (secrets && secrets.value.type === 'ArrayExpression' && secrets.value.elements.length === 0) { context.report({ node: callee, message: toEncodedMessage$1(MESSAGE$5, [secrets]), }); } else if (!secrets) { context.report({ node: callee, message: toEncodedMessage$1(MESSAGE$5, [firstArgument]), }); } }, }; }, }; const rule$3W = { meta: { messages: { removeInstantiationOf: 'Either remove this useless object instantiation of "{{constructor}}" or use it.', removeInstantiation: 'Either remove this useless object instantiation or use it.', }, }, create(context) { const sourceCode = context.sourceCode; return { 'ExpressionStatement > NewExpression': (node) => { if (isTestCode(context) || isTryable(node, context)) { return; } const { callee } = node; if (callee.type === 'Identifier' || callee.type === 'MemberExpression') { const calleeText = sourceCode.getText(callee); if (isException$2(context, callee, calleeText)) { return; } const reportLocation = { start: node.loc.start, end: callee.loc.end, }; reportIssue$1(reportLocation, `${calleeText}`, 'removeInstantiationOf', context); } else { const newToken = sourceCode.getFirstToken(node); reportIssue$1(newToken.loc, '', 'removeInstantiation', context); } }, }; }, }; function isTryable(node, context) { const ancestors = context.sourceCode.getAncestors(node); let parent = undefined; let child = node; while ((parent = ancestors.pop()) !== undefined) { if (parent.type === 'TryStatement' && parent.block === child) { return true; } child = parent; } return false; } function reportIssue$1(loc, objectText, messageId, context) { context.report({ messageId, data: { constructor: objectText, }, loc, }); } function isException$2(context, node, name) { if (name === 'Notification') { return true; } const fqn = getFullyQualifiedName(context, node); return fqn === 'vue' || fqn === '@ag-grid-community.core.Grid' || (fqn === null || fqn === void 0 ? void 0 : fqn.startsWith('aws-cdk-lib')); } const FORMIDABLE_MODULE$1 = 'formidable'; const KEEP_EXTENSIONS = 'keepExtensions'; const UPLOAD_DIR = 'uploadDir'; const MULTER_MODULE$1 = 'multer'; const STORAGE_OPTION = 'storage'; const DESTINATION_OPTION = 'destination'; const formidableObjects$1 = new Map(); const rule$3V = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { return { NewExpression(node) { checkCallExpression$3(context, node); }, CallExpression(node) { checkCallExpression$3(context, node); }, AssignmentExpression(node) { visitAssignment$1(context, node); }, Program() { formidableObjects$1.clear(); }, 'Program:exit'() { formidableObjects$1.forEach(value => report$4(context, value.uploadDirSet, value.keepExtensions, value.callExpression)); }, }; }, }; function checkCallExpression$3(context, callExpression) { const { callee } = callExpression; if (callee.type !== 'Identifier') { return; } const fqn = getFullyQualifiedName(context, callee); if (!fqn) { return; } const [moduleName] = fqn.split('.'); if (moduleName === FORMIDABLE_MODULE$1) { checkFormidable$1(context, callExpression); } if (moduleName === MULTER_MODULE$1) { checkMulter$1(context, callExpression); } } function checkFormidable$1(context, callExpression) { var _a; if (callExpression.arguments.length === 0) { const formVariable = getLhsVariable(context, callExpression); if (formVariable) { formidableObjects$1.set(formVariable, { uploadDirSet: false, keepExtensions: false, callExpression, }); } return; } const options = getValueOfExpression(context, callExpression.arguments[0], 'ObjectExpression'); if (options) { report$4(context, !!getProperty$1(options, UPLOAD_DIR, context), keepExtensionsValue((_a = getProperty$1(options, KEEP_EXTENSIONS, context)) === null || _a === void 0 ? void 0 : _a.value), callExpression); } } function checkMulter$1(context, callExpression) { var _a; if (callExpression.arguments.length === 0) { return; } const multerOptions = getValueOfExpression(context, callExpression.arguments[0], 'ObjectExpression'); if (!multerOptions) { return; } const storagePropertyValue = (_a = getProperty$1(multerOptions, STORAGE_OPTION, context)) === null || _a === void 0 ? void 0 : _a.value; if (storagePropertyValue) { const storageValue = getValueOfExpression(context, storagePropertyValue, 'CallExpression'); if (storageValue) { const diskStorageCallee = getDiskStorageCalleeIfUnsafeStorage(context, storageValue); if (diskStorageCallee) { report$4(context, false, false, callExpression, { node: diskStorageCallee, message: 'no destination specified', }); } } } } function getDiskStorageCalleeIfUnsafeStorage(context, storageCreation) { const { arguments: args, callee } = storageCreation; if (args.length > 0 && isMemberWithProperty(callee, 'diskStorage')) { const storageOptions = getValueOfExpression(context, args[0], 'ObjectExpression'); if (storageOptions && !getProperty$1(storageOptions, DESTINATION_OPTION, context)) { return callee; } } return false; } function isMemberWithProperty(expr, property) { return (expr.type === 'MemberExpression' && expr.property.type === 'Identifier' && expr.property.name === property); } function keepExtensionsValue(extensionValue) { if (extensionValue && extensionValue.type === 'Literal' && typeof extensionValue.value === 'boolean') { return extensionValue.value; } return false; } function visitAssignment$1(context, assignment) { const variableProperty = getVariablePropertyFromAssignment(context, assignment); if (!variableProperty) { return; } const { objectVariable, property } = variableProperty; const formOptions = formidableObjects$1.get(objectVariable); if (formOptions !== undefined) { if (property === UPLOAD_DIR) { formOptions.uploadDirSet = true; } if (property === KEEP_EXTENSIONS) { formOptions.keepExtensions = keepExtensionsValue(assignment.right); } } } function getVariablePropertyFromAssignment(context, assignment) { if (assignment.left.type !== 'MemberExpression') { return undefined; } const memberExpr = assignment.left; if (memberExpr.object.type === 'Identifier' && memberExpr.property.type === 'Identifier') { const objectVariable = getVariableFromName(context, memberExpr.object.name, memberExpr); if (objectVariable) { return { objectVariable, property: memberExpr.property.name }; } } return undefined; } function report$4(context, uploadDirSet, keepExtensions, callExpression, secondaryLocation) { let message; if (keepExtensions && uploadDirSet) { message = 'Restrict the extension of uploaded files.'; } else if (!keepExtensions && !uploadDirSet) { message = 'Restrict folder destination of uploaded files.'; } else if (keepExtensions && !uploadDirSet) { message = 'Restrict the extension and folder destination of uploaded files.'; } if (message) { if (secondaryLocation) { message = toEncodedMessage$1(message, [secondaryLocation.node], [secondaryLocation.message]); } else { message = toEncodedMessage$1(message, []); } context.report({ message, node: callExpression.callee, }); } } const FORMIDABLE_MODULE = 'formidable'; const MAX_FILE_SIZE = 'maxFileSize'; const FORMIDABLE_DEFAULT_SIZE = 200 * 1024 * 1024; const MULTER_MODULE = 'multer'; const LIMITS_OPTION = 'limits'; const FILE_SIZE_OPTION = 'fileSize'; const BODY_PARSER_MODULE = 'body-parser'; const BODY_PARSER_DEFAULT_SIZE = bytes.parse('100kb'); const formidableObjects = new Map(); const rule$3U = { meta: { messages: { safeLimit: 'Make sure the content length limit is safe here.', }, schema: [ { type: 'object', properties: { fileUploadSizeLimit: { type: 'integer', }, standardSizeLimit: { type: 'integer', }, }, }, ], }, create(context) { return { NewExpression(node) { checkCallExpression$2(context, node); }, CallExpression(node) { checkCallExpression$2(context, node); }, AssignmentExpression(node) { visitAssignment(context, node); }, Program() { formidableObjects.clear(); }, 'Program:exit'() { formidableObjects.forEach(value => report$3(context, value.nodeToReport, value.maxFileSize)); }, }; }, }; function checkCallExpression$2(context, callExpression) { const { callee } = callExpression; let identifierFromModule; if (callee.type === 'MemberExpression' && callee.object.type === 'Identifier') { identifierFromModule = callee.object; } else if (callee.type === 'Identifier') { identifierFromModule = callee; } else { return; } const fqn = getFullyQualifiedName(context, identifierFromModule); if (!fqn) { return; } const [moduleName] = fqn.split('.'); if (moduleName === FORMIDABLE_MODULE) { checkFormidable(context, callExpression); } if (moduleName === MULTER_MODULE) { checkMulter(context, callExpression); } if (moduleName === BODY_PARSER_MODULE) { checkBodyParser(context, callExpression); } } function checkFormidable(context, callExpression) { if (callExpression.arguments.length === 0) { const formVariable = getLhsVariable(context, callExpression); if (formVariable) { formidableObjects.set(formVariable, { maxFileSize: FORMIDABLE_DEFAULT_SIZE, nodeToReport: callExpression, }); } return; } const options = getValueOfExpression(context, callExpression.arguments[0], 'ObjectExpression'); if (options) { const property = getProperty$1(options, MAX_FILE_SIZE, context); checkSize(context, callExpression, property, FORMIDABLE_DEFAULT_SIZE); } } function checkMulter(context, callExpression) { var _a; if (callExpression.arguments.length === 0) { report$3(context, callExpression.callee); return; } const multerOptions = getValueOfExpression(context, callExpression.arguments[0], 'ObjectExpression'); if (!multerOptions) { return; } const limitsPropertyValue = (_a = getProperty$1(multerOptions, LIMITS_OPTION, context)) === null || _a === void 0 ? void 0 : _a.value; if (limitsPropertyValue && limitsPropertyValue.type === 'ObjectExpression') { const fileSizeProperty = getProperty$1(limitsPropertyValue, FILE_SIZE_OPTION, context); checkSize(context, callExpression, fileSizeProperty); } if (!limitsPropertyValue) { report$3(context, callExpression.callee); } } function checkBodyParser(context, callExpression) { if (callExpression.arguments.length === 0) { checkSize(context, callExpression, undefined, BODY_PARSER_DEFAULT_SIZE, true); return; } const options = getValueOfExpression(context, callExpression.arguments[0], 'ObjectExpression'); if (!options) { return; } const limitsProperty = getProperty$1(options, LIMITS_OPTION, context); checkSize(context, callExpression, limitsProperty, BODY_PARSER_DEFAULT_SIZE, true); } function checkSize(context, callExpr, property, defaultLimit, useStandardSizeLimit = false) { if (property) { const maxFileSizeValue = getSizeValue(context, property.value); if (maxFileSizeValue) { report$3(context, property, maxFileSizeValue, useStandardSizeLimit); } } else { report$3(context, callExpr, defaultLimit, useStandardSizeLimit); } } function visitAssignment(context, assignment) { const variableProperty = getVariablePropertyFromAssignment(context, assignment); if (!variableProperty) { return; } const { objectVariable, property } = variableProperty; const formOptions = formidableObjects.get(objectVariable); if (formOptions && property === MAX_FILE_SIZE) { const rhsValue = getSizeValue(context, assignment.right); if (rhsValue !== undefined) { formOptions.maxFileSize = rhsValue; formOptions.nodeToReport = assignment; } else { formidableObjects.delete(objectVariable); } } } function getSizeValue(context, node) { const literal = getValueOfExpression(context, node, 'Literal'); if (literal) { if (typeof literal.value === 'number') { return literal.value; } else if (typeof literal.value === 'string') { return bytes.parse(literal.value); } } return undefined; } function report$3(context, nodeToReport, size, useStandardSizeLimit = false) { const [{ fileUploadSizeLimit, standardSizeLimit }] = context.options; const limitToCompare = useStandardSizeLimit ? standardSizeLimit : fileUploadSizeLimit; if (!size || size > limitToCompare) { context.report({ messageId: 'safeLimit', node: nodeToReport, }); } } const HELMET$6 = 'helmet'; const CONTENT_SECURITY_POLICY$2 = 'contentSecurityPolicy'; const rule$3T = Express.SensitiveMiddlewarePropertyRule(findFalseContentSecurityPolicyPropertyFromHelmet, `Make sure not enabling content security policy fetch directives is safe here.`); function findFalseContentSecurityPolicyPropertyFromHelmet(context, node) { let sensitive; const { callee, arguments: args } = node; if (getFullyQualifiedName(context, callee) === HELMET$6 && args.length === 1 && args[0].type === 'ObjectExpression') { sensitive = getPropertyWithValue(context, args[0], CONTENT_SECURITY_POLICY$2, false); } return sensitive ? [sensitive] : []; } class CookieFlagCheck { constructor(context, flag) { this.context = context; this.flag = flag; this.issueMessage = `Make sure creating this cookie without the "${flag}" flag is safe.`; } checkCookieSession(callExpression) { this.checkSensitiveCookieArgument(callExpression, 0); } checkCookiesMethodCall(callExpression) { if (!isIdentifier(callExpression.callee.property, 'set')) { return; } this.checkSensitiveCookieArgument(callExpression, 2); } checkCsurf(callExpression) { const cookieProperty = this.checkSensitiveObjectArgument(callExpression, 0); if (cookieProperty) { const cookiePropertyLiteral = getValueOfExpression(this.context, cookieProperty.value, 'Literal'); if ((cookiePropertyLiteral === null || cookiePropertyLiteral === void 0 ? void 0 : cookiePropertyLiteral.value) === true) { this.context.report({ node: callExpression.callee, message: toEncodedMessage$1(this.issueMessage, [cookiePropertyLiteral]), }); } } } checkExpressSession(callExpression) { this.checkSensitiveObjectArgument(callExpression, 0); } checkSensitiveCookieArgument(callExpression, sensitiveArgumentIndex) { if (callExpression.arguments.length < sensitiveArgumentIndex + 1) { return; } const sensitiveArgument = callExpression.arguments[sensitiveArgumentIndex]; const cookieObjectExpression = getValueOfExpression(this.context, sensitiveArgument, 'ObjectExpression'); if (!cookieObjectExpression) { return; } this.checkFlagOnCookieExpression(cookieObjectExpression, sensitiveArgument, cookieObjectExpression, callExpression); } checkSensitiveObjectArgument(callExpression, argumentIndex) { if (callExpression.arguments.length < argumentIndex + 1) { return; } const firstArgument = callExpression.arguments[argumentIndex]; const objectExpression = getValueOfExpression(this.context, firstArgument, 'ObjectExpression'); if (!objectExpression) { return; } const cookieProperty = getProperty$1(objectExpression, 'cookie', this.context); if (!cookieProperty) { return; } const cookiePropertyValue = getValueOfExpression(this.context, cookieProperty.value, 'ObjectExpression'); if (cookiePropertyValue) { this.checkFlagOnCookieExpression(cookiePropertyValue, firstArgument, objectExpression, callExpression); return; } return cookieProperty; } checkFlagOnCookieExpression(cookiePropertyValue, firstArgument, objectExpression, callExpression) { const flagProperty = getProperty$1(cookiePropertyValue, this.flag, this.context); if (flagProperty) { const flagPropertyValue = getValueOfExpression(this.context, flagProperty.value, 'Literal'); if ((flagPropertyValue === null || flagPropertyValue === void 0 ? void 0 : flagPropertyValue.value) === false) { const secondaryLocations = [flagPropertyValue]; if (firstArgument !== objectExpression) { secondaryLocations.push(objectExpression); } this.context.report({ node: callExpression.callee, message: toEncodedMessage$1(this.issueMessage, secondaryLocations), }); } } } checkCookiesFromCallExpression(node) { const callExpression = node; const { callee } = callExpression; const fqn = getFullyQualifiedName(this.context, callee); if (fqn === 'cookie-session') { this.checkCookieSession(callExpression); return; } if (fqn === 'csurf') { this.checkCsurf(callExpression); return; } if (fqn === 'express-session') { this.checkExpressSession(callExpression); return; } if (callee.type === 'MemberExpression') { const objectValue = getValueOfExpression(this.context, callee.object, 'NewExpression'); if (objectValue && getFullyQualifiedName(this.context, objectValue.callee) === 'cookies') { this.checkCookiesMethodCall(callExpression); } } } } const rule$3S = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { return { CallExpression: (node) => new CookieFlagCheck(context, 'httpOnly').checkCookiesFromCallExpression(node), }; }, }; const rule$3R = { meta: { messages: { safeCookie: 'Make sure that cookie is written safely here.', }, }, create(context) { let usingExpressFramework = false; return { Program() { usingExpressFramework = false; }, Literal(node) { if (node.value === 'express') { usingExpressFramework = true; } }, AssignmentExpression(node) { const { left } = node; if (left.type === 'MemberExpression') { const { object, property } = left; if (isIdentifier(object, 'document') && isIdentifier(property, 'cookie')) { context.report({ messageId: 'safeCookie', node: left, }); } } }, CallExpression(node) { const { callee, arguments: args } = node; if (callee.type === 'MemberExpression' && usingExpressFramework && isIdentifier(callee.property, 'cookie', 'cookies')) { context.report({ messageId: 'safeCookie', node, }); } if (callee.type === 'MemberExpression' && isIdentifier(callee.property, 'setHeader') && isLiteral(args[0], 'Set-Cookie')) { context.report({ messageId: 'safeCookie', node: callee, }); } }, }; }, }; function isLiteral(node, value) { return node && node.type === 'Literal' && node.value === value; } const MESSAGE$4 = `Make sure that enabling CORS is safe here.`; const CORS_HEADER = 'Access-Control-Allow-Origin'; const rule$3Q = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { function report(node, ...secondaryLocations) { const message = toEncodedMessage$1(MESSAGE$4, secondaryLocations); context.report({ message, node }); } function isCorsCall(call) { return getFullyQualifiedName(context, call) === 'cors'; } return { CallExpression(node) { const call = node; if (isCorsCall(call)) { if (call.arguments.length === 0) { report(call); return; } const [arg] = call.arguments; let sensitiveCorsProperty = getSensitiveCorsProperty(arg, context); if (sensitiveCorsProperty) { report(sensitiveCorsProperty); } if ((arg === null || arg === void 0 ? void 0 : arg.type) === 'Identifier') { const usage = getUniqueWriteUsage(context, arg.name, arg); sensitiveCorsProperty = getSensitiveCorsProperty(usage, context); if (sensitiveCorsProperty) { report(sensitiveCorsProperty, arg); } } } if (isSettingCorsHeader(call)) { report(call); } }, ObjectExpression(node) { const objProperty = getProperty$1(node, CORS_HEADER, context); if (objProperty && isAnyDomain(objProperty.value)) { report(objProperty); } }, }; }, }; function isCorsHeader(node) { const header = node; return header && header.type === 'Literal' && header.value === CORS_HEADER; } function isAnyDomain(node) { const domain = node; return domain && domain.type === 'Literal' && domain.value === '*'; } function getSensitiveCorsProperty(node, context) { const originProperty = getProperty$1(node, 'origin', context); if (originProperty && isAnyDomain(originProperty.value)) { return originProperty; } return undefined; } function isSettingCorsHeader(call) { return isCorsHeader(call.arguments[0]) && isAnyDomain(call.arguments[1]); } const CSURF_MODULE = 'csurf'; const SAFE_METHODS = ['GET', 'HEAD', 'OPTIONS']; const rule$3P = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { let globalCsrfProtection = false; let importedCsrfMiddleware = false; function checkIgnoredMethods(node) { if (node.value.type === 'ArrayExpression') { const arrayExpr = node.value; const unsafeMethods = arrayExpr.elements .filter(isLiteral$2) .filter(e => typeof e.value === 'string' && !SAFE_METHODS.includes(e.value)); if (unsafeMethods.length > 0) { const [first, ...rest] = unsafeMethods; context.report({ message: toEncodedMessage$1('Make sure disabling CSRF protection is safe here.', rest), node: first, }); } } } function isCsurfMiddleware(node) { return node && getFullyQualifiedName(context, node) === CSURF_MODULE; } function checkCallExpression(callExpression) { const { callee } = callExpression; if (isRequireModule(callExpression, CSURF_MODULE)) { importedCsrfMiddleware = true; } if (getFullyQualifiedName(context, callee) === CSURF_MODULE) { const [args] = callExpression.arguments; const ignoredMethods = getProperty$1(args, 'ignoreMethods', context); if (ignoredMethods) { checkIgnoredMethods(ignoredMethods); } } if (callee.type === 'MemberExpression') { if (isIdentifier(callee.property, 'use') && flattenArgs(context, callExpression.arguments).find(isCsurfMiddleware)) { globalCsrfProtection = true; } if (isIdentifier(callee.property, 'post', 'put', 'delete', 'patch') && !globalCsrfProtection && importedCsrfMiddleware && !callExpression.arguments.some(arg => isCsurfMiddleware(arg))) { context.report({ message: toEncodedMessage$1('Make sure not using CSRF protection is safe here.', []), node: callee, }); } } } return { Program() { globalCsrfProtection = false; }, CallExpression(node) { checkCallExpression(node); }, ImportDeclaration(node) { if (node.source.value === CSURF_MODULE) { importedCsrfMiddleware = true; } }, }; }, }; const rule$3O = { meta: { schema: [ { type: 'object', properties: { threshold: { type: 'integer', }, }, }, { type: 'string', enum: [SONAR_RUNTIME], }, ], }, create(context) { const [{ threshold }] = context.options; let functionsWithParent; let functionsDefiningModule; let functionsImmediatelyInvoked; return { Program: () => { functionsWithParent = new Map(); functionsDefiningModule = []; functionsImmediatelyInvoked = []; }, 'Program:exit': () => { functionsWithParent.forEach((parent, func) => { if (!functionsDefiningModule.includes(func) && !functionsImmediatelyInvoked.includes(func)) { raiseOnUnauthorizedComplexity(func, parent, threshold, context); } }); }, 'FunctionDeclaration, FunctionExpression, ArrowFunctionExpression': (node) => functionsWithParent.set(node, getParent(context, node)), "CallExpression[callee.type='Identifier'][callee.name='define'] FunctionExpression": (node) => functionsDefiningModule.push(node), "NewExpression[callee.type='FunctionExpression'], CallExpression[callee.type='FunctionExpression']": (node) => functionsImmediatelyInvoked.push(node.callee), }; }, }; function raiseOnUnauthorizedComplexity(node, parent, threshold, context) { const tokens = computeCyclomaticComplexity(node, parent, context); const complexity = tokens.length; if (complexity > threshold) { context.report({ message: toEncodedMessage(complexity, threshold, tokens), loc: locations.getMainFunctionTokenLocation(node, parent, context), }); } } function toEncodedMessage(complexity, threshold, tokens) { const encodedMessage = { message: `Function has a complexity of ${complexity} which is greater than ${threshold} authorized.`, cost: complexity - threshold, secondaryLocations: tokens.map(toSecondaryLocation), }; return JSON.stringify(encodedMessage); } function toSecondaryLocation(token) { return { line: token.loc.start.line, column: token.loc.start.column, endLine: token.loc.end.line, endColumn: token.loc.end.column, message: '+1', }; } function computeCyclomaticComplexity(node, parent, context) { const visitor = new FunctionComplexityVisitor(node, parent, context); visitor.visit(); return visitor.getComplexityTokens(); } class FunctionComplexityVisitor { constructor(root, parent, context) { this.root = root; this.parent = parent; this.context = context; this.tokens = []; } visit() { const visitNode = (node) => { const { sourceCode } = this.context; let token; if (isFunctionNode(node)) { if (node !== this.root) { return; } else { token = { loc: locations.getMainFunctionTokenLocation(node, this.parent, this.context), }; } } else { switch (node.type) { case 'ConditionalExpression': token = sourceCode.getFirstTokenBetween(node.test, node.consequent, token => token.value === '?'); break; case 'SwitchCase': if (!node.test) { break; } case 'IfStatement': case 'ForStatement': case 'ForInStatement': case 'ForOfStatement': case 'WhileStatement': case 'DoWhileStatement': token = sourceCode.getFirstToken(node); break; case 'LogicalExpression': token = sourceCode.getTokenAfter(node.left, token => ['||', '&&'].includes(token.value) && token.type === 'Punctuator'); break; } } if (token) { this.tokens.push(token); } childrenOf$1(node, sourceCode.visitorKeys).forEach(visitNode); }; visitNode(this.root); } getComplexityTokens() { return this.tokens; } } const rule$3N = { meta: { messages: { defineLocally: 'Define this declaration in a local scope or bind explicitly the property to the global object.', }, }, create(context) { return { Program(node) { const scope = context.sourceCode.getScope(node); const moduleScope = findModuleScope(context); moduleScope === null || moduleScope === void 0 ? void 0 : moduleScope.variables.forEach(variable => { var _a; if (scope.variables.find(global => global.name === variable.name)) { return; } for (const def of variable.defs) { const defNode = def.node; if (def.type === 'FunctionName' || (def.type === 'Variable' && ((_a = def.parent) === null || _a === void 0 ? void 0 : _a.kind) === 'var' && !isRequire(def.node.init))) { context.report({ node: defNode, messageId: 'defineLocally', }); return; } } }); }, }; }, }; function findModuleScope(context) { return context.sourceCode.scopeManager.scopes.find(s => s.type === 'module'); } function isRequire(node) { return ((node === null || node === void 0 ? void 0 : node.type) === 'CallExpression' && node.arguments.length === 1 && isIdentifier(node.callee, 'require')); } const NUM_ARGS_REDUX_REDUCER = 2; function decorate$G(rule) { return interceptReport(rule, reportExempting$9(isReduxReducer)); } function reportExempting$9(exemptionCondition) { return (context, reportDescriptor) => { var _a, _b; if ('node' in reportDescriptor) { const node = reportDescriptor['node']; const scope = context.sourceCode.getScope(node); const variable = scope.variables.find(value => isIdentifier(node.left, value.name)); const enclosingFunction = (_b = (_a = variable === null || variable === void 0 ? void 0 : variable.defs) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.node; if (enclosingFunction && !exemptionCondition(enclosingFunction)) { context.report(reportDescriptor); } } }; } function isReduxReducer(enclosingFunction) { if (enclosingFunction.params.length === NUM_ARGS_REDUX_REDUCER) { const [firstParam, secondParam] = enclosingFunction.params; return (firstParam.type === 'AssignmentPattern' && isIdentifier(firstParam.left, 'state') && isIdentifier(secondParam, 'action')); } return false; } const rule$3M = decorate$G(tsEslintRules['default-param-last']); const rule$3L = { meta: { messages: { deprecation: '{{deprecation}}', }, }, create(context) { const services = context.sourceCode.parserServices; if (!isRequiredParserServices(services)) { return {}; } return { Program: () => { const program = services.program; const checker = program.getTypeChecker(); const sourceFile = program.getSourceFile(context.filename); const diagnostics = checker.getSuggestionDiagnostics(sourceFile); for (const diagnostic of diagnostics) { if (diagnostic.reportsDeprecated === true) { const sourceCode = context.sourceCode; const start = sourceCode.getLocFromIndex(diagnostic.start); const end = sourceCode.getLocFromIndex(diagnostic.start + diagnostic.length); const loc = { start, end }; context.report({ loc, messageId: 'deprecation', data: { deprecation: diagnostic.messageText, }, }); } } }, }; }, }; const MAX_INDEX = 4; const isAllowedIndex = (idx) => idx >= 0 && idx <= MAX_INDEX; const rule$3K = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { function visitStatements(statements) { const declarationsByObject = new Map(); for (const statement of statements) { if (statement.type === 'VariableDeclaration') { visitDeclarations(declarationsByObject, statement.declarations); } else { checkDeclarationsBlock(declarationsByObject); declarationsByObject.clear(); } } checkDeclarationsBlock(declarationsByObject); } function visitDeclarations(declarationsByObject, declarations) { for (const declaration of declarations) { const id = declaration.id; if (declaration.init && id.type === 'Identifier') { const varName = id.name; const expression = declaration.init; if (expression.type !== 'MemberExpression') { continue; } const property = expression.property; if (isIdentifier(property, varName) || (isNumberLiteral(property) && isAllowedIndex(property.value))) { addDeclaration(declarationsByObject, expression.object, declaration); } } } } function addDeclaration(declarationsByObject, object, declaration) { const key = context.sourceCode.getText(object); const value = declarationsByObject.get(key); if (value) { value.push(declaration); } else { declarationsByObject.set(key, [declaration]); } } function checkDeclarationsBlock(declarationsByObject) { declarationsByObject.forEach((declarations, key) => { if (declarations.length > 1) { const firstKind = getKind(declarations[0]); const tail = declarations.slice(1); if (tail.every(decl => getKind(decl) === firstKind)) { context.report({ node: declarations[0], message: toEncodedMessage$1(`Use destructuring syntax for these assignments from "${key}".`, tail, Array(tail.length).fill('Replace this assignment.')), }); } } }); } return { BlockStatement: (node) => { visitStatements(node.body); }, SwitchCase: (node) => { visitStatements(node.consequent); }, Program: (node) => { visitStatements(node.body); }, }; }, }; function getKind(declarator) { const declaration = findFirstMatchingAncestor(declarator, n => n.type === 'VariableDeclaration'); return declaration === null || declaration === void 0 ? void 0 : declaration.kind; } const rule$3J = { meta: { hasSuggestions: true, schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { const services = context.sourceCode.parserServices; if (!isRequiredParserServices(services)) { return {}; } function isComparableTo(lhs, rhs) { const checker = services.program.getTypeChecker(); const lhsType = checker.getBaseTypeOfLiteralType(getTypeFromTreeNode$1(lhs, services)); const rhsType = checker.getBaseTypeOfLiteralType(getTypeFromTreeNode$1(rhs, services)); return (checker.isTypeAssignableTo(lhsType, rhsType) || checker.isTypeAssignableTo(rhsType, lhsType)); } return { BinaryExpression: (node) => { const { left, operator, right } = node; if (['===', '!=='].includes(operator) && !isComparableTo(left, right)) { const [actual, expected, outcome] = operator === '===' ? ['===', '==', 'false'] : ['!==', '!=', 'true']; const operatorToken = context.sourceCode .getTokensBetween(left, right) .find(token => token.type === 'Punctuator' && token.value === operator); context.report({ message: toEncodedMessage$1(`Remove this "${actual}" check; it will always be ${outcome}. Did you mean to use "${expected}"?`, [left, right]), loc: operatorToken.loc, suggest: [ { desc: `Replace "${actual}" with "${expected}"`, fix: fixer => fixer.replaceText(operatorToken, expected), }, ], }); } }, }; }, }; const MESSAGE$3 = 'Make sure disabling auto-escaping feature is safe here.'; const rule$3I = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { const services = context.sourceCode.parserServices; function isEmptySanitizerFunction(sanitizerFunction) { if (sanitizerFunction.params.length !== 1) { return false; } const firstParam = sanitizerFunction.params[0]; if (firstParam.type !== 'Identifier') { return false; } const firstParamName = firstParam.name; if (sanitizerFunction.body.type !== 'BlockStatement') { return (sanitizerFunction.body.type === 'Identifier' && sanitizerFunction.body.name === firstParamName); } const { body } = sanitizerFunction.body; if (body.length !== 1) { return false; } const onlyStatement = body[0]; if (onlyStatement.type === 'ReturnStatement' && onlyStatement.argument && isIdentifier(onlyStatement.argument, firstParamName)) { return true; } return false; } function isInvalidSanitizerFunction(node) { var _a; let assignedFunction = (_a = getValueOfExpression(context, node, 'FunctionExpression')) !== null && _a !== void 0 ? _a : getValueOfExpression(context, node, 'ArrowFunctionExpression'); if (!assignedFunction && node.type === 'Identifier' && isRequiredParserServices(services)) { assignedFunction = resolveFromFunctionReference(context, node); } if (!!assignedFunction) { return isEmptySanitizerFunction(assignedFunction); } return false; } return { CallExpression: (node) => { const callExpression = node; const fqn = getFullyQualifiedName(context, callExpression); if (fqn === 'handlebars.compile') { checkSensitiveCall(context, callExpression, 1, 'noEscape', true, MESSAGE$3); } if (fqn === 'marked.setOptions') { checkSensitiveCall(context, callExpression, 0, 'sanitize', false, MESSAGE$3); } if (fqn === 'markdown-it') { checkSensitiveCall(context, callExpression, 0, 'html', true, MESSAGE$3); } }, NewExpression: (node) => { const newExpression = node; if (getFullyQualifiedName(context, newExpression) === 'kramed.Renderer') { checkSensitiveCall(context, newExpression, 0, 'sanitize', false, MESSAGE$3); } }, AssignmentExpression: (node) => { const assignmentExpression = node; const { left, right } = assignmentExpression; if (left.type !== 'MemberExpression') { return; } if (!(getFullyQualifiedName(context, left) === 'mustache.escape' || (isMustacheIdentifier(left.object) && isIdentifier(left.property, 'escape')))) { return; } if (isInvalidSanitizerFunction(right)) { context.report({ node: left, message: toEncodedMessage$1(MESSAGE$3), }); } }, }; }, }; function isMustacheIdentifier(node) { return isIdentifier(node, 'Mustache'); } const rule$3H = { meta: { messages: { safeResource: 'Make sure not using resource integrity feature is safe here.', }, }, create(context) { const services = context.sourceCode.parserServices; if (!isRequiredParserServices(services)) { return {}; } function shouldReport(assignedVariable) { let nbSrcAssignment = 0; let hasUnsafeSrcAssignment = false; let hasIntegrityAssignment = false; assignedVariable.references.forEach(ref => { const parentNode = ref.identifier.parent; if (!parentNode) { return; } nbSrcAssignment += isSrcAssignment(parentNode) ? 1 : 0; hasUnsafeSrcAssignment = hasUnsafeSrcAssignment || isUnsafeSrcAssignment(parentNode); hasIntegrityAssignment = hasIntegrityAssignment || isIntegrityAssignment(parentNode); }); return nbSrcAssignment === 1 && hasUnsafeSrcAssignment && !hasIntegrityAssignment; } function isIntegrityAssignment(memberExpression) { if (memberExpression.type !== 'MemberExpression') { return false; } return (memberExpression.property.type === 'Identifier' && memberExpression.property.name === 'integrity'); } function isSrcAssignment(memberExpression) { if (memberExpression.type !== 'MemberExpression') { return false; } if (memberExpression.property.type !== 'Identifier' || memberExpression.property.name !== 'src') { return false; } const assignmentExpression = memberExpression.parent; if ((assignmentExpression === null || assignmentExpression === void 0 ? void 0 : assignmentExpression.type) !== 'AssignmentExpression') { return false; } return true; } function isUnsafeSrcAssignment(memberExpression) { if (!isSrcAssignment(memberExpression)) { return false; } const right = memberExpression.parent.right; if (right.type !== 'Literal') { return false; } return !!right.raw && (!!right.raw.match('^"http') || !!right.raw.match('^"//')); } return { 'VariableDeclarator[init.type="CallExpression"]': (node) => { const variableDeclarator = node; const callExpression = variableDeclarator.init; const left = variableDeclarator.id; const { callee } = callExpression; if (left.type !== 'Identifier') { return; } if (callee.type !== 'MemberExpression') { return; } const typeName = getTypeAsString(left, services); if (!isIdentifier(callee.object, 'document') || !isIdentifier(callee.property, 'createElement') || typeName !== 'HTMLScriptElement') { return; } const scope = context.sourceCode.getScope(node); const assignedVariable = scope.variables.find(v => v.name === left.name); if (!assignedVariable) { return; } if (shouldReport(assignedVariable)) { context.report({ node: variableDeclarator, messageId: 'safeResource', }); } }, }; }, }; const MESSAGE$2 = 'Set this timeout to 0 if you want to disable it, otherwise use a value lower than 2147483648.'; const MAX_DELAY_VALUE = 2147483647; const rule$3G = { create(context) { if (!Chai.isImported(context)) { return {}; } const constructs = []; return { CallExpression: (node) => { if (Mocha.isTestConstruct(node)) { constructs.push(node); return; } if (constructs.length > 0) { checkTimeoutDisabling(node, context); } }, 'CallExpression:exit': (node) => { if (Mocha.isTestConstruct(node)) { constructs.pop(); } }, }; }, }; function checkTimeoutDisabling(node, context) { if (isMethodCall(node) && node.arguments.length > 0) { const { callee: { object, property }, arguments: [value], } = node; if (isThisExpression(object) && isIdentifier(property, 'timeout') && isDisablingTimeout(value, context)) { context.report({ message: MESSAGE$2, node: value, }); } } } function isDisablingTimeout(timeout, context) { const usage = getUniqueWriteUsageOrNode(context, timeout); return isNumberLiteral(usage) && usage.value > MAX_DELAY_VALUE; } const MESSAGE$1 = 'Make sure allowing browsers to perform DNS prefetching is safe here.'; const rule$3F = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { return { CallExpression: (node) => { const callExpression = node; const fqn = getFullyQualifiedName(context, callExpression); if (fqn === 'helmet.dnsPrefetchControl') { checkSensitiveCall(context, callExpression, 0, 'allow', true, MESSAGE$1); } if (fqn === 'helmet') { checkSensitiveCall(context, callExpression, 0, 'dnsPrefetchControl', false, MESSAGE$1); } if (fqn === 'dns-prefetch-control') { checkSensitiveCall(context, callExpression, 0, 'allow', true, MESSAGE$1); } }, }; }, }; const rule$3E = createRegExpRule(context => { let flags; return { onRegExpLiteralEnter: (node) => { flags = node.flags; }, onCharacterClassEnter: (node) => { const duplicates = new Set(); const characterClass = new SimplifiedRegexCharacterClass(flags); node.elements.forEach(element => { const intersections = new SimplifiedRegexCharacterClass(flags, element).findIntersections(characterClass); if (intersections.length > 0) { intersections.forEach(intersection => duplicates.add(intersection)); duplicates.add(element); } characterClass.add(element); }); if (duplicates.size > 0) { const [primary, ...secondaries] = duplicates; const secondaryLocations = []; const messages = []; for (const secondary of secondaries) { const loc = getRegexpLocation(context.node, secondary, context); if (loc) { secondaryLocations.push({ loc }); messages.push('Additional duplicate'); } } context.reportRegExpNode({ message: toEncodedMessage$1('Remove duplicates in this character class.', secondaryLocations, messages), node: context.node, regexpNode: primary, }); } }, }; }, { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, }); const rule$3D = createRegExpRule(context => { return { onQuantifierEnter: (node) => { const { element } = node; if (matchEmptyString(element)) { context.reportRegExpNode({ message: `Rework this part of the regex to not match the empty string.`, node: context.node, regexpNode: element, }); } }, }; }); function matchEmptyString(node) { switch (node.type) { case 'Alternative': return node.elements.every(matchEmptyString); case 'Assertion': return true; case 'CapturingGroup': case 'Group': case 'Pattern': return node.alternatives.some(matchEmptyString); case 'Quantifier': return node.min === 0; default: return false; } } const getEncryptionRuleModule = (clientSideMethods, serverSideMethods) => ({ meta: { messages: { safeEncryption: 'Make sure that encrypting data is safe here.', }, }, create(context) { let usingCryptoInFile = false; return { Program() { usingCryptoInFile = false; }, MemberExpression(node) { const { object, property } = node; if (isIdentifier(property, 'subtle') && (isIdentifier(object, 'crypto') || isMemberWithProperty$1(object, 'crypto'))) { usingCryptoInFile = true; } }, 'CallExpression:exit'(node) { const { callee } = node; if (usingCryptoInFile) { checkForClientSide(callee, context, clientSideMethods); } checkForServerSide(callee, context, serverSideMethods); }, }; }, }); function checkForServerSide(callee, context, serverSideMethods) { const fqn = getFullyQualifiedName(context, callee); if (serverSideMethods.some(method => fqn === `crypto.${method}`)) { context.report({ messageId: 'safeEncryption', node: callee, }); } } function checkForClientSide(callee, context, clientSideMethods) { if (isIdentifier(callee, ...clientSideMethods) || isMemberWithProperty$1(callee, ...clientSideMethods)) { context.report({ messageId: 'safeEncryption', node: callee, }); } } const clientSideEncryptMethods = ['encrypt', 'decrypt']; const serverSideEncryptMethods = [ 'createCipher', 'createCipheriv', 'createDecipher', 'createDecipheriv', 'publicEncrypt', 'publicDecrypt', 'privateEncrypt', 'privateDecrypt', ]; const rule$3C = getEncryptionRuleModule(clientSideEncryptMethods, serverSideEncryptMethods); const aliases = [ 'AES128', 'AES192', 'AES256', 'BF', 'blowfish', 'CAMELLIA128', 'CAMELLIA192', 'CAMELLIA256', 'CAST', 'DES', 'DES-EDE', 'DES-EDE3', 'DES3', 'DESX', 'RC2', 'RC2-40', 'RC2-64', 'RC2-128', 'SEED', ]; const rule$3B = { meta: { messages: { useSecureMode: 'Use a secure mode and padding scheme.', }, }, create(context) { const patterns = [/CBC/i, /ECB/i]; aliases.forEach(alias => patterns.push(new RegExp(`^${alias}$`, 'i'))); return { CallExpression: (node) => { const callExpression = node; if (getFullyQualifiedName(context, callExpression) !== 'crypto.createCipheriv') { return; } const sensitiveArgument = callExpression.arguments[0]; const sensitiveArgumentValue = getValueOfExpression(context, sensitiveArgument, 'Literal'); if (!sensitiveArgumentValue) { return; } const { value } = sensitiveArgumentValue; if (typeof value !== 'string') { return; } if (patterns.some(pattern => pattern.test(value))) { context.report({ messageId: 'useSecureMode', node: sensitiveArgument, }); } }, }; }, }; const rule$3A = eslintRules['comma-dangle']; const rule$3z = { meta: { messages: { nonExistingGroup: 'Referencing non-existing group{{groups}}.', }, }, create(context) { const services = context.sourceCode.parserServices; if (!isRequiredParserServices(services)) { return {}; } return { CallExpression: (call) => { if (isStringReplaceCall(call, services)) { const [pattern, substr] = call.arguments; const regex = getParsedRegex(pattern, context); if (regex !== null) { const groups = extractGroups(regex); const references = extractReferences(substr); const invalidReferences = references.filter(ref => !isReferencingExistingGroup(ref, groups)); if (invalidReferences.length > 0) { const groups = `${invalidReferences.length > 1 ? 's' : ''}: ${invalidReferences .map(ref => ref.raw) .join(', ')}`; context.report({ node: substr, messageId: 'nonExistingGroup', data: { groups, }, }); } } } }, }; }, }; class CapturingGroups { constructor() { this.names = new Set(); this.groups = 0; } add(name) { if (name !== null) { this.names.add(name); } this.groups++; } has(name) { return this.names.has(name); } count() { return this.groups; } } function extractGroups(regex) { const groups = new CapturingGroups(); regexpp__namespace.visitRegExpAST(regex, { onCapturingGroupEnter: group => groups.add(group.name), }); return groups; } function isReferencingExistingGroup(reference, groups) { if (!isNaN(Number(reference.value))) { const index = Number(reference.value); return index >= 1 && index <= groups.count(); } else { const name = reference.value; return groups.has(name); } } const rule$3y = { meta: { schema: [ { type: 'object', properties: { max: { type: 'integer', }, }, }, { type: 'string', enum: [SONAR_RUNTIME], }, ], }, create(context) { const options = context.options; const threshold = options[0].max; const statementLevel = [new ExpressionComplexity()]; return { '*': (node) => { const tree = node; if (isConditionalLike(tree)) { const expr = statementLevel[statementLevel.length - 1]; expr.incrementNestedExprLevel(); expr.addOperator(getOperatorToken(tree, context)); } else if (isScopeLike(tree)) { statementLevel.push(new ExpressionComplexity()); } }, '*:exit': (node) => { const tree = node; if (isConditionalLike(tree)) { const expr = statementLevel[statementLevel.length - 1]; expr.decrementNestedExprLevel(); if (expr.isOnFirstExprLevel()) { const operators = expr.getComplexityOperators(); if (operators.length > threshold) { reportIssue(tree, operators, threshold, context); } expr.resetExpressionComplexityOperators(); } } else if (isScopeLike(tree)) { statementLevel.pop(); } }, }; }, }; class ExpressionComplexity { constructor() { this.nestedLevel = 0; this.operators = []; } addOperator(operator) { this.operators.push(operator); } incrementNestedExprLevel() { this.nestedLevel++; } decrementNestedExprLevel() { this.nestedLevel--; } isOnFirstExprLevel() { return this.nestedLevel === 0; } getComplexityOperators() { return this.operators; } resetExpressionComplexityOperators() { this.operators = []; } } function isScopeLike(node) { return (node.type === 'FunctionExpression' || (node.type === 'FunctionDeclaration' && node.generator) || node.type === 'ObjectExpression' || node.type === 'CallExpression' || node.type === 'JSXElement'); } function isConditionalLike(node) { return node.type === 'ConditionalExpression' || node.type === 'LogicalExpression'; } function getOperatorToken(node, context) { const sourceCode = context.sourceCode; if (node.type === 'ConditionalExpression') { return sourceCode.getTokenAfter(node.test, token => token.type === 'Punctuator' && token.value === '?'); } else { const expr = node; return sourceCode.getTokenAfter(expr.left, token => token.type === 'Punctuator' && token.value === expr.operator); } } function reportIssue(node, operators, max, context) { const complexity = operators.length; const message = `Reduce the number of conditional operators (${complexity}) used in the expression (maximum allowed ${max}).`; const secondaryLocationsHolder = operators; const secondaryMessages = Array(complexity).fill('+1'); const cost = complexity - max; context.report({ node: node, message: toEncodedMessage$1(message, secondaryLocationsHolder, secondaryMessages, cost), }); } let cached; const rule$3x = { meta: { messages: { fixHeader: 'Add or update the header of this file.', }, schema: [ { type: 'object', properties: { headerFormat: { type: 'string', }, isRegularExpression: { type: 'boolean', }, }, }, ], }, create(context) { updateCache(context.options); if (cached.failedToCompile) { return {}; } return { 'Program:exit'() { if (cached.isRegularExpression) { checkRegularExpression(cached.searchPattern, context); } else { checkPlainText(cached.expectedLines, context); } }, }; }, }; function checkPlainText(expectedLines, context) { let matches = false; const lines = context.sourceCode.lines; if (expectedLines.length <= lines.length) { matches = true; let i = 0; for (const expectedLine of expectedLines) { const line = lines[i]; i++; if (line !== expectedLine) { matches = false; break; } } } if (!matches) { addFileIssue(context); } } function checkRegularExpression(searchPattern, context) { const fileContent = context.sourceCode.getText(); const match = searchPattern.exec(fileContent); if (!match || match.index !== 0) { addFileIssue(context); } } function addFileIssue(context) { context.report({ messageId: 'fixHeader', loc: { line: 0, column: 0 }, }); } function updateCache(options) { const [{ headerFormat, isRegularExpression }] = options; if (!cached || cached.headerFormat !== headerFormat || cached.isRegularExpression !== isRegularExpression) { cached = { headerFormat, isRegularExpression, }; if (isRegularExpression) { try { cached.searchPattern = new RegExp(headerFormat, 's'); cached.failedToCompile = false; } catch (e) { console.error(`Failed to compile regular expression for rule S1451 (${e.message})`); cached.failedToCompile = true; } } else { cached.expectedLines = headerFormat.split(/(?:\r)?\n|\r/); } } } const rule$3w = { meta: { messages: { renameFile: 'Rename this file to "{{exported}}"', }, }, create(context) { let isOnlyExport = true; let nameOfExported = undefined; return { ExportDefaultDeclaration: (node) => { const declaration = node.declaration; if (declaration.type === 'Identifier') { const variable = getVariableFromName(context, declaration.name, node); if (variable && variable.defs.length === 1) { const def = variable.defs[0]; if (def.type === 'ClassName' || def.type === 'FunctionName' || isConst(def)) { nameOfExported = declaration.name; } } } else if ((declaration.type === 'ClassDeclaration' || declaration.type === 'FunctionDeclaration') && declaration.id) { nameOfExported = declaration.id.name; } }, 'ExportAllDeclaration, ExportNamedDeclaration': () => { isOnlyExport = false; }, 'Program:exit': () => { if (isOnlyExport && nameOfExported) { const fileName = path.parse(context.filename).name; if ('index' !== fileName && !sameName(nameOfExported, fileName) && !sameName(nameOfExported, sliceOffPostfix(fileName))) { context.report({ messageId: 'renameFile', data: { exported: nameOfExported, }, loc: { line: 0, column: 0 }, }); } } }, }; }, }; function sameName(nameOfExported, fileName) { const normalizedFileName = fileName.replace(/_/g, '').replace(/-/g, '').replace(/\./g, ''); const normalizedNameOfExported = nameOfExported.replace(/_/g, '').replace(/-/g, ''); return normalizedNameOfExported.toLowerCase() === normalizedFileName.toLowerCase(); } function isConst(def) { return def.type === 'Variable' && def.parent && def.parent.kind === 'const'; } function sliceOffPostfix(fileName) { return fileName.slice(0, fileName.lastIndexOf('.')); } const chmodLikeFunction = ['chmod', 'chmodSync', 'fchmod', 'fchmodSync', 'lchmod', 'lchmodSync']; const rule$3v = { meta: { messages: { safePermission: 'Make sure this permission is safe.', }, }, create(context) { function isChmodLikeFunction(node) { const { callee } = node; if (callee.type !== 'MemberExpression') { return false; } return isIdentifier(callee.property, ...chmodLikeFunction); } function modeFromLiteral(modeExpr) { const modeValue = modeExpr.value; let mode = null; if (typeof modeValue === 'string') { mode = Number.parseInt(modeValue, 8); } else if (typeof modeValue === 'number') { const raw = modeExpr.raw; if ((raw === null || raw === void 0 ? void 0 : raw.startsWith('0')) && !raw.startsWith('0o')) { mode = Number.parseInt(raw, 8); } else { mode = modeValue; } } return mode; } const FS_CONST = { S_IRWXU: 0o700, S_IRUSR: 0o400, S_IWUSR: 0o200, S_IXUSR: 0o100, S_IRWXG: 0o70, S_IRGRP: 0o40, S_IWGRP: 0o20, S_IXGRP: 0o10, S_IRWXO: 0o7, S_IROTH: 0o4, S_IWOTH: 0o2, S_IXOTH: 0o1, }; function modeFromMemberExpression(modeExpr) { const { object, property } = modeExpr; if (isMemberExpression(object, 'fs', 'constants') && property.type === 'Identifier') { return FS_CONST[property.name]; } return null; } function modeFromExpression(expr, visited) { if (!expr) { return null; } if (expr.type === 'MemberExpression') { return modeFromMemberExpression(expr); } else if (expr.type === 'Literal') { return modeFromLiteral(expr); } else if (expr.type === 'Identifier') { const usage = getUniqueWriteUsage(context, expr.name, expr); if (usage && !visited.has(usage)) { visited.add(usage); return modeFromExpression(usage, visited); } } else if (expr.type === 'BinaryExpression') { const { left, operator, right } = expr; if (operator === '|') { const leftValue = modeFromExpression(left, visited); const rightValue = modeFromExpression(right, visited); if (leftValue && rightValue) { return leftValue | rightValue; } } } return null; } function checkModeArgument(node, moduloTest) { const visited = new Set(); const mode = modeFromExpression(node, visited); if (mode !== null && !isNaN(mode) && mode % 8 !== moduloTest) { context.report({ node, messageId: 'safePermission', }); } } return { CallExpression: (node) => { const callExpression = node; if (isChmodLikeFunction(callExpression)) { checkModeArgument(callExpression.arguments[0], 0); checkModeArgument(callExpression.arguments[1], 0); } else if (getFullyQualifiedName(context, callExpression) === 'process.umask') { checkModeArgument(callExpression.arguments[0], 7); } }, }; }, }; const todoPattern = 'todo'; const letterPattern = /[\p{Letter}]/u; const rule$3u = { meta: { messages: { completeTODO: 'Complete the task associated to this "TODO" comment.', }, }, create(context) { return { 'Program:exit': () => { reportPatternInComment(context, todoPattern, 'completeTODO'); }, }; }, }; function reportPatternInComment(context, pattern, messageId) { const sourceCode = context.sourceCode; sourceCode.getAllComments().forEach(comment => { const rawText = comment.value.toLowerCase(); if (rawText.includes(pattern)) { const lines = rawText.split(/\r\n?|\n/); for (let i = 0; i < lines.length; i++) { const index = lines[i].indexOf(pattern); if (index >= 0 && !isLetterAround(lines[i], index, pattern)) { context.report({ messageId, loc: getPatternPosition(i, index, comment, pattern), }); } } } }); } function isLetterAround(line, start, pattern) { const end = start + pattern.length; const pre = start > 0 && letterPattern.test(line.charAt(start - 1)); const post = end <= line.length - 1 && letterPattern.test(line.charAt(end)); return pre || post; } function getPatternPosition(lineIdx, index, comment, pattern) { const line = comment.loc.start.line + lineIdx; const columnStart = lineIdx === 0 ? comment.loc.start.column + 2 : 0; const patternStart = columnStart + index; return { start: { line, column: patternStart }, end: { line, column: patternStart + pattern.length }, }; } const fixmePattern = 'fixme'; const rule$3t = { meta: { messages: { fixme: 'Take the required action to fix the issue indicated by this comment.', }, }, create(context) { return { 'Program:exit': () => { reportPatternInComment(context, fixmePattern, 'fixme'); }, }; }, }; const rule$3s = { meta: { messages: { restrictLoop: 'Restrict what this loop acts on by testing each property.', }, }, create(context) { function isAttrCopy(statement) { if (statement.type !== 'ExpressionStatement') { return false; } const expression = statement.expression; return (expression.type === 'AssignmentExpression' && expression.left.type === 'MemberExpression' && expression.left.computed); } return { ForInStatement(node) { const forInStatement = node; const body = forInStatement.body; if (body.type === 'BlockStatement') { if (body.body.length === 0) { return; } const firstStatement = body.body[0]; if (firstStatement.type === 'IfStatement' || isAttrCopy(firstStatement)) { return; } } if (body.type === 'EmptyStatement' || body.type === 'IfStatement' || isAttrCopy(body)) { return; } context.report({ node: forInStatement, messageId: 'restrictLoop', }); }, }; }, }; const rule$3r = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { return { ForStatement: (node) => { const forStatement = node; const test = forStatement.test; const loopIncrement = ForLoopIncrement.findInLoopUpdate(forStatement); if (test == null || loopIncrement == null || forStatement.update == null) { return; } const wrongDirection = getWrongDirection(test, loopIncrement); if (wrongDirection !== 0 && wrongDirection === loopIncrement.direction) { const movement = wrongDirection > 0 ? 'incremented' : 'decremented'; const message = toEncodedMessage$1(`"${loopIncrement.identifier.name}" is ${movement} and will never reach its stop condition.`, [test]); context.report({ message, node: forStatement.update, }); } }, }; }, }; class ForLoopIncrement { constructor(increment, identifier, direction) { this.increment = increment; this.identifier = identifier; this.direction = direction; } static findInLoopUpdate(forStatement) { let result = null; const expression = forStatement.update; if (!expression) { return null; } if (expression.type === 'UpdateExpression') { const updateExpression = expression; const direction = updateExpression.operator === '++' ? 1 : -1; result = ForLoopIncrement.increment(updateExpression, updateExpression.argument, direction); } if (expression.type === 'AssignmentExpression') { const assignmentExpression = expression; if (assignmentExpression.operator === '+=' && assignmentExpression.left.type === 'Identifier') { result = ForLoopIncrement.increment(expression, assignmentExpression.left, directionFromValue(assignmentExpression.right)); } if (assignmentExpression.operator === '-=' && assignmentExpression.left.type === 'Identifier') { result = ForLoopIncrement.increment(expression, assignmentExpression.left, -directionFromValue(assignmentExpression.right)); } if (assignmentExpression.operator === '=') { result = ForLoopIncrement.assignmentIncrement(assignmentExpression); } } return result; } static increment(increment, expression, direction) { if (expression.type === 'Identifier') { return new ForLoopIncrement(increment, expression, direction); } return null; } static assignmentIncrement(assignmentExpression) { const lhs = assignmentExpression.left; const rhs = assignmentExpression.right; if (lhs.type === 'Identifier' && rhs.type === 'BinaryExpression' && (rhs.operator === '+' || rhs.operator === '-')) { let incrementDirection = directionFromValue(rhs.right); if (incrementDirection !== null && isSameIdentifier(rhs.left, lhs)) { incrementDirection = rhs.operator === '-' ? -incrementDirection : incrementDirection; return ForLoopIncrement.increment(assignmentExpression, lhs, incrementDirection); } } return null; } } function directionFromValue(expression) { if (expression.type === 'Literal') { const value = Number(expression.raw); if (isNaN(value) || value === 0) { return 0; } return value > 0 ? 1 : -1; } if (expression.type === 'UnaryExpression') { const unaryExpression = expression; if (unaryExpression.operator === '+') { return directionFromValue(unaryExpression.argument); } if (unaryExpression.operator === '-') { return -directionFromValue(unaryExpression.argument); } } return 0; } function getWrongDirection(condition, forLoopIncrement) { if (condition.type !== 'BinaryExpression') { return 0; } if (isSameIdentifier(condition.left, forLoopIncrement.identifier)) { if (condition.operator === '<' || condition.operator === '<=') { return -1; } if (condition.operator === '>' || condition.operator === '>=') { return +1; } } else if (isSameIdentifier(condition.right, forLoopIncrement.identifier)) { if (condition.operator === '<' || condition.operator === '<=') { return +1; } if (condition.operator === '>' || condition.operator === '>=') { return -1; } } return 0; } function isSameIdentifier(expression, identifier) { return expression.type === 'Identifier' && expression.name === identifier.name; } const HELMET$5 = 'helmet'; const HELMET_CSP$1 = 'helmet-csp'; const DIRECTIVES$1 = 'directives'; const NONE = "'none'"; const CONTENT_SECURITY_POLICY$1 = 'contentSecurityPolicy'; const FRAME_ANCESTORS_CAMEL = 'frameAncestors'; const FRAME_ANCESTORS_HYPHEN = 'frame-ancestors'; const rule$3q = Express.SensitiveMiddlewarePropertyRule(findDirectivesWithSensitiveFrameAncestorsPropertyFromHelmet, `Make sure disabling content security policy frame-ancestors directive is safe here.`); function findDirectivesWithSensitiveFrameAncestorsPropertyFromHelmet(context, node) { const { arguments: args } = node; if (isValidHelmetModuleCall$1(context, node) && args.length === 1) { const [options] = args; const maybeDirectives = getProperty$1(options, DIRECTIVES$1, context); if (maybeDirectives) { const maybeFrameAncestors = getFrameAncestorsProperty(maybeDirectives, context); if (!maybeFrameAncestors) { return [maybeDirectives]; } if (isSetNoneFrameAncestorsProperty(maybeFrameAncestors)) { return [maybeFrameAncestors]; } } } return []; } function isValidHelmetModuleCall$1(context, callExpr) { const fqn = getFullyQualifiedName(context, callExpr); return fqn === HELMET_CSP$1 || fqn === `${HELMET$5}.${CONTENT_SECURITY_POLICY$1}`; } function isSetNoneFrameAncestorsProperty(frameAncestors) { const { value } = frameAncestors; return (value.type === 'ArrayExpression' && Boolean(value.elements.find(v => (v === null || v === void 0 ? void 0 : v.type) === 'Literal' && typeof v.value === 'string' && v.value === NONE))); } function getFrameAncestorsProperty(directives, context) { const propertyKeys = [FRAME_ANCESTORS_CAMEL, FRAME_ANCESTORS_HYPHEN]; for (const propertyKey of propertyKeys) { const maybeProperty = getProperty$1(directives.value, propertyKey, context); if (maybeProperty) { return maybeProperty; } } return undefined; } const message$3 = 'Make sure this function is not called after the loop completes.'; const loopLike = 'WhileStatement,DoWhileStatement,ForStatement,ForOfStatement,ForInStatement'; const functionLike = 'FunctionDeclaration,FunctionExpression,ArrowFunctionExpression'; const allowedCallbacks = [ 'replace', 'forEach', 'filter', 'map', 'find', 'findIndex', 'every', 'some', 'reduce', 'reduceRight', 'sort', 'each', ]; const rule$3p = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { function getLocalEnclosingLoop(node) { return findFirstMatchingAncestor(node, n => loopLike.includes(n.type)); } return { [functionLike]: (node) => { const loopNode = getLocalEnclosingLoop(node); if (loopNode && !isIIEF(node, context) && !isAllowedCallbacks(context, node) && context.sourceCode.getScope(node).through.some(ref => !isSafe(ref, loopNode))) { context.report({ message: toEncodedMessage$1(message$3, [getMainLoopToken(loopNode, context)]), loc: locations.getMainFunctionTokenLocation(node, getParent(context, node), context), }); } }, }; }, }; function isIIEF(node, context) { const parent = getParent(context, node); return (parent && ((parent.type === 'CallExpression' && parent.callee === node) || (parent.type === 'MemberExpression' && parent.object === node))); } function isAllowedCallbacks(context, node) { const parent = getParent(context, node); if (parent && parent.type === 'CallExpression') { const callee = parent.callee; if (callee.type === 'MemberExpression') { return (callee.property.type === 'Identifier' && allowedCallbacks.includes(callee.property.name)); } } return false; } function isSafe(ref, loopNode) { const variable = ref.resolved; if (variable) { const definition = variable.defs[0]; const declaration = definition === null || definition === void 0 ? void 0 : definition.parent; const kind = declaration && declaration.type === 'VariableDeclaration' ? declaration.kind : ''; if (kind !== 'let' && kind !== 'const') { return hasConstValue(variable, loopNode); } } return true; } function hasConstValue(variable, loopNode) { for (const ref of variable.references) { if (ref.isWrite()) { if (ref.from.type === 'block' && ref.from.block === loopNode.body) { return false; } const refRange = ref.identifier.range; const range = getLoopTestRange(loopNode); if (refRange && range && refRange[0] >= range[0] && refRange[1] <= range[1]) { return false; } } } return true; } function getLoopTestRange(loopNode) { var _a; const bodyRange = loopNode.body.range; if (bodyRange) { switch (loopNode.type) { case 'ForStatement': if ((_a = loopNode.test) === null || _a === void 0 ? void 0 : _a.range) { return [loopNode.test.range[0], bodyRange[0]]; } break; case 'WhileStatement': case 'DoWhileStatement': return loopNode.test.range; case 'ForOfStatement': case 'ForInStatement': { const leftRange = loopNode.range; if (leftRange) { return [leftRange[0], bodyRange[0]]; } } } } return undefined; } function getMainLoopToken(loop, context) { const sourceCode = context.sourceCode; let token; switch (loop.type) { case 'WhileStatement': case 'DoWhileStatement': token = sourceCode.getTokenBefore(loop.test, t => t.type === 'Keyword' && t.value === 'while'); break; case 'ForStatement': case 'ForOfStatement': default: token = sourceCode.getFirstToken(loop, t => t.type === 'Keyword' && t.value === 'for'); } return token; } const functionExitSelector = [ ':matches(', ['FunctionExpression', 'ArrowFunctionExpression', 'FunctionDeclaration'].join(','), ')', ':exit', ].join(''); const functionExpressionProperty = [ 'Property', '[key.type="Identifier"]', ':matches(', ['[value.type="FunctionExpression"]', '[value.type="ArrowFunctionExpression"]'].join(','), ')', ].join(''); const functionExpressionVariable = [ 'VariableDeclarator', '[id.type="Identifier"]', ':matches(', ['[init.type="FunctionExpression"]', '[init.type="ArrowFunctionExpression"]'].join(','), ')', ].join(''); const rule$3o = { meta: { messages: { renameFunction: "Rename this '{{function}}' function to match the regular expression '{{format}}'.", }, schema: [ { type: 'object', properties: { format: { type: 'string', }, }, }, ], }, create(context) { const [{ format }] = context.options; const knowledgeStack = []; return { [functionExpressionProperty]: (node) => { knowledgeStack.push({ node: node.key, func: node.value, returnsJSX: returnsJSX(node.value), }); }, [functionExpressionVariable]: (node) => { knowledgeStack.push({ node: node.id, func: node.init, returnsJSX: returnsJSX(node.init), }); }, 'MethodDefinition[key.type="Identifier"]': (node) => { knowledgeStack.push({ node: node.key, func: node.value, returnsJSX: false, }); }, 'FunctionDeclaration[id.type="Identifier"]': (node) => { knowledgeStack.push({ node: node.id, func: node, returnsJSX: false, }); }, [functionExitSelector]: (func) => { var _a; if (func === ((_a = last(knowledgeStack)) === null || _a === void 0 ? void 0 : _a.func)) { const knowledge = knowledgeStack.pop(); if (knowledge && !knowledge.returnsJSX) { const { node } = knowledge; if (!node.name.match(format)) { context.report({ messageId: 'renameFunction', data: { function: node.name, format, }, node, }); } } } }, ReturnStatement: (node) => { const knowledge = last(knowledgeStack); const ancestors = context.sourceCode.getAncestors(node); for (let i = ancestors.length - 1; i >= 0; i--) { if (functionLike$1.has(ancestors[i].type)) { const enclosingFunction = ancestors[i]; if (knowledge && knowledge.func === enclosingFunction && node.argument && node.argument.type.startsWith('JSX')) { knowledge.returnsJSX = true; } return; } } }, }; }, }; function returnsJSX(node) { return node.body.type.startsWith('JSX'); } class FunctionScope { constructor() { this.returnStatements = []; } getReturnStatements() { return this.returnStatements.slice(); } addReturnStatement(node) { this.returnStatements.push(node); } } const isASanitationFunction = (signature) => { const { types } = signature.getReturnType(); return types.length === 2 && types.some(isBooleanTrueType) && types.some(isStringType$1); }; const rule$3n = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { let scopes = []; const services = context.sourceCode.parserServices; if (!isRequiredParserServices(services)) { return {}; } const checker = services.program.getTypeChecker(); function onFunctionExit(node) { const returnStatements = scopes.pop().getReturnStatements(); if (returnStatements.some(retStmt => { var _a; return ((_a = retStmt.argument) === null || _a === void 0 ? void 0 : _a.type) === 'ThisExpression'; })) { return; } const signature = checker.getSignatureFromDeclaration(services.esTreeNodeToTSNodeMap.get(node)); if (signature && hasMultipleReturnTypes(signature, checker)) { if (isASanitationFunction(signature)) { return; } const stmts = returnStatements.filter(retStmt => !isNullLike$1(getTypeFromTreeNode$1(retStmt.argument, services))); const stmtsTypes = stmts.map(retStmt => getTypeFromTreeNode$1(retStmt.argument, services)); if (stmtsTypes.every(isAny$2)) { return; } context.report({ message: toEncodedMessage$1('Refactor this function to always return the same type.', stmts, stmtsTypes.map(stmtType => `Returns ${prettyPrint(stmtType, checker)}`)), loc: locations.getMainFunctionTokenLocation(node, getParent(context, node), context), }); } } return { ReturnStatement: (node) => { const retStmt = node; if (scopes.length > 0 && retStmt.argument) { scopes[scopes.length - 1].addReturnStatement(retStmt); } }, ':function': () => { scopes.push(new FunctionScope()); }, ':function:exit': onFunctionExit, 'Program:exit': () => { scopes = []; }, }; }, }; function hasMultipleReturnTypes(signature, checker) { const returnType = checker.getBaseTypeOfLiteralType(checker.getReturnTypeOfSignature(signature)); return isMixingTypes(returnType, checker) && !hasReturnTypeJSDoc(signature); } function isMixingTypes(type, checker) { return (type.isUnion() && type.types .filter(tp => !isNullLike$1(tp)) .map(tp => prettyPrint(tp, checker)) .filter(distinct).length > 1); } function hasReturnTypeJSDoc(signature) { return signature.getJsDocTags().some(tag => ['return', 'returns'].includes(tag.name)); } function isObjectLikeType(type) { return !!(type.getFlags() & ts__namespace.TypeFlags.Object); } function distinct(value, index, self) { return self.indexOf(value) === index; } function prettyPrint(type, checker) { if (type.isUnionOrIntersection()) { const delimiter = type.isUnion() ? ' | ' : ' & '; return type.types .map(tp => prettyPrint(tp, checker)) .filter(distinct) .join(delimiter); } const typeNode = checker.typeToTypeNode(type, undefined, undefined); if (typeNode !== undefined) { if (ts__namespace.isFunctionTypeNode(typeNode)) { return 'function'; } if (ts__namespace.isArrayTypeNode(typeNode) || isTypedArray(type, checker)) { return 'array'; } } if (isObjectLikeType(type)) { return 'object'; } return checker.typeToString(checker.getBaseTypeOfLiteralType(type)); } function isTypedArray(type, checker) { return checker.typeToString(type).endsWith('Array'); } function isNullLike$1(type) { return ((type.flags & ts__namespace.TypeFlags.Null) !== 0 || (type.flags & ts__namespace.TypeFlags.Void) !== 0 || (type.flags & ts__namespace.TypeFlags.Undefined) !== 0); } const futureReservedWords = [ 'implements', 'interface', 'package', 'private', 'protected', 'public', 'enum', 'class', 'const', 'export', 'extends', 'import', 'super', 'let', 'static', 'yield', 'await', ]; const rule$3m = { meta: { messages: { renameReserved: 'Rename "{{reserved}}" identifier to prevent potential conflicts with future evolutions of the JavaScript language.', }, }, create(context) { function checkVariable(variable) { if (variable.defs.length > 0) { const def = variable.defs[0].name; context.report({ node: def, messageId: 'renameReserved', data: { reserved: variable.name, }, }); } } function checkVariablesByScope(scope) { scope.variables.filter(v => futureReservedWords.includes(v.name)).forEach(checkVariable); scope.childScopes.forEach(childScope => { checkVariablesByScope(childScope); }); } return { 'Program:exit': (node) => { checkVariablesByScope(context.sourceCode.getScope(node)); }, }; }, }; const rule$3l = { meta: { messages: { addYield: 'Add a "yield" statement to this generator.', }, }, create(context) { const yieldStack = []; function enterFunction() { yieldStack.push(0); } function exitFunction(node) { const functionNode = node; const countYield = yieldStack.pop(); if (countYield === 0 && functionNode.body.body.length > 0) { context.report({ messageId: 'addYield', loc: locations.getMainFunctionTokenLocation(functionNode, getParent(context, node), context), }); } } return { ':function[generator=true]': enterFunction, ':function[generator=true]:exit': exitFunction, YieldExpression() { if (yieldStack.length > 0) { yieldStack[yieldStack.length - 1] += 1; } }, }; }, }; const message$2 = 'Make sure this weak hash algorithm is not used in a sensitive context here.'; const CRYPTO_UNSECURE_HASH_ALGORITHMS = new Set([ 'md2', 'md4', 'md5', 'md6', 'haval128', 'hmacmd5', 'dsa', 'ripemd', 'ripemd128', 'ripemd160', 'hmacripemd160', 'sha1', ]); const SUBTLE_UNSECURE_HASH_ALGORITHMS = new Set(['sha-1']); const rule$3k = { create(context) { function checkNodejsCrypto(fqn, node) { const { callee, arguments: args } = node; if (fqn === 'crypto.createHash') { checkUnsecureAlgorithm(callee, args[0], CRYPTO_UNSECURE_HASH_ALGORITHMS); } } function checkSubtleCrypto(fqn, node) { const { callee, arguments: args } = node; if (fqn === 'crypto.subtle.digest') { checkUnsecureAlgorithm(callee, args[0], SUBTLE_UNSECURE_HASH_ALGORITHMS); } } function checkUnsecureAlgorithm(method, hash, unsecureAlgorithms) { const hashAlgorithm = getUniqueWriteUsageOrNode(context, hash); if (isStringLiteral(hashAlgorithm) && unsecureAlgorithms.has(hashAlgorithm.value.toLocaleLowerCase())) { context.report({ message: message$2, node: method, }); } } return { 'CallExpression[arguments.length > 0]': (node) => { const callExpr = node; const fqn = getFullyQualifiedName(context, callExpr); checkNodejsCrypto(fqn, callExpr); checkSubtleCrypto(fqn, callExpr); }, }; }, }; const SERVE_STATIC = 'serve-static'; const rule$3j = { meta: { messages: { safeHiddenFile: 'Make sure serving hidden files is safe here.', }, }, create(context) { return { CallExpression(node) { const { callee, arguments: args } = node; if (getFullyQualifiedName(context, callee) === SERVE_STATIC && args.length > 1) { let options = args[1]; if (options.type === 'Identifier') { options = getUniqueWriteUsage(context, options.name, node); } const dotfilesProperty = getProperty$1(options, 'dotfiles', context); if ((dotfilesProperty === null || dotfilesProperty === void 0 ? void 0 : dotfilesProperty.value.type) === 'Literal' && dotfilesProperty.value.value === 'allow') { context.report({ node: dotfilesProperty, messageId: 'safeHiddenFile' }); } } }, }; }, }; function decorate$F(rule) { return interceptReportForReact(rule, (context, descriptor) => { const { node } = descriptor; if (node.type === 'ArrayPattern' && node.elements.length === 1) { return; } context.report(descriptor); }); } const rule$3i = decorate$F(react.rules['hook-use-state']); const langRule = jsxA11y.rules['lang']; const htmlHasLangRule = jsxA11y.rules['html-has-lang']; const decoratedHasLangRule = decorate$E(htmlHasLangRule); function decorate$E(rule) { return interceptReport(rule, (context, reportDescriptor) => { const node = reportDescriptor.node; reportDescriptor.node = node.name; context.report(reportDescriptor); }); } const rule$3h = { meta: { hasSuggestions: true, messages: { ...langRule.meta.messages, ...decoratedHasLangRule.meta.messages, }, }, create(context) { const langListener = langRule.create(context); const htmlHasLangListener = decoratedHasLangRule.create(context); return mergeRules(langListener, htmlHasLangListener); }, }; const rule$3g = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { const services = context.sourceCode.parserServices; if (!isRequiredParserServices(services)) { return {}; } function isPrimitive(node) { const type = getTypeFromTreeNode$1(node, services); return ((type.flags & ts__namespace.TypeFlags.StringLike) !== 0 || (type.flags & ts__namespace.TypeFlags.NumberLike) !== 0 || (type.flags & ts__namespace.TypeFlags.BooleanLike) !== 0 || (type.flags & ts__namespace.TypeFlags.Null) !== 0 || (type.flags & ts__namespace.TypeFlags.Undefined) !== 0); } return { 'BinaryExpression[operator="in"]': (node) => { const { left, right, operator } = node; if (isPrimitive(right)) { const opToken = context.sourceCode .getTokensBetween(left, right) .find(token => token.type === 'Keyword' && token.value === operator); context.report({ message: toEncodedMessage$1('TypeError can be thrown as this operand might have primitive type.', [opToken]), node: right, }); } }, }; }, }; const rule$3f = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { const usedInNew = new Map(); const usedInCall = new Map(); const hasIssue = []; return { NewExpression: (node) => { checkExpression(node, usedInNew, usedInCall, hasIssue, 'out', context); }, CallExpression: (node) => { checkExpression(node, usedInCall, usedInNew, hasIssue, '', context); }, }; }, }; function checkExpression(callExpression, thisTypeUsageMap, otherTypeUsageMap, hasIssue, tail, context) { const variable = getVariable(callExpression, context); if (variable && variable.defs.length !== 0) { const otherTypeUsage = otherTypeUsageMap.get(variable); if ((otherTypeUsage === null || otherTypeUsage === void 0 ? void 0 : otherTypeUsage.loc) && !hasIssue.includes(variable)) { const message = `Correct the use of this function; ` + `on line ${otherTypeUsage.loc.start.line} it was called with${tail} "new".`; context.report({ node: callExpression.callee, message: toEncodedMessage$1(message, [otherTypeUsage.callee]), }); hasIssue.push(variable); } else { thisTypeUsageMap.set(variable, callExpression); } } } function getVariable(node, context) { if (node.callee.type === 'Identifier') { return getVariableFromName(context, node.callee.name, node); } return undefined; } const rule$3e = { meta: { messages: { considerIncludes: "This check ignores index 0; consider using 'includes' method to make this check safe and explicit.", }, }, create(context) { const services = context.sourceCode.parserServices; if (!isRequiredParserServices(services)) { return {}; } return { BinaryExpression(node) { const expression = node; if (expression.operator === '>' && isZero(expression.right) && isArrayIndexOfCall(expression.left, services)) { context.report({ node, messageId: 'considerIncludes' }); } }, }; }, }; function isZero(node) { return node.type === 'Literal' && node.value === 0; } function isArrayIndexOfCall(node, services) { return (node.type === 'CallExpression' && node.arguments.length === 1 && node.callee.type === 'MemberExpression' && node.callee.property.type === 'Identifier' && node.callee.property.name === 'indexOf' && isArray(node.callee.object, services)); } const rule$3d = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { return { CallExpression: (node) => new CookieFlagCheck(context, 'secure').checkCookiesFromCallExpression(node), }; }, }; const rule$3c = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { const SIGN_MESSAGE = 'Use only strong cipher algorithms when signing this JWT.'; const VERIFY_MESSAGE = 'Use only strong cipher algorithms when verifying the signature of this JWT.'; const SECONDARY_MESSAGE = `The "algorithms" option should be defined and should not contain 'none'.`; function checkCallToSign(callExpression, thirdArgumentValue, secondaryLocations) { const unsafeAlgorithmProperty = getPropertyWithValue(context, thirdArgumentValue, 'algorithm', 'none'); if (unsafeAlgorithmProperty) { const unsafeAlgorithmValue = getValueOfExpression(context, unsafeAlgorithmProperty.value, 'Literal'); if (unsafeAlgorithmValue && unsafeAlgorithmValue !== unsafeAlgorithmProperty.value) { secondaryLocations.push(unsafeAlgorithmValue); } raiseIssueOn(callExpression.callee, SIGN_MESSAGE, secondaryLocations); } } function checkCallToVerify(callExpression, publicKey, thirdArgumentValue, secondaryLocations) { const algorithmsProperty = getProperty$1(thirdArgumentValue, 'algorithms', context); if (!algorithmsProperty) { if (isNullLiteral(publicKey)) { raiseIssueOn(callExpression.callee, VERIFY_MESSAGE, secondaryLocations); } return; } const algorithmsValue = getValueOfExpression(context, algorithmsProperty.value, 'ArrayExpression'); if (!algorithmsValue) { return; } const algorithmsContainNone = algorithmsValue.elements.some(e => { const value = getValueOfExpression(context, e, 'Literal'); return (value === null || value === void 0 ? void 0 : value.value) === 'none'; }); if (algorithmsContainNone) { if (algorithmsProperty.value !== algorithmsValue) { secondaryLocations.push(algorithmsValue); } raiseIssueOn(callExpression.callee, VERIFY_MESSAGE, secondaryLocations); } } function raiseIssueOn(node, message, secondaryLocations) { context.report({ node, message: toEncodedMessage$1(message, secondaryLocations, Array(secondaryLocations.length).fill(SECONDARY_MESSAGE)), }); } return { CallExpression: (node) => { const callExpression = node; const fqn = getFullyQualifiedName(context, callExpression); const isCallToSign = fqn === 'jsonwebtoken.sign'; const isCallToVerify = fqn === 'jsonwebtoken.verify'; if (!isCallToSign && !isCallToVerify) { return; } if (callExpression.arguments.length < 3) { return; } const thirdArgument = callExpression.arguments[2]; const thirdArgumentValue = getValueOfExpression(context, thirdArgument, 'ObjectExpression'); if (!thirdArgumentValue) { return; } const secondaryLocations = [thirdArgumentValue]; if (thirdArgumentValue !== thirdArgument) { secondaryLocations.push(thirdArgument); } if (isCallToSign) { checkCallToSign(callExpression, thirdArgumentValue, secondaryLocations); } const secondArgument = callExpression.arguments[1]; if (isCallToVerify) { checkCallToVerify(callExpression, secondArgument, thirdArgumentValue, secondaryLocations); } }, }; }, }; const ASSERT_FUNCTIONS = [ 'equal', 'notEqual', 'strictEqual', 'notStrictEqual', 'deepEqual', 'notDeepEqual', 'closeTo', 'approximately', ]; const rule$3b = { meta: { hasSuggestions: true, schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { const testCases = []; return { CallExpression(node) { if (Mocha.isTestCase(node)) { testCases.push(node); return; } if (testCases.length > 0) { checkInvertedArguments(node, context); } }, 'CallExpression:exit': (node) => { if (Mocha.isTestCase(node)) { testCases.pop(); } }, }; }, }; function checkInvertedArguments(node, context) { const args = extractAssertionsArguments(node); if (args) { const [actual, expected, format] = args; if (isLiteral$2(actual) && !isLiteral$2(expected)) { const message = toEncodedMessage$1(`Swap these 2 arguments so they are in the correct order: ${format}.`, [actual], ['Other argument to swap.']); context.report({ node: expected, message, suggest: [ { desc: 'Swap arguments', fix: fixer => [ fixer.replaceText(actual, context.sourceCode.getText(expected)), fixer.replaceText(expected, context.sourceCode.getText(actual)), ], }, ], }); } } } function extractAssertionsArguments(node) { var _a, _b; return (_b = (_a = extractAssertArguments(node)) !== null && _a !== void 0 ? _a : extractExpectArguments(node)) !== null && _b !== void 0 ? _b : extractFailArguments(node); } function extractAssertArguments(node) { if (isMethodCall(node) && node.arguments.length > 1) { const { callee: { object, property }, arguments: [actual, expected], } = node; if (isIdentifier(object, 'assert') && isIdentifier(property, ...ASSERT_FUNCTIONS)) { return [actual, expected, `${object.name}.${property.name}(actual, expected)`]; } } return null; } function extractExpectArguments(node) { if (node.callee.type !== 'MemberExpression') { return null; } let { object, property } = node.callee; if (!isIdentifier(property, 'equal', 'eql', 'closeTo')) { return null; } while (object.type === 'MemberExpression') { object = object.object; } if (object.type === 'CallExpression' && isIdentifier(object.callee, 'expect')) { return [ object.arguments[0], node.arguments[0], `${object.callee.name}(actual).to.${property.name}(expected)`, ]; } return null; } function extractFailArguments(node) { if (isMethodCall(node) && node.arguments.length > 1) { const { callee: { object, property }, arguments: [actual, expected], } = node; if (isIdentifier(object, 'assert', 'expect', 'should') && isIdentifier(property, 'fail')) { return [actual, expected, `${object.name}.${property.name}(actual, expected)`]; } } return null; } function decorate$D(rule) { return interceptReportForReact(rule, reportExempting$8(hasSpreadOperator)); } function reportExempting$8(exemptionCondition) { return (context, reportDescriptor) => { if ('node' in reportDescriptor) { const { node, ...rest } = reportDescriptor; if (exemptionCondition(node)) { return; } context.report({ node, ...rest, }); } }; } function hasSpreadOperator(node) { return (node.type === 'JSXElement' && node.openingElement.attributes.some(attribute => attribute.type === 'JSXSpreadAttribute')); } const rule$3a = decorate$D(react.rules['jsx-key']); function decorate$C(rule) { return changeRuleMessagesWith(rule, lineRemover()); } function changeRuleMessagesWith(rule, messageChanger) { var _a; if ((_a = rule.meta) === null || _a === void 0 ? void 0 : _a.messages) { const messages = rule.meta.messages; const newMessages = Object.fromEntries(Object.entries(messages).map(([key, value]) => [key, messageChanger(value)])); rule.meta.messages = newMessages; } return rule; } function lineRemover() { const lineRegexp = / \(at line [^)]+\)/g; return (message) => message.replace(lineRegexp, ''); } const rule$39 = decorate$C(react.rules['jsx-no-constructed-context-values']); function decorate$B(rule) { rule.meta.hasSuggestions = true; rule.meta.messages = { ...rule.meta.messages, NeedsMoreChildren: 'A fragment with only one child is redundant.', }; return interceptReport(rule, (context, descriptor) => { const { node } = descriptor; if (node.type === 'JSXFragment' && node.children.length === 0) { return; } context.report(descriptor); }); } const rule$38 = decorate$B(react.rules['jsx-no-useless-fragment']); function decorate$A(rule) { return interceptReport(rule, (context, reportDescriptor) => { const { node } = reportDescriptor; const parent = node.parent; if (parent.children !== undefined) { for (const child of parent.children) { if (child.type === 'JSXElement' && isCustomComponent(child)) { return; } } } const name = node.name; context.report({ ...reportDescriptor, node: name }); }); } function isCustomComponent(node) { return !KNOWN_HTML_TAGS.has(node.openingElement.name.name); } const KNOWN_HTML_TAGS = new Set([ 'a', 'area', 'abbr', 'address', 'article', 'aside', 'audio', 'b', 'base', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'cite', 'code', 'col', 'colgroup', 'data', 'datalist', 'dd', 'del', 'details', 'dfn', 'dialog', 'div', 'dl', 'dt', 'em', 'embed', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'link', 'main', 'map', 'mark', 'menu', 'meta', 'meter', 'nav', 'noscript', 'object', 'ol', 'optgroup', 'option', 'output', 'p', 'param', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'script', 'search', 'section', 'select', 'small', 'source', 'span', 'strong', 'style', 'sub', 'summary', 'sup', 'svg', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'title', 'tr', 'track', 'u', 'ul', 'var', 'video', 'wbr', ]); const rule$37 = decorate$A(jsxA11y.rules['label-has-associated-control']); const rule$36 = { meta: { messages: { removeLabel: 'Remove this "{{label}}" label.', }, }, create(context) { return { LabeledStatement: (node) => checkLabeledStatement(node, context), }; }, }; function checkLabeledStatement(node, context) { if (!isLoopStatement(node.body) && !isSwitchStatement(node.body)) { context.report({ messageId: 'removeLabel', data: { label: node.label.name, }, node: node.label, }); } } function isLoopStatement(node) { return (node.type === 'WhileStatement' || node.type === 'DoWhileStatement' || node.type === 'ForStatement' || node.type === 'ForOfStatement' || node.type === 'ForInStatement'); } function isSwitchStatement(node) { return node.type === 'SwitchStatement'; } const REQUIRED_OPTION = 'noopener'; const REQUIRED_OPTION_INDEX = 2; const URL_INDEX = 0; const rule$35 = { meta: { messages: { missingNoopener: 'Make sure not using "noopener" is safe here.', }, }, create(context) { return { CallExpression: (node) => { if (!isMethodCall(node)) { return; } const { object, property } = node.callee; const isWindowOpen = isIdentifier(property, 'open') && (isIdentifier(object, 'window') || isThisWindow(object)); if (!isWindowOpen) { return; } const args = node.arguments; const hasHttpUrl = URL_INDEX < args.length && isHttpUrl(context, args[URL_INDEX]); if (!hasHttpUrl) { return; } if (args.length <= REQUIRED_OPTION_INDEX || !hasRequiredOption(context, args[REQUIRED_OPTION_INDEX])) { context.report({ messageId: 'missingNoopener', node: property, }); } }, }; }, }; function isThisWindow(node) { return (node.type === 'MemberExpression' && node.object.type === 'ThisExpression' && isIdentifier(node.property, 'window')); } function hasRequiredOption(context, argument) { const stringOrNothing = extractString(context, argument); return stringOrNothing === null || stringOrNothing === void 0 ? void 0 : stringOrNothing.includes(REQUIRED_OPTION); } function isHttpUrl(context, argument) { const stringOrNothing = extractString(context, argument); return (stringOrNothing !== undefined && (stringOrNothing.startsWith('http://') || stringOrNothing.startsWith('https://'))); } function extractString(context, node) { const literalNodeOrNothing = getValueOfExpression(context, node, 'Literal'); if (literalNodeOrNothing === undefined || !isStringLiteral(literalNodeOrNothing)) { return undefined; } else { return literalNodeOrNothing.value; } } const rule$34 = { meta: { messages: { refactorUnion: 'Refactor this union type to have less than {{threshold}} elements.', }, schema: [ { type: 'object', properties: { threshold: { type: 'integer', }, }, }, ], }, create(context) { return { TSUnionType: (node) => { const union = node; if (isUsedWithUtilityType(union)) { return; } const [{ threshold }] = context.options; if (union.types.length > threshold && !isFromTypeStatement(union)) { context.report({ messageId: 'refactorUnion', data: { threshold: `${threshold}`, }, node, }); } }, }; }, }; function isFromTypeStatement(node) { return node.parent.type === 'TSTypeAliasDeclaration'; } function isUsedWithUtilityType(node) { return (node.parent.type === 'TSTypeParameterInstantiation' && node.parent.parent.type === 'TSTypeReference' && isIdentifier(node.parent.parent.typeName, ...UTILITY_TYPES)); } function decorate$z(rule) { return interceptReport(rule, (context, descriptor) => { const { node } = descriptor; const name = node.name; context.report({ ...descriptor, node: name }); }); } const rule$33 = decorate$z(jsxA11y.rules['media-has-caption']); class ForInfo { constructor(forLoop) { this.forLoop = forLoop; this.updatedExpressions = []; this.testedExpressions = []; } } const rule$32 = { meta: { messages: { misplacedCounter: `This loop's stop condition tests "{{test}}" but the incrementer updates "{{update}}".`, }, }, create(context) { const forLoopStack = []; function join(expressions) { return expressions.map(expr => context.sourceCode.getText(expr)).join(', '); } function isInsideUpdate(node) { return isInside(node, f => f.update); } function isInsideTest(node) { return isInside(node, f => f.test); } function isInside(node, getChild) { if (forLoopStack.length > 0) { const currentLoop = peekFor(); const parentChain = context.sourceCode.getAncestors(node); parentChain.push(node); const forLoopChild = getChild(currentLoop.forLoop); if (forLoopChild) { return parentChain.some(parentChainNode => forLoopChild === parentChainNode); } } return false; } function peekFor() { return forLoopStack[forLoopStack.length - 1]; } return { ForStatement: (node) => { forLoopStack.push(new ForInfo(node)); }, 'ForStatement:exit': () => { const forInfo = forLoopStack.pop(); if (forInfo.updatedExpressions.length === 0 || !forInfo.forLoop.test) { return; } const hasIntersection = forInfo.testedExpressions.some(testedExpr => forInfo.updatedExpressions.some(updatedExpr => equivalence.areEquivalent(updatedExpr, testedExpr, context.getSourceCode()))); if (!hasIntersection) { context.report({ loc: context.sourceCode.getFirstToken(forInfo.forLoop).loc, messageId: 'misplacedCounter', data: { test: join(forInfo.testedExpressions), update: join(forInfo.updatedExpressions), }, }); } }, 'ForStatement AssignmentExpression': (node) => { if (isInsideUpdate(node)) { const left = node.left; const assignedExpressions = []; computeAssignedExpressions(left, assignedExpressions); const { updatedExpressions } = peekFor(); assignedExpressions.forEach(ass => updatedExpressions.push(ass)); } }, 'ForStatement UpdateExpression': (node) => { if (isInsideUpdate(node)) { peekFor().updatedExpressions.push(node.argument); } }, 'ForStatement CallExpression': (node) => { if (!isInsideUpdate(node)) { return; } const callee = getCalleeObject(node); if (callee) { peekFor().updatedExpressions.push(callee); } }, 'ForStatement Identifier': (node) => { if (isInsideTest(node)) { const parent = getParent(context, node); if (parent.type !== 'MemberExpression' || parent.computed || parent.object === node) { peekFor().testedExpressions.push(node); } } }, 'ForStatement MemberExpression': (node) => { if (isInsideTest(node) && getParent(context, node).type !== 'MemberExpression' && getParent(context, node).type !== 'CallExpression') { peekFor().testedExpressions.push(node); } }, }; }, }; function getCalleeObject(node) { let callee = node.callee; while (callee.type === 'MemberExpression') { callee = callee.object; } if (callee.type === 'Identifier' && callee !== node.callee) { return callee; } return null; } function computeAssignedExpressions(node, assigned) { switch (node === null || node === void 0 ? void 0 : node.type) { case 'ArrayPattern': node.elements.forEach(element => computeAssignedExpressions(element, assigned)); break; case 'ObjectPattern': node.properties.forEach(property => computeAssignedExpressions(property, assigned)); break; case 'Property': computeAssignedExpressions(node.value, assigned); break; case 'AssignmentPattern': computeAssignedExpressions(node.left, assigned); break; default: assigned.push(node); } } const mouseEventsHaveKeyEvents = jsxA11y.rules['mouse-events-have-key-events']; const clickEventsHaveKeyEvents = jsxA11y.rules['click-events-have-key-events']; const rule$31 = { meta: { hasSuggestions: true, messages: { ...mouseEventsHaveKeyEvents.meta.messages, ...clickEventsHaveKeyEvents.meta.messages, }, }, create(context) { const mouseEventsHaveKeyEventsListener = mouseEventsHaveKeyEvents.create(context); const clickEventsHaveKeyEventsListener = clickEventsHaveKeyEvents.create(context); return mergeRules(mouseEventsHaveKeyEventsListener, clickEventsHaveKeyEventsListener); }, }; const rule$30 = { meta: { schema: [ { type: 'object', properties: { maximumNestingLevel: { type: 'integer', }, }, }, { type: 'string', enum: [SONAR_RUNTIME], }, ], }, create(context) { const sourceCode = context.sourceCode; const [{ maximumNestingLevel: threshold }] = context.options; const nodeStack = []; function push(n) { nodeStack.push(n); } function pop() { return nodeStack.pop(); } function check(node) { if (nodeStack.length === threshold) { context.report({ message: toEncodedMessage$1(`Refactor this code to not nest more than ${threshold} if/for/while/switch/try statements.`, nodeStack, nodeStack.map(_n => '+1')), loc: sourceCode.getFirstToken(node).loc, }); } } function isElseIf(node) { const parent = last(context.sourceCode.getAncestors(node)); return (node.type === 'IfStatement' && parent.type === 'IfStatement' && node === parent.alternate); } const controlFlowNodes = [ 'ForStatement', 'ForInStatement', 'ForOfStatement', 'WhileStatement', 'DoWhileStatement', 'IfStatement', 'TryStatement', 'SwitchStatement', ].join(','); return { [controlFlowNodes]: (node) => { if (isElseIf(node)) { pop(); push(sourceCode.getFirstToken(node)); } else { check(node); push(sourceCode.getFirstToken(node)); } }, [`${controlFlowNodes}:exit`]: (node) => { if (!isElseIf(node)) { pop(); } }, }; }, }; function decorate$y(rule) { return interceptReport(rule, reportExempting$7(isNotClassOrFunction)); } function reportExempting$7(exemptionCondition) { return (context, reportDescriptor) => { if ('node' in reportDescriptor) { const node = reportDescriptor['node']; if (!exemptionCondition(context, node)) { context.report(reportDescriptor); } } }; } function isNotClassOrFunction(context, node) { const callee = node.callee; if (callee.type !== 'Identifier') { return false; } const variable = getVariableFromName(context, callee.name, node); if (variable) { for (const def of variable.defs) { if (!(def.type === 'ClassName' || def.type === 'FunctionName')) { return true; } } } return false; } const rule$2$ = decorate$y(eslintRules['new-cap']); const rule$2_ = { meta: { schema: [ { type: 'object', properties: { considerJSDoc: { type: 'boolean', }, }, }, { type: 'string', enum: [SONAR_RUNTIME], }, ], }, create(context) { const { considerJSDoc } = context.options[0]; const services = context.sourceCode.parserServices; if (!isRequiredParserServices(services)) { return {}; } return { 'NewExpression[callee.type!="ThisExpression"]': (node) => { const { callee } = node; const type = getTypeFromTreeNode$1(callee, services); const signature = getSignatureFromCallee(node, services); if (!isInstantiable(type, signature, considerJSDoc) && !isAny$1(type)) { const functionToken = context.sourceCode.getFirstToken(node, token => token.type === 'Keyword' && token.value === 'function'); const newToken = context.sourceCode.getFirstToken(node, token => token.type === 'Keyword' && token.value === 'new'); const text = isFunction(type) ? 'this function' : context.sourceCode.getText(callee); const loc = callee.type === 'FunctionExpression' ? functionToken.loc : callee.loc; context.report({ message: toEncodedMessage$1(`Replace ${text} with a constructor function.`, [newToken]), loc, }); } }, }; }, }; function isInstantiable(type, signature, considerJSDoc) { return (isClass(type) || isModule(type) || isConstructor(type, signature, considerJSDoc) || (type.isUnionOrIntersection() && type.types.some(tp => isInstantiable(tp, signature, considerJSDoc)))); } function isClass(type) { return (type.symbol && ((type.symbol.flags & ts__namespace.SymbolFlags.Class) !== 0 || (type.symbol.flags & ts__namespace.SymbolFlags.Type) !== 0)); } function isModule(type) { return type.symbol && (type.symbol.flags & ts__namespace.SymbolFlags.Module) !== 0; } function isFunction(type) { return type.symbol && (type.symbol.flags & ts__namespace.SymbolFlags.Function) !== 0; } function isConstructor(type, signature, considerJSDoc) { return isFunction(type) && (!considerJSDoc || hasJSDocAnnotation(signature)); } function hasJSDocAnnotation(signature) { return signature === null || signature === void 0 ? void 0 : signature.getJsDocTags().some(tag => ['constructor', 'class'].includes(tag.name)); } function isAny$1(type) { return type.flags === ts__namespace.TypeFlags.Any; } function isAccessorNode(node) { return (node === null || node === void 0 ? void 0 : node.type) === 'Property' || (node === null || node === void 0 ? void 0 : node.type) === 'MethodDefinition'; } const rule$2Z = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { const getterReturnListener = getterReturnDecorator.create(context); const noAccessorFieldMismatchListener = noAccessorFieldMismatchRule.create(context); return mergeRules(getterReturnListener, noAccessorFieldMismatchListener); }, }; function decorateGetterReturn(rule) { return interceptReport(rule, (context, descriptor) => { const props = descriptor; const { node, messageId } = props; if (node != null && reportWithFieldLocation(context, node.parent)) { return; } if (messageId === 'expected') { reportWithSonarFormat(context, descriptor, 'Refactor this getter to return a value.'); } else if (messageId === 'expectedAlways') { reportWithSonarFormat(context, descriptor, 'Refactor this getter to always return a value.'); } }); } const getterReturnDecorator = decorateGetterReturn(eslintRules['getter-return']); const noAccessorFieldMismatchRule = { create(context) { const currentFieldsStack = [new Map()]; const singleDescriptorAccessorSelector = [ 'CallExpression[arguments.1.type=Literal]', 'ObjectExpression:nth-child(3)', 'Property[value.type=FunctionExpression][key.name=/^[gs]et$/]', ].join(' > '); const multiDescriptorsAccessorSelector = [ 'CallExpression', 'ObjectExpression:nth-child(2)', 'Property:matches([key.type=Identifier], [key.type=Literal])', 'ObjectExpression', 'Property[value.type=FunctionExpression][key.name=/^[gs]et$/]', ].join(' > '); return { 'Property,MethodDefinition': (node) => { const accessorNode = node; const accessorInfo = getObjectOrClassAccessorInfo(accessorNode); if (accessorInfo) { const fieldMap = currentFieldsStack[currentFieldsStack.length - 1]; checkAccessorNode(context, accessorNode, fieldMap, accessorInfo); } }, [singleDescriptorAccessorSelector]: (node) => { const accessorNode = node; const accessorInfo = getSingleDescriptorAccessorInfo(accessorNode); if (accessorInfo) { const fieldMap = getSingleVariableFieldMap(context, accessorInfo.name, node); checkAccessorNode(context, accessorNode, fieldMap, accessorInfo); } }, [multiDescriptorsAccessorSelector]: (node) => { const accessorNode = node; const accessorInfo = getMultiDescriptorsAccessorInfo(accessorNode); if (accessorInfo) { const fieldMap = getSingleVariableFieldMap(context, accessorInfo.name, node); checkAccessorNode(context, accessorNode, fieldMap, accessorInfo); } }, ClassBody: (node) => { currentFieldsStack.push(getClassBodyFieldMap(node)); }, ObjectExpression: (node) => { currentFieldsStack.push(getObjectExpressionFieldMap(node)); }, ':matches(ClassBody, ObjectExpression):exit': () => { currentFieldsStack.pop(); }, }; }, }; function checkAccessorNode(context, node, fieldMap, info) { const accessor = getAccessor(node, fieldMap, info); if (accessor == null || isReportedByGetterReturnDecorator(accessor)) { return; } if (!isUsingAccessorFieldInBody(accessor)) { reportWithSecondaryLocation(context, accessor); } } function isReportedByGetterReturnDecorator(accessor) { const info = accessor.info; const emptyGetter = info.type === 'getter' && accessor.statement == null; return emptyGetter && (info.definition === 'descriptor' || accessor.node.kind === 'get'); } function reportWithFieldLocation(context, node) { if (!node || !isAccessorNode(node)) { return false; } const info = getNodeAccessorInfo(node); if (!info) { return false; } const fieldMap = getNodeFieldMap(context, node.parent, info); const accessor = getAccessor(node, fieldMap, info); if (!accessor) { return false; } reportWithSecondaryLocation(context, accessor); return true; } function reportWithSonarFormat(context, descriptor, message) { context.report({ ...descriptor, messageId: undefined, message: toEncodedMessage$1(message) }); } function reportWithSecondaryLocation(context, accessor) { const fieldToRefer = accessor.matchingFields[0]; const ref = accessor.info.definition === 'descriptor' ? 'variable' : 'property'; const primaryMessage = `Refactor this ${accessor.info.type} ` + `so that it actually refers to the ${ref} '${fieldToRefer.name}'.`; const secondaryLocations = [fieldToRefer.node]; const secondaryMessages = [`${ref[0].toUpperCase()}${ref.slice(1)} which should be referred.`]; context.report({ message: toEncodedMessage$1(primaryMessage, secondaryLocations, secondaryMessages), loc: accessor.node.key.loc, }); } function isPropertyDefinitionCall(call) { const objects = ['Object', 'Reflect']; const method = 'defineProperty'; const minArgs = 3; return call && objects.some(object => isMethodInvocation(call, object, method, minArgs)); } function isPropertiesDefinitionCall(call) { const object = 'Object'; const methods = ['defineProperties', 'create']; const minArgs = 2; return call && methods.some(methodName => isMethodInvocation(call, object, methodName, minArgs)); } function getAccessor(accessor, fieldMap, info) { const accessorIsPublic = accessor.type !== 'MethodDefinition' || accessor.accessibility == null || accessor.accessibility === 'public'; const statements = getFunctionBody(accessor.value); if (!fieldMap || !accessorIsPublic || !statements || statements.length > 1) { return null; } const matchingFields = findMatchingFields(fieldMap, info.name); if (matchingFields.length === 0) { return null; } return { statement: statements.length === 0 ? null : statements[0], info, matchingFields, node: accessor, }; } function getNodeAccessorInfo(accessorNode) { var _a, _b; if (accessorNode.type === 'MethodDefinition') { return getObjectOrClassAccessorInfo(accessorNode); } else { return ((_b = (_a = getMultiDescriptorsAccessorInfo(accessorNode)) !== null && _a !== void 0 ? _a : getSingleDescriptorAccessorInfo(accessorNode)) !== null && _b !== void 0 ? _b : getObjectOrClassAccessorInfo(accessorNode)); } } function getSingleDescriptorAccessorInfo(accessorNode) { const callNode = findParentCallExpression(accessorNode); const propertyNode = callNode === null || callNode === void 0 ? void 0 : callNode.arguments[1]; if (!isPropertyDefinitionCall(callNode) || !propertyNode || !isStringLiteral(propertyNode)) { return null; } return getDescriptorAccessorInfo(String(propertyNode.value), accessorNode); } function getMultiDescriptorsAccessorInfo(accessorNode) { var _a; const callNode = findParentCallExpression(accessorNode); const propertyNode = (_a = accessorNode.parent) === null || _a === void 0 ? void 0 : _a.parent; if (!isPropertiesDefinitionCall(callNode) || (propertyNode === null || propertyNode === void 0 ? void 0 : propertyNode.type) !== 'Property') { return null; } const propertyName = getName(propertyNode.key); if (!propertyName) { return null; } return getDescriptorAccessorInfo(propertyName, accessorNode); } function getDescriptorAccessorInfo(name, accessor) { const key = getName(accessor.key); if (key == null) { return null; } else { return { type: key === 'get' ? 'getter' : 'setter', name, definition: 'descriptor', refResolver: getIdentifierName, }; } } function getObjectOrClassAccessorInfo(accessor) { let name = getName(accessor.key); if (!name) { return null; } name = name.toLowerCase(); let type = null; if (accessor.kind === 'get') { type = 'getter'; } else if (accessor.kind === 'set') { type = 'setter'; } else if (accessor.value.type === 'FunctionExpression') { const offset = 3; const params = accessor.value.params; if (name.startsWith('set') && name.length > offset && params.length === 1) { type = 'setter'; name = name.substring(offset); } else if (name.startsWith('get') && name.length > offset && params.length === 0) { type = 'getter'; name = name.substring(offset); } } if (type == null) { return null; } return { type, name, definition: accessor.type === 'Property' ? 'object' : 'class', refResolver: getPropertyName, }; } function findParentCallExpression(node) { var _a, _b; const parent = (_a = node.parent) === null || _a === void 0 ? void 0 : _a.parent; const candidates = [parent, (_b = parent === null || parent === void 0 ? void 0 : parent.parent) === null || _b === void 0 ? void 0 : _b.parent]; return candidates.find(node => (node === null || node === void 0 ? void 0 : node.type) === 'CallExpression'); } function getName(key) { if (key.type === 'Literal') { return String(key.value); } else if (key.type === 'Identifier' || key.type === 'PrivateIdentifier') { return key.name; } return null; } function getNodeFieldMap(context, node, info) { if (info.definition === 'descriptor') { return getSingleVariableFieldMap(context, info.name, node); } else if ((node === null || node === void 0 ? void 0 : node.type) === 'ObjectExpression') { return getObjectExpressionFieldMap(node); } else if ((node === null || node === void 0 ? void 0 : node.type) === 'ClassBody') { return getClassBodyFieldMap(node); } else { return null; } } function getSingleVariableFieldMap(context, name, node) { const fieldMap = new Map(); for (const candidate of [name, `_${name}`, `${name}_`]) { const variable = getVariableFromName(context, candidate, node); if (variable != null && variable.defs.length > 0) { fieldMap.set(candidate, { name: candidate, node: variable.defs[0].node }); break; } } return fieldMap; } function getObjectExpressionFieldMap(node) { return getFieldMap(node.properties, prop => (isValidObjectField(prop) ? prop.key : null)); } function getClassBodyFieldMap(classBody) { const fields = getFieldMap(classBody.body, classElement => (classElement.type === 'PropertyDefinition' || classElement.type === 'TSAbstractPropertyDefinition') && !classElement.static ? classElement.key : null); const fieldsFromConstructor = fieldsDeclaredInConstructorParameters(classBody); return new Map([...fields, ...fieldsFromConstructor]); } function getFieldMap(elements, getPropertyName) { const fields = new Map(); for (const element of elements) { const propertyNameNode = getPropertyName(element); if (propertyNameNode) { const name = getName(propertyNameNode); if (name) { fields.set(name.toLowerCase(), { name, node: element, }); } } } return fields; } function isValidObjectField(prop) { return prop.type === 'Property' && !prop.method && prop.kind === 'init'; } function fieldsDeclaredInConstructorParameters(containingClass) { const fieldsFromConstructor = new Map(); const constr = getConstructorOf(containingClass); if (!constr) { return fieldsFromConstructor; } for (const parameter of constr.params) { if (parameter.type === 'TSParameterProperty' && (parameter.accessibility || parameter.readonly)) { const parameterName = getName(parameter.parameter); if (parameterName) { fieldsFromConstructor.set(parameterName, { name: parameterName, node: parameter, }); } } } return fieldsFromConstructor; } function getConstructorOf(containingClass) { for (const classElement of containingClass.body) { if (classElement.type === 'MethodDefinition' && getName(classElement.key) === 'constructor') { return classElement.value; } } } function findMatchingFields(currentFields, name) { const underscoredTargetName1 = `_${name}`; const underscoredTargetName2 = `${name}_`; const exactFieldName = currentFields.get(name); const underscoreFieldName1 = currentFields.get(underscoredTargetName1); const underscoreFieldName2 = currentFields.get(underscoredTargetName2); return [exactFieldName, underscoreFieldName1, underscoreFieldName2].filter(field => field); } function getFunctionBody(node) { if (node.type !== 'FunctionExpression' || !node.body) { return null; } return node.body.body; } function getPropertyName(expression) { if (expression && expression.type === 'MemberExpression' && expression.object.type === 'ThisExpression') { return getName(expression.property); } return null; } function getIdentifierName(expression) { return (expression === null || expression === void 0 ? void 0 : expression.type) === 'Identifier' ? expression.name : null; } function getFieldUsedInsideSimpleBody(statement, accessorInfo) { if (accessorInfo.type === 'setter') { if (statement.type === 'ExpressionStatement' && statement.expression.type === 'AssignmentExpression') { return accessorInfo.refResolver(statement.expression.left); } } else if (statement.type === 'ReturnStatement') { return accessorInfo.refResolver(statement.argument); } return null; } function isUsingAccessorFieldInBody(accessor) { if (accessor.statement == null) { return false; } const usedField = getFieldUsedInsideSimpleBody(accessor.statement, accessor.info); if (!usedField) { return true; } return accessor.matchingFields.some(matchingField => usedField === matchingField.name); } const compareNumberFunctionPlaceholder = '(a, b) => (a - b)'; const compareBigIntFunctionPlaceholder = [ '(a, b) => {', ' if (a < b) {', ' return -1;', ' } else if (a > b) {', ' return 1;', ' } else {', ' return 0;', ' }', '}', ]; const languageSensitiveOrderPlaceholder = '(a, b) => a.localeCompare(b)'; const rule$2Y = { meta: { hasSuggestions: true, messages: { provideCompareFunction: 'Provide a compare function to avoid sorting elements alphabetically.', provideCompareFunctionForArrayOfStrings: 'Provide a compare function that depends on "String.localeCompare", to reliably sort elements alphabetically.', suggestNumericOrder: 'Add a comparator function to sort in ascending order', suggestLanguageSensitiveOrder: 'Add a comparator function to sort in ascending language-sensitive order', }, }, create(context) { const sourceCode = context.sourceCode; const services = context.sourceCode.parserServices; if (!isRequiredParserServices(services)) { return {}; } return { 'CallExpression[arguments.length=0][callee.type="MemberExpression"]': (call) => { const { object, property: node } = call.callee; const text = sourceCode.getText(node); const type = getTypeFromTreeNode$1(object, services); if ([...sortLike, ...copyingSortLike].includes(text) && isArrayLikeType(type, services)) { const suggest = getSuggestions(call, type); const messageId = getMessageId(type); context.report({ node, suggest, messageId }); } }, }; function getSuggestions(call, type) { const suggestions = []; if (isNumberArray(type, services)) { suggestions.push({ messageId: 'suggestNumericOrder', fix: fixer(call, compareNumberFunctionPlaceholder), }); } else if (isBigIntArray(type, services)) { suggestions.push({ messageId: 'suggestNumericOrder', fix: fixer(call, ...compareBigIntFunctionPlaceholder), }); } else if (isStringArray(type, services)) { suggestions.push({ messageId: 'suggestLanguageSensitiveOrder', fix: fixer(call, languageSensitiveOrderPlaceholder), }); } return suggestions; } function getMessageId(type) { if (isStringArray(type, services)) { return 'provideCompareFunctionForArrayOfStrings'; } return 'provideCompareFunction'; } function fixer(call, ...placeholder) { var _a; const closingParenthesis = sourceCode.getLastToken(call, token => token.value === ')'); const indent = ' '.repeat((_a = call.loc) === null || _a === void 0 ? void 0 : _a.start.column); const text = placeholder.join(`\n${indent}`); return fixer => fixer.insertTextBefore(closingParenthesis, text); } }, }; const bypassMethods = [ 'bypassSecurityTrustHtml', 'bypassSecurityTrustStyle', 'bypassSecurityTrustScript', 'bypassSecurityTrustUrl', 'bypassSecurityTrustResourceUrl', ]; const rule$2X = { meta: { messages: { checkAngularBypass: 'Make sure disabling Angular built-in sanitization is safe here.', }, }, create(context) { return { CallExpression: (node) => { const { callee, arguments: args } = node; if (isMemberWithProperty$1(callee, ...bypassMethods) && args.length === 1 && !isHardcodedLiteral$1(args[0])) { context.report({ messageId: 'checkAngularBypass', node: callee.property, }); } }, }; }, }; function isHardcodedLiteral$1(node) { if (node.type === 'TemplateLiteral') { return node.expressions.length === 0; } else { return isLiteral$2(node); } } const ArrayDeleteExpression = "UnaryExpression[operator='delete'] > MemberExpression[computed=true]"; const rule$2W = { meta: { messages: { removeDelete: 'Remove this use of "delete".', }, }, create(context) { const services = context.sourceCode.parserServices; if (isRequiredParserServices(services)) { return { [ArrayDeleteExpression]: (node) => { const member = node; const object = member.object; if (isArray(object, services)) { raiseIssue$1(context, node); } }, }; } return {}; }, }; function raiseIssue$1(context, node) { const deleteKeyword = context.sourceCode.getFirstToken(getParent(context, node)); context.report({ messageId: 'removeDelete', loc: deleteKeyword.loc, }); } const rule$2V = interceptReportForReact(react.rules['no-array-index-key'], (context, reportDescriptor) => { const { node } = reportDescriptor; if (node.type === 'BinaryExpression') { return; } if (node.type === 'TemplateLiteral' && node.expressions.length > 1) { return; } context.report(reportDescriptor); }); const rule$2U = { meta: { messages: { noAssociativeArray: 'Make it an object if it must have named properties; otherwise, use a numeric index here.', }, }, create(context) { const services = context.sourceCode.parserServices; if (!isRequiredParserServices(services)) { return {}; } return { 'AssignmentExpression[left.type="MemberExpression"]'(node) { const { property, object } = node .left; if (isString$1(property, services) && isArray(object, services)) { context.report({ messageId: 'noAssociativeArray', node, }); } }, }; }, }; function decorate$x(rule) { return interceptReport(rule, (context, reportDescriptor) => { if ('node' in reportDescriptor) { const services = context.sourceCode.parserServices; if (isGenericType(reportDescriptor.node, services)) ; else { context.report(reportDescriptor); } } }); } const rule$2T = decorate$x(tsEslintRules['no-base-to-string']); const rule$2S = { meta: { messages: { removeOverride: 'Remove this override of "{{overridden}}".', }, }, create(context) { const overriden = new Set(); function isBuiltIn(variable) { return globalsByLibraries.builtin.includes(variable.name); } function checkVariable(variable) { if (isBuiltIn(variable)) { variable.defs.forEach(def => overriden.add(def.name)); variable.references .filter(ref => ref.isWrite()) .forEach(ref => overriden.add(ref.identifier)); } } function checkScope(scope) { scope.variables.forEach(checkVariable); scope.childScopes.forEach(checkScope); } function isTSEnumMemberId(node) { var _a; const id = node; return ((_a = id.parent) === null || _a === void 0 ? void 0 : _a.type) === 'TSEnumMember'; } return { Program: (node) => { checkScope(context.sourceCode.getScope(node)); }, 'Program:exit': () => { overriden.forEach(node => { if (!isTSEnumMemberId(node)) { context.report({ messageId: 'removeOverride', data: { overridden: node.name, }, node, }); } }); overriden.clear(); }, }; }, }; const rule$2R = { meta: { messages: { removeLabel: 'Remove this misleading "{{label}}" label.', }, }, create(context) { const stack = [0]; function enterCase() { stack.push(stack.pop() + 1); } function leaveCase() { stack.push(stack.pop() - 1); } function inCase() { return stack[stack.length - 1] > 0; } return { SwitchCase: () => { enterCase(); }, LabeledStatement: (node) => { if (inCase()) { const label = node.label; context.report({ messageId: 'removeLabel', data: { label: label.name, }, node: label, }); } }, 'FunctionExpression, FunctionDeclaration': () => { stack.push(0); }, 'SwitchCase:exit': () => { leaveCase(); }, 'FunctionExpression, FunctionDeclaration :exit': () => { stack.pop(); }, }; }, }; const INSECURE_PROTOCOLS = ['http://', 'ftp://', 'telnet://']; const LOOPBACK_PATTERN = /localhost|127(?:\.\d+){0,2}\.\d+$|\/\/(?:0*:)*?:?0*1$/; const EXCEPTION_FULL_HOSTS = [ 'www.w3.org', 'xml.apache.org', 'schemas.xmlsoap.org', 'schemas.openxmlformats.org', 'rdfs.org', 'purl.org', 'xmlns.com', 'schemas.google.com', 'a9.com', 'ns.adobe.com', 'ltsc.ieee.org', 'docbook.org', 'graphml.graphdrawing.org', 'json-schema.org', ]; const EXCEPTION_TOP_HOSTS = [ /\.example$/, /\.?example\.com$/, /\.?example\.org$/, /\.test$/, /\.?test\.com$/, ]; const rule$2Q = { meta: { messages: { insecureProtocol: 'Using {{protocol}} protocol is insecure. Use {{alternative}} instead.', }, }, create(context) { function checkNodemailer(callExpression) { const firstArg = callExpression.arguments.length > 0 ? callExpression.arguments[0] : null; if (!firstArg) { return; } const firstArgValue = getValueOfExpression(context, firstArg, 'ObjectExpression'); const ses = getProperty$1(firstArgValue, 'SES', context); if (ses && usesSesCommunication(ses)) { return; } const secure = getProperty$1(firstArgValue, 'secure', context); if (secure && (secure.value.type !== 'Literal' || secure.value.raw !== 'false')) { return; } const requireTls = getProperty$1(firstArgValue, 'requireTLS', context); if (requireTls && (requireTls.value.type !== 'Literal' || requireTls.value.raw !== 'false')) { return; } const port = getProperty$1(firstArgValue, 'port', context); if (port && (port.value.type !== 'Literal' || port.value.raw === '465')) { return; } context.report({ node: callExpression.callee, ...getMessageAndData$1('http') }); } function usesSesCommunication(sesProperty) { var _a; const configuration = getValueOfExpression(context, sesProperty.value, 'ObjectExpression'); if (!configuration) { return false; } const ses = getValueOfExpression(context, (_a = getProperty$1(configuration, 'ses', context)) === null || _a === void 0 ? void 0 : _a.value, 'NewExpression'); if (!ses || normalizeFQN(getFullyQualifiedName(context, ses)) !== '@aws_sdk.client_ses.SES') { return false; } const aws = getProperty$1(configuration, 'aws', context); if (!aws || normalizeFQN(getFullyQualifiedName(context, aws.value)) !== '@aws_sdk.client_ses') { return false; } return true; } function checkCallToFtp(callExpression) { if (callExpression.callee.type === 'MemberExpression' && callExpression.callee.property.type === 'Identifier' && callExpression.callee.property.name === 'connect') { const newExpression = getValueOfExpression(context, callExpression.callee.object, 'NewExpression'); if (!!newExpression && getFullyQualifiedName(context, newExpression.callee) === 'ftp') { const firstArg = callExpression.arguments.length > 0 ? callExpression.arguments[0] : null; if (!firstArg) { return; } const firstArgValue = getValueOfExpression(context, firstArg, 'ObjectExpression'); const secure = getProperty$1(firstArgValue, 'secure', context); if (secure && secure.value.type === 'Literal' && secure.value.raw === 'false') { context.report({ node: callExpression.callee, ...getMessageAndData$1('ftp'), }); } } } } function checkCallToRequire(callExpression) { if (callExpression.callee.type === 'Identifier' && callExpression.callee.name === 'require') { const firstArg = callExpression.arguments.length > 0 ? callExpression.arguments[0] : null; if (firstArg && firstArg.type === 'Literal' && typeof firstArg.value === 'string' && firstArg.value === 'telnet-client') { context.report({ node: firstArg, ...getMessageAndData$1('telnet'), }); } } } function isExceptionUrl(value, node) { if (INSECURE_PROTOCOLS.includes(value)) { const parent = getParent(context, node); return !((parent === null || parent === void 0 ? void 0 : parent.type) === 'BinaryExpression' && parent.operator === '+'); } return hasExceptionHost(value); } function hasExceptionHost(value) { let url$1; try { url$1 = new url.URL(value); } catch (err) { return false; } const host = url$1.hostname; return (host.length === 0 || LOOPBACK_PATTERN.test(host) || EXCEPTION_FULL_HOSTS.some(exception => exception === host) || EXCEPTION_TOP_HOSTS.some(exception => exception.test(host))); } return { Literal: (node) => { const literal = node; if (typeof literal.value === 'string') { const value = literal.value.trim().toLocaleLowerCase(); const insecure = INSECURE_PROTOCOLS.find(protocol => value.startsWith(protocol)); if (insecure && !isExceptionUrl(value, node)) { const protocol = insecure.substring(0, insecure.indexOf(':')); context.report({ ...getMessageAndData$1(protocol), node, }); } } }, CallExpression: (node) => { const callExpression = node; if (getFullyQualifiedName(context, callExpression) === 'nodemailer.createTransport') { checkNodemailer(callExpression); } checkCallToFtp(callExpression); checkCallToRequire(callExpression); }, ImportDeclaration: (node) => { const importDeclaration = node; if (typeof importDeclaration.source.value === 'string' && importDeclaration.source.value === 'telnet-client') { context.report({ node: importDeclaration.source, ...getMessageAndData$1('telnet'), }); } }, }; }, }; function getMessageAndData$1(protocol) { let alternative; switch (protocol) { case 'http': alternative = 'https'; break; case 'ftp': alternative = 'sftp, scp or ftps'; break; default: alternative = 'ssh'; } return { messageId: 'insecureProtocol', data: { protocol, alternative } }; } const sensitivePorts = [80, 8080, 8000, 8008]; const rule$2P = AwsCdkTemplate({ 'aws-cdk-lib.aws_elasticache.CfnReplicationGroup': AwsCdkCheckArguments('replicationGroup', true, 'transitEncryptionEnabled', { primitives: { invalid: [false] } }), 'aws-cdk-lib.aws_kinesis.Stream': AwsCdkCheckArguments('streamEncryptionDisabled', false, 'encryption', { fqns: { invalid: ['aws_cdk_lib.aws_kinesis.StreamEncryption.UNENCRYPTED'] } }), 'aws-cdk-lib.aws_kinesis.CfnStream': AwsCdkCheckArguments('streamEncryptionDisabled', true, 'streamEncryption'), 'aws-cdk-lib.aws_elasticloadbalancing.LoadBalancer': { callExpression: AwsCdkCheckArguments('noSSLTLS', false, 'externalProtocol', { fqns: { invalid: [ 'aws-cdk-lib.aws_elasticloadbalancing.LoadBalancingProtocol.TCP', 'aws-cdk-lib.aws_elasticloadbalancing.LoadBalancingProtocol.HTTP', ], }, }, false, 0), functionName: 'addListener', newExpression: AwsCdkCheckArguments('noSSLTLS', false, ['listeners', 'externalProtocol'], { fqns: { invalid: [ 'aws-cdk-lib.aws_elasticloadbalancing.LoadBalancingProtocol.TCP', 'aws-cdk-lib.aws_elasticloadbalancing.LoadBalancingProtocol.HTTP', ], }, }), }, 'aws-cdk-lib.aws_elasticloadbalancing.CfnLoadBalancer': AwsCdkCheckArguments('noSSLTLS', false, ['listeners', 'protocol'], { primitives: { invalid: ['tcp', 'http'], case_insensitive: true } }), 'aws-cdk-lib.aws_elasticloadbalancingv2.ApplicationLoadBalancer': { callExpression: httpOrSensitivePort(1), functionName: 'addListener', }, 'aws-cdk-lib.aws_elasticloadbalancingv2.ApplicationListener': httpOrSensitivePort(2), 'aws-cdk-lib.aws_elasticloadbalancingv2.NetworkLoadBalancer': { callExpression: (expr, ctx) => { const httpProtocol = AwsCdkCheckArguments('noSSLTLS', false, 'protocol', { fqns: { invalid: [ 'aws-cdk-lib.aws_elasticloadbalancingv2.Protocol.HTTP', 'aws-cdk-lib.aws_elasticloadbalancingv2.Protocol.TCP', 'aws-cdk-lib.aws_elasticloadbalancingv2.Protocol.UDP', 'aws-cdk-lib.aws_elasticloadbalancingv2.Protocol.TCP_UDP', ], }, }, true, 1); const node = httpProtocol(expr, ctx); if (node) { ctx.report({ messageId: 'noSSLTLS', node }); } else { const missingProtocol = AwsCdkCheckArguments('noSSLTLS', true, 'protocol', undefined, true, 1); if (missingProtocol(expr, ctx)) { const certificatesChecker = AwsCdkCheckArguments('noSSLTLS', true, 'certificates', undefined, true, 1); const portNode = certificatesChecker(expr, ctx); if (portNode) { ctx.report({ messageId: 'noSSLTLS', node: portNode }); } } } }, functionName: 'addListener', }, 'aws-cdk-lib.aws_elasticloadbalancingv2.NetworkListener': (expr, ctx) => { const httpProtocol = AwsCdkCheckArguments('noSSLTLS', false, 'protocol', { fqns: { invalid: [ 'aws-cdk-lib.aws_elasticloadbalancingv2.Protocol.TCP', 'aws-cdk-lib.aws_elasticloadbalancingv2.Protocol.UDP', 'aws-cdk-lib.aws_elasticloadbalancingv2.Protocol.TCP_UDP', ], }, }, true); const node = httpProtocol(expr, ctx); if (node) { ctx.report({ messageId: 'noSSLTLS', node }); } else { const missingProtocol = AwsCdkCheckArguments('noSSLTLS', true, 'protocol', undefined, true); if (missingProtocol(expr, ctx)) { const certificatesChecker = AwsCdkCheckArguments('noSSLTLS', true, 'certificates', undefined, true); const portNode = certificatesChecker(expr, ctx); if (portNode) { ctx.report({ messageId: 'noSSLTLS', node: portNode }); } } } }, 'aws-cdk-lib.aws_elasticloadbalancingv2.CfnListener': AwsCdkCheckArguments('noSSLTLS', false, 'protocol', { primitives: { invalid: ['HTTP', 'TCP', 'UDP', 'TCP_UDP'], case_insensitive: true } }), }, { meta: { messages: { replicationGroup: 'Make sure that disabling transit encryption is safe here.', noSSLTLS: 'Make sure that using network protocols without an SSL/TLS underlay is safe here.', streamEncryptionDisabled: 'Make sure that disabling stream encryption is safe here.', }, }, }); function httpOrSensitivePort(position) { return function (expr, ctx) { const httpProtocol = AwsCdkCheckArguments('noSSLTLS', false, 'protocol', { fqns: { invalid: ['aws-cdk-lib.aws_elasticloadbalancingv2.ApplicationProtocol.HTTP'] } }, true, position); const node = httpProtocol(expr, ctx); if (node) { ctx.report({ messageId: 'noSSLTLS', node }); } else { const missingProtocol = AwsCdkCheckArguments('noSSLTLS', true, 'protocol', undefined, true, position); if (missingProtocol(expr, ctx)) { const portChecker = AwsCdkCheckArguments('noSSLTLS', false, 'port', { primitives: { invalid: sensitivePorts } }, true, position); const portNode = portChecker(expr, ctx); if (portNode) { ctx.report({ messageId: 'noSSLTLS', node: portNode }); } } } }; } const rule$2O = { meta: { messages: { ...rule$2Q.meta.messages, ...rule$2P.meta.messages }, }, create(context) { return mergeRules(rule$2Q.create(context), rule$2P.create(context)); }, }; const rule$2N = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { let currentDoneVariable; let doneCall; let doneSegment; let currentSegment; let currentCase; const segmentFirstStatement = new Map(); function checkForTestCase(node) { const testCase = Mocha.extractTestCase(node); if (!testCase) { return; } currentCase = testCase; currentDoneVariable = undefined; if (testCase.callback.params.length === 0) { return; } const [done] = testCase.callback.params; if (done.type !== 'Identifier') { return; } const callbackScope = context.sourceCode .getScope(node) .childScopes.find(scope => scope.block === testCase.callback); if (!callbackScope) { return; } currentDoneVariable = getVariableFromIdentifier(done, callbackScope); } function checkForDoneCall(node) { const { callee } = node; if (currentDoneVariable === null || currentDoneVariable === void 0 ? void 0 : currentDoneVariable.references.some(ref => ref.identifier === callee)) { doneCall = node; doneSegment = currentSegment; } } function report(statementAfterDone) { context.report({ node: statementAfterDone, message: toEncodedMessage$1(`Move this code before the call to "done".`, [ doneCall, ]), }); doneSegment = undefined; doneCall = undefined; currentDoneVariable = undefined; } return { CallExpression: (node) => { checkForTestCase(node); checkForDoneCall(node); }, ExpressionStatement: (node) => { if (currentSegment && currentSegment === doneSegment) { report(node); } if (currentSegment && !segmentFirstStatement.has(currentSegment)) { segmentFirstStatement.set(currentSegment, node); } }, onCodePathSegmentStart(segment) { currentSegment = segment; }, onCodePathEnd(_codePath, node) { currentSegment = undefined; if ((currentCase === null || currentCase === void 0 ? void 0 : currentCase.callback) === node && doneSegment) { const statementAfterDone = doneSegment.nextSegments .map(segment => segmentFirstStatement.get(segment)) .find(stmt => !!stmt); if (statementAfterDone) { report(statementAfterDone); } } }, }; }, }; function buildParserOptions(initialOptions, usingBabel = false) { const options = { tokens: true, comment: true, loc: true, range: true, ecmaVersion: 2018, sourceType: 'module', codeFrame: false, ecmaFeatures: { jsx: true, globalReturn: false, legacyDecorators: true, }, extraFileExtensions: ['.vue'], ...initialOptions, }; if (usingBabel) { return babelParserOptions(options); } return options; } function babelParserOptions(options) { const pluginPath = `${__dirname}/../../../../node_modules`; const babelOptions = { targets: 'defaults', presets: [ `${pluginPath}/@babel/preset-react`, `${pluginPath}/@babel/preset-flow`, `${pluginPath}/@babel/preset-env`, ], plugins: [[`${pluginPath}/@babel/plugin-proposal-decorators`, { version: '2022-03' }]], babelrc: false, configFile: false, parserOpts: { allowReturnOutsideFunction: true, }, }; return { ...options, requireConfigFile: false, babelOptions }; } class Detector { constructor(probability) { if (probability < 0 || probability > 1) { throw new Error('probability should be between [0 .. 1]'); } this.probability = probability; } recognition(line) { const matchers = this.scan(line); if (matchers === 0) { return 0; } else { return 1 - Math.pow(1 - this.probability, matchers); } } } class CamelCaseDetector extends Detector { scan(line) { let previousChar = ' '; let currentChar; for (let i = 0; i < line.length; i++) { currentChar = line.charAt(i); if (isLowerCaseThenUpperCase(previousChar, currentChar)) { return 1; } previousChar = currentChar; } return 0; } } function isLowerCaseThenUpperCase(previousChar, char) { return isLowercase(previousChar) && isUpprcase(char); function isLowercase(char) { return char.toLowerCase() === char; } function isUpprcase(char) { return char.toUpperCase() === char; } } class ContainsDetector extends Detector { constructor(probability, ...strings) { super(probability); this.strings = strings; } scan(line) { var _a; const lineWithoutSpaces = line.replace(/\s+/, ''); let matchers = 0; for (const str of this.strings) { let regex = str; if (typeof str === 'string') { regex = new RegExp(escapeRegex(str), 'g'); } matchers += ((_a = lineWithoutSpaces.match(regex)) !== null && _a !== void 0 ? _a : []).length; } return matchers; } } function escapeRegex(value) { return value.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'); } class EndWithDetector extends Detector { constructor(probability, ...endOfLines) { super(probability); this.endOfLines = endOfLines; } scan(line) { for (let i = line.length - 1; i >= 0; i--) { const char = line.charAt(i); for (const endOfLine of this.endOfLines) { if (char === endOfLine) { return 1; } } if (!isWhitespace(char) && char !== '*' && char !== '/') { return 0; } } return 0; function isWhitespace(char) { return /\s/.test(char); } } } class KeywordsDetector extends Detector { constructor(probability, ...keywords) { super(probability); this.keywords = keywords; } scan(line) { let matchers = 0; const words = line.split(/[ \t(),{}]/); for (const word of words) { if (this.keywords.includes(word)) { matchers++; } } return matchers; } } class JavaScriptFootPrint { constructor() { this.detectors = new Set(); this.detectors.add(new EndWithDetector(0.95, '}', ';', '{')); this.detectors.add(new KeywordsDetector(0.7, '++', '||', '&&', '===', '?.', '??')); this.detectors.add(new KeywordsDetector(0.3, 'public', 'abstract', 'class', 'implements', 'extends', 'return', 'throw', 'private', 'protected', 'enum', 'continue', 'assert', 'boolean', 'this', 'instanceof', 'interface', 'static', 'void', 'super', 'true', 'case:', 'let', 'const', 'var', 'async', 'await', 'break', 'yield', 'typeof', 'import', 'export')); this.detectors.add(new ContainsDetector(0.95, 'for(', 'if(', 'while(', 'catch(', 'switch(', 'try{', 'else{', 'this.', 'window.', /;\s+\/\//, "import '", 'import "', 'require(')); this.detectors.add(new CamelCaseDetector(0.5)); } getDetectors() { return this.detectors; } } class CodeRecognizer { constructor(threshold, language) { this.language = language; this.threshold = threshold; } recognition(line) { let probability = 0; for (const pattern of this.language.getDetectors()) { probability = 1 - (1 - probability) * (1 - pattern.recognition(line)); } return probability; } extractCodeLines(lines) { return lines.filter(line => this.recognition(line) >= this.threshold); } isLineOfCode(line) { return this.recognition(line) - this.threshold > 0; } } const EXCLUDED_STATEMENTS = ['BreakStatement', 'LabeledStatement', 'ContinueStatement']; const recognizer = new CodeRecognizer(0.9, new JavaScriptFootPrint()); const rule$2M = { meta: { messages: { commentedCode: 'Remove this commented out code.', commentedCodeFix: 'Remove this commented out code', }, hasSuggestions: true, }, create(context) { function getGroupedComments(comments) { const groupedComments = []; let currentGroup = []; for (const comment of comments) { if (comment.type === 'Block') { groupedComments.push({ value: comment.value, nodes: [comment] }); } else if (currentGroup.length === 0 || areAdjacentLineComments(currentGroup[currentGroup.length - 1], comment)) { currentGroup.push(comment); } else { groupedComments.push({ value: currentGroup.map(lineComment => lineComment.value).join('\n'), nodes: currentGroup, }); currentGroup = [comment]; } } if (currentGroup.length > 0) { groupedComments.push({ value: currentGroup.map(lineComment => lineComment.value).join('\n'), nodes: currentGroup, }); } return groupedComments; } function areAdjacentLineComments(previous, next) { const nextCommentLine = next.loc.start.line; if (previous.loc.start.line + 1 === nextCommentLine) { const nextCodeToken = context.sourceCode.getTokenAfter(previous); return !nextCodeToken || nextCodeToken.loc.start.line > nextCommentLine; } return false; } return { 'Program:exit': () => { const groupedComments = getGroupedComments(context.sourceCode.getAllComments()); groupedComments.forEach(groupComment => { const rawTextTrimmed = groupComment.value.trim(); if (rawTextTrimmed !== '}' && containsCode(injectMissingBraces(rawTextTrimmed))) { context.report({ messageId: 'commentedCode', loc: getCommentLocation(groupComment.nodes), suggest: [ { messageId: 'commentedCodeFix', fix(fixer) { const start = groupComment.nodes[0].range[0]; const end = groupComment.nodes[groupComment.nodes.length - 1].range[1]; return fixer.removeRange([start, end]); }, }, ], }); } }); }, }; }, }; function isExpressionExclusion(statement, code) { if (statement.type === 'ExpressionStatement') { const expression = statement.expression; if (expression.type === 'Identifier' || expression.type === 'SequenceExpression' || isUnaryPlusOrMinus(expression) || isExcludedLiteral(expression) || !code.getLastToken(statement, token => token.value === ';')) { return true; } } return false; } function isExclusion(parsedBody, code) { if (parsedBody.length === 1) { const singleStatement = parsedBody[0]; return (EXCLUDED_STATEMENTS.includes(singleStatement.type) || isReturnThrowExclusion(singleStatement) || isExpressionExclusion(singleStatement, code)); } return false; } function containsCode(value) { if (!couldBeJsCode(value)) { return false; } try { const options = buildParserOptions({ filePath: 'some/filePath', tsConfigs: [], fileContent: '', fileType: 'MAIN' }, true); const result = babelESLintParser__namespace.parse(value, options); const parseResult = new eslint.SourceCode(value, result); return parseResult.ast.body.length > 0 && !isExclusion(parseResult.ast.body, parseResult); } catch (exception) { return false; } function couldBeJsCode(input) { return recognizer.extractCodeLines(input.split('\n')).length > 0; } } function injectMissingBraces(value) { var _a, _b; const openCurlyBraceNum = ((_a = value.match(/{/g)) !== null && _a !== void 0 ? _a : []).length; const closeCurlyBraceNum = ((_b = value.match(/}/g)) !== null && _b !== void 0 ? _b : []).length; const missingBraces = openCurlyBraceNum - closeCurlyBraceNum; if (missingBraces > 0) { return value + Array(missingBraces).fill('}').join(''); } else if (missingBraces < 0) { return Array(-missingBraces).fill('{').join('') + value; } else { return value; } } function getCommentLocation(nodes) { return { start: nodes[0].loc.start, end: nodes[nodes.length - 1].loc.end, }; } function isReturnThrowExclusion(statement) { if (statement.type === 'ReturnStatement' || statement.type === 'ThrowStatement') { return statement.argument == null || statement.argument.type === 'Identifier'; } return false; } function isUnaryPlusOrMinus(expression) { return (expression.type === 'UnaryExpression' && (expression.operator === '+' || expression.operator === '-')); } function isExcludedLiteral(expression) { if (expression.type === 'Literal') { return typeof expression.value === 'string' || typeof expression.value === 'number'; } return false; } const rule$2L = { meta: { messages: { removeAssignment: 'Remove this useless assignment to variable "{{variable}}".', }, }, create(context) { const codePathStack = []; const liveVariablesMap = new Map(); const readVariables = new Set(); const variableUsages = new Map(); const referencesUsedInDestructuring = new Set(); const destructuringStack = []; const codePathSegments = []; let currentCodePathSegments = []; return { ':matches(AssignmentExpression, VariableDeclarator[init])': (node) => { pushAssignmentContext(node); }, ':matches(AssignmentExpression, VariableDeclarator[init]):exit': () => { popAssignmentContext(); }, Identifier: (node) => { if (isEnumConstant(node)) { return; } checkIdentifierUsage(node); }, JSXIdentifier: (node) => { checkIdentifierUsage(node); }, ObjectPattern: () => { destructuringStack.push(new DestructuringContext()); }, 'ObjectPattern > Property > Identifier': (node) => { const destructuring = peek$1(destructuringStack); const { ref } = resolveReference(node); if (ref) { destructuring.references.push(ref); } }, 'ObjectPattern > :matches(RestElement, ExperimentalRestProperty)': () => { peek$1(destructuringStack).hasRest = true; }, 'ObjectPattern:exit': () => { const destructuring = destructuringStack.pop(); if (destructuring === null || destructuring === void 0 ? void 0 : destructuring.hasRest) { destructuring.references.forEach(ref => referencesUsedInDestructuring.add(ref)); } }, 'Program:exit': () => { lva(liveVariablesMap); liveVariablesMap.forEach(lva => { checkSegment(lva); reportNeverReadVariables(lva); }); }, onCodePathSegmentStart: (segment) => { liveVariablesMap.set(segment.id, new LiveVariables(segment)); currentCodePathSegments.push(segment); }, onCodePathStart: codePath => { pushContext(new CodePathContext$1(codePath)); codePathSegments.push(currentCodePathSegments); currentCodePathSegments = []; }, onCodePathSegmentEnd() { currentCodePathSegments.pop(); }, onCodePathEnd: () => { popContext(); currentCodePathSegments = codePathSegments.pop() || []; }, }; function pushAssignmentContext(node) { peek$1(codePathStack).assignmentStack.push(new AssignmentContext$1(node)); } function popAssignmentContext() { const assignment = peek$1(codePathStack).assignmentStack.pop(); assignment.rhs.forEach(r => processReference(r)); assignment.lhs.forEach(r => processReference(r)); } function checkSegment(liveVariables) { const willBeRead = new Set(liveVariables.out); const references = [...liveVariables.references].reverse(); references.forEach(ref => { const variable = ref.resolved; if (!variable) { return; } if (ref.isWrite()) { if (!willBeRead.has(variable) && shouldReport(ref)) { report(ref); } willBeRead.delete(variable); } if (ref.isRead()) { willBeRead.add(variable); } }); } function reportNeverReadVariables(lva) { lva.references.forEach(ref => { if (shouldReportReference(ref) && !readVariables.has(ref.resolved)) { report(ref); } }); } function shouldReport(ref) { const variable = ref.resolved; return (variable && shouldReportReference(ref) && !variableUsedOutsideOfCodePath(variable) && readVariables.has(variable)); } function shouldReportReference(ref) { const variable = ref.resolved; return (variable && isLocalVar(variable) && !isReferenceWithBasicValue(ref) && !isDefaultParameter(ref) && !referencesUsedInDestructuring.has(ref) && !variable.name.startsWith('_') && !isIncrementOrDecrement(ref) && !isNullAssignment(ref)); } function isIncrementOrDecrement(ref) { const parent = ref.identifier.parent; return parent && parent.type === 'UpdateExpression'; } function isNullAssignment(ref) { const parent = ref.identifier.parent; return (parent && parent.type === 'AssignmentExpression' && isNullLiteral(parent.right)); } function isEnumConstant(node) { return context.sourceCode.getAncestors(node).some(n => n.type === 'TSEnumDeclaration'); } function isDefaultParameter(ref) { if (ref.identifier.type !== 'Identifier') { return false; } const parent = ref.identifier.parent; return parent && parent.type === 'AssignmentPattern'; } function isLocalVar(variable) { const scope = variable.scope; const node = scope.block; return node.type !== 'Program' && node.type !== 'TSModuleDeclaration'; } function variableUsedOutsideOfCodePath(variable) { return variableUsages.get(variable).size > 1; } function isReferenceWithBasicValue(ref) { return ref.init && ref.writeExpr && isBasicValue(ref.writeExpr); } function isBasicValue(node) { switch (node.type) { case 'Literal': return node.value === '' || [0, 1, null, true, false].includes(node.value); case 'Identifier': return node.name === 'undefined'; case 'UnaryExpression': return isBasicValue(node.argument); case 'ObjectExpression': return node.properties.length === 0; case 'ArrayExpression': return node.elements.length === 0; default: return false; } } function report(ref) { context.report({ messageId: 'removeAssignment', data: { variable: ref.identifier.name, }, loc: ref.identifier.loc, }); } function checkIdentifierUsage(node) { const { ref, variable } = node.type === 'Identifier' ? resolveReference(node) : resolveJSXReference(node); if (ref) { processReference(ref); if (variable) { updateReadVariables(ref); } } if (variable) { updateVariableUsages(variable); } } function resolveJSXReference(node) { if (isJSXAttributeName(node)) { return {}; } const jsxReference = new JSXReference(node, context.sourceCode.getScope(node)); return { ref: jsxReference, variable: jsxReference.resolved }; } function isJSXAttributeName(node) { const parent = node.parent; return parent && parent.type === 'JSXAttribute' && parent.name === node; } function processReference(ref) { const assignmentStack = peek$1(codePathStack).assignmentStack; if (assignmentStack.length > 0) { const assignment = peek$1(assignmentStack); assignment.add(ref); } else { [...currentCodePathSegments].forEach(segment => { lvaForSegment(segment).add(ref); }); } } function lvaForSegment(segment) { let lva; if (liveVariablesMap.has(segment.id)) { lva = liveVariablesMap.get(segment.id); } else { lva = new LiveVariables(segment); liveVariablesMap.set(segment.id, lva); } return lva; } function updateReadVariables(reference) { const variable = reference.resolved; if (reference.isRead()) { readVariables.add(variable); } } function updateVariableUsages(variable) { const codePathId = peek$1(codePathStack).codePath.id; if (variableUsages.has(variable)) { variableUsages.get(variable).add(codePathId); } else { variableUsages.set(variable, new Set([codePathId])); } } function popContext() { codePathStack.pop(); } function pushContext(codePathContext) { codePathStack.push(codePathContext); } function resolveReference(node) { return resolveReferenceRecursively(node, context.sourceCode.getScope(node)); } function resolveReferenceRecursively(node, scope, depth = 0) { if (scope === null || depth > 2) { return { ref: null, variable: null }; } const ref = scope.references.find(r => r.identifier === node); if (ref) { return { ref, variable: ref.resolved }; } else { const variable = scope.variables.find(v => v.defs.find(def => def.name === node)); if (variable) { return { ref: null, variable }; } return resolveReferenceRecursively(node, scope.upper, depth + 1); } } }, }; let CodePathContext$1 = class CodePathContext { constructor(codePath) { this.segments = new Map(); this.assignmentStack = []; this.codePath = codePath; } }; class DestructuringContext { constructor() { this.hasRest = false; this.references = []; } } let AssignmentContext$1 = class AssignmentContext { constructor(node) { this.lhs = new Set(); this.rhs = new Set(); this.node = node; } isRhs(node) { return this.node.type === 'AssignmentExpression' ? this.node.right === node : this.node.init === node; } isLhs(node) { return this.node.type === 'AssignmentExpression' ? this.node.left === node : this.node.id === node; } add(ref) { let parent = ref.identifier; while (parent) { if (this.isLhs(parent)) { this.lhs.add(ref); break; } if (this.isRhs(parent)) { this.rhs.add(ref); break; } parent = parent.parent; } if (parent === null) { throw new Error('failed to find assignment lhs/rhs'); } } }; class JSXReference { constructor(node, scope) { this.init = false; this.writeExpr = null; this.from = scope; this.identifier = node; this.resolved = findJSXVariableInScope(node, scope); } isRead() { return true; } isReadOnly() { return true; } isReadWrite() { return false; } isWrite() { return false; } isWriteOnly() { return false; } } function findJSXVariableInScope(node, scope) { return (scope && (scope.variables.find(v => v.name === node.name) || findJSXVariableInScope(node, scope.upper))); } function peek$1(arr) { return arr[arr.length - 1]; } const rule$2K = { meta: { messages: { removeDelete: 'Remove this "delete" operator or pass an object property to it.', }, }, create(context) { return { "UnaryExpression[operator='delete'][argument.type!='MemberExpression'][argument.type!='ChainExpression']": (node) => { const { argument } = node; if (!isGlobalProperty(argument, context.sourceCode.getScope(node).references)) { context.report({ messageId: 'removeDelete', node, }); } }, }; }, }; function isGlobalProperty(expr, references) { return (expr.type === 'Identifier' && references.filter(ref => ref.identifier.name === expr.name && ref.resolved).length === 0); } tmp.setGracefulCleanup(); const DefinitelyTyped = '@types/'; const dirCache = new Map(); const cache = new Map(); function getDependencies(fileName) { let dirname = path.posix.dirname(toUnixPath(fileName)); const cached = cache.get(dirname); if (cached) { return cached; } const result = new Set(); cache.set(dirname, result); for (const packageJson of getNearestPackageJsons()) { dirname = path.posix.dirname(packageJson.filename); const dirCached = dirCache.get(dirname); if (dirCached) { dirCached.forEach(d => result.add(d)); } else { const dep = getDependenciesFromPackageJson(packageJson.contents); dep.forEach(d => result.add(d)); dirCache.set(dirname, dep); } } return result; } function getNearestPackageJsons(file) { { return []; } } function getDependenciesFromPackageJson(content) { const result = new Set(); if (content.name) { addDependencies(result, { [content.name]: '*' }); } if (content.dependencies !== undefined) { addDependencies(result, content.dependencies); } if (content.devDependencies !== undefined) { addDependencies(result, content.devDependencies); } if (content.peerDependencies !== undefined) { addDependencies(result, content.peerDependencies); } return result; } function addDependencies(result, dependencies) { Object.keys(dependencies).forEach(name => result.add(name.startsWith(DefinitelyTyped) ? name.substring(DefinitelyTyped.length) : name)); } function isSupported(filename, minVersions) { validateVersions(minVersions); return isSupportedNodeVersion(filename, minVersions.node); } function validateVersions(versions) { for (const [ref, version] of Object.entries(versions)) { if (semver__namespace.valid(version) === null) { throw new Error(`Invalid semver version: "${version}" for "${ref}"`); } } } function isSupportedNodeVersion(filename, requiredVersion) { var _a, _b; if (!requiredVersion) { return true; } const packageJsons = getNearestPackageJsons(); const versionRange = (_b = (_a = packageJsons.find(pj => { var _a; return (_a = pj.contents.engines) === null || _a === void 0 ? void 0 : _a.node; })) === null || _a === void 0 ? void 0 : _a.contents.engines) === null || _b === void 0 ? void 0 : _b.node; if (!versionRange) { return true; } const projectMinVersion = semver__namespace.minVersion(versionRange); if (!projectMinVersion) { return true; } return semver__namespace.gte(projectMinVersion, requiredVersion); } const reactNoDeprecated = react.rules['no-deprecated']; const rule$2J = { meta: { messages: { deprecated: '{{oldMethod}} is deprecated since React {{version}}{{newMethod}}', }, schema: [ { type: 'object', properties: {}, }, ], }, create(context) { function getVersionFromOptions() { var _a, _b; return (_b = (_a = context.options) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b['react-version']; } function getVersionFromPackageJson() { var _a, _b; for (const { contents: packageJson } of getNearestPackageJsons(context.filename)) { if ((_a = packageJson.dependencies) === null || _a === void 0 ? void 0 : _a.react) { return packageJson.dependencies.react; } if ((_b = packageJson.devDependencies) === null || _b === void 0 ? void 0 : _b.react) { return packageJson.devDependencies.react; } } return null; } const reactVersion = getVersionFromOptions() || getVersionFromPackageJson(); const patchedContext = reactVersion ? Object.create(context, { settings: { value: { react: { version: reactVersion } }, writable: false, }, }) : context; return reactNoDeprecated.create(patchedContext); }, }; const rule$2I = { meta: { hasSuggestions: true, schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { return { 'TSUnionType, TSIntersectionType'(node) { const sourceCode = context.sourceCode; const compositeType = node; const groupedTypes = new Map(); compositeType.types.forEach(typescriptType => { const nodeValue = sourceCode.getText(typescriptType); const nodesWithGivenType = groupedTypes.get(nodeValue); const nodeType = typescriptType; if (!nodesWithGivenType) { groupedTypes.set(nodeValue, [nodeType]); } else { nodesWithGivenType.push(nodeType); } }); groupedTypes.forEach(duplicates => { if (duplicates.length > 1) { const suggest = getSuggestions$1(compositeType, duplicates, context); const primaryNode = duplicates.splice(1, 1)[0]; const secondaryMessages = Array(duplicates.length); secondaryMessages[0] = `Original`; secondaryMessages.fill(`Another duplicate`, 1, duplicates.length); context.report({ message: toEncodedMessage$1(`Remove this duplicated type or replace with another one.`, duplicates, secondaryMessages), loc: primaryNode.loc, suggest, }); } }); }, }; }, }; function getSuggestions$1(composite, duplicates, context) { const ranges = duplicates.slice(1).map(duplicate => { const idx = composite.types.indexOf(duplicate); return [ getEnd(context, composite.types[idx - 1], composite), getEnd(context, duplicate, composite), ]; }); return [ { desc: 'Remove duplicate types', fix: fixer => ranges.map(r => fixer.removeRange(r)), }, ]; } function getEnd(context, node, composite) { let end = node; while (true) { const nextToken = context.sourceCode.getTokenAfter(end); if (nextToken && nextToken.value === ')' && nextToken.range[1] <= composite.range[1]) { end = nextToken; } else { break; } } return end.range[1]; } function decorate$w(rule) { rule.meta.hasSuggestions = true; return interceptReport(rule, (context, reportDescriptor) => { const node = reportDescriptor.node; const type = reportDescriptor.data.type; let openingBrace; if (node.type === 'SwitchStatement') { openingBrace = context.sourceCode.getTokenAfter(node.discriminant, token => token.value === '{'); } else { openingBrace = context.sourceCode.getFirstToken(node); } const closingBrace = context.sourceCode.getLastToken(node); suggestEmptyBlockQuickFix(context, reportDescriptor, type, openingBrace, closingBrace); }); } function suggestEmptyBlockQuickFix(context, descriptor, blockType, openingBrace, closingBrace) { let commentPlaceholder; if (openingBrace.loc.start.line === closingBrace.loc.start.line) { commentPlaceholder = ` /* TODO document why this ${blockType} is empty */ `; } else { const columnOffset = closingBrace.loc.start.column; const padding = ' '.repeat(columnOffset); commentPlaceholder = `\n${padding} // TODO document why this ${blockType} is empty\n${padding}`; } context.report({ ...descriptor, suggest: [ { desc: 'Insert placeholder comment', fix: fixer => fixer.insertTextAfter(openingBrace, commentPlaceholder), }, ], }); } const rule$2H = decorate$w(eslintRules['no-empty']); const rule$2G = createRegExpRule(context => { return { onRegExpLiteralEnter: (node) => { node.pattern.alternatives.forEach(({ elements }) => checkElements(elements, context)); }, }; }); function report$2(quantifier, context) { const ending = quantifier.min === 1 ? '' : 's'; const message = `Fix this reluctant quantifier that will only ever match ${quantifier.min} repetition${ending}.`; context.reportRegExpNode({ message, regexpNode: quantifier, node: context.node, }); } function checkElements(elements, context) { if (elements.length === 0) { return; } const lastElement = elements[elements.length - 1]; if (lastElement.type === 'Quantifier' && !lastElement.greedy) { report$2(lastElement, context); return; } if (elements.length === 1) { return; } const lastButOneElement = elements[elements.length - 2]; if (lastButOneElement.type === 'Quantifier' && !lastButOneElement.greedy) { if (lastElement.type === 'Assertion' && lastElement.kind === 'end') { context.reportRegExpNode({ message: `Remove the '?' from this unnecessarily reluctant quantifier.`, regexpNode: lastButOneElement, node: context.node, }); } else if (lastElement.type === 'Quantifier' && lastElement.min === 0) { report$2(lastButOneElement, context); } } } const rule$2F = createRegExpRule(context => { function checkAlternation(alternation) { const { alternatives: alts } = alternation; if (alts.length <= 1) { return; } for (let i = 0; i < alts.length; i++) { const alt = alts[i]; if (alt.elements.length === 0 && !isLastEmptyInGroup(alt)) { context.reportRegExpNode({ message: 'Remove this empty alternative.', regexpNode: alt, offset: i === alts.length - 1 ? [-1, 0] : [0, 1], node: context.node, }); } } } return { onPatternEnter: checkAlternation, onGroupEnter: checkAlternation, onCapturingGroupEnter: checkAlternation, }; }); function isLastEmptyInGroup(alt) { const group = alt.parent; return ((group.type === 'Group' || group.type === 'CapturingGroup') && last(group.alternatives) === alt && group.parent.type !== 'Quantifier'); } function isRuleFunctionNode(node) { return isFunctionNode(node) && 'parent' in node; } function decorate$v(rule) { rule.meta.hasSuggestions = true; return interceptReport(rule, reportWithQuickFixIfApplicable); } function reportWithQuickFixIfApplicable(context, reportDescriptor) { if (!('node' in reportDescriptor) || !isRuleFunctionNode(reportDescriptor.node)) { return; } const functionNode = reportDescriptor.node; if (isApplicable(functionNode)) { reportWithQuickFix(context, reportDescriptor, functionNode); } } function isApplicable(functionNode) { function isExceptionalName(node) { return (node !== null && isIdentifier(node) && (/^on[A-Z]/.test(node.name) || /noop/i.test(node.name))); } function isFunctionDeclaration() { return functionNode.type === 'FunctionDeclaration' && !isExceptionalName(functionNode.id); } function isMethodDefinition() { const methodNode = functionNode.parent; return (methodNode.type === 'MethodDefinition' && methodNode.value === functionNode && !isExceptionalName(methodNode.key)); } function isVariableDeclarator() { const variableNode = functionNode.parent; return (variableNode.type === 'VariableDeclarator' && variableNode.init === functionNode && !isExceptionalName(variableNode.id)); } return isFunctionDeclaration() || isMethodDefinition() || isVariableDeclarator(); } function reportWithQuickFix(context, reportDescriptor, func) { const name = reportDescriptor.data.name; const openingBrace = context.sourceCode.getFirstToken(func.body); const closingBrace = context.sourceCode.getLastToken(func.body); suggestEmptyBlockQuickFix(context, reportDescriptor, name, openingBrace, closingBrace); } const rule$2E = decorate$v(tsEslintRules['no-empty-function']); const rule$2D = createRegExpRule(context => { function checkEmptyGroup(group) { const { alternatives } = group; if (alternatives.every(alt => alt.elements.length === 0)) { context.reportRegExpNode({ message: 'Remove this empty group.', node: context.node, regexpNode: group, }); } } return { onGroupEnter: checkEmptyGroup, onCapturingGroupEnter: checkEmptyGroup, }; }); function decorate$u(rule) { return interceptReport(rule, (context, reportDescriptor) => { var _a; const id = reportDescriptor.node; const decl = id.parent; if (((_a = decl.extends) === null || _a === void 0 ? void 0 : _a.length) === 1 && isUtilityType(decl.extends[0])) { return; } context.report(reportDescriptor); }); } function isUtilityType(node) { return node.expression.type === 'Identifier' && UTILITY_TYPES.has(node.expression.name); } const rule$2C = decorate$u(tsEslintRules['no-empty-interface']); const APIs = new Set([ 'it', 'fit', 'xit', 'it', 'it.concurrent', 'it.concurrent.each', 'it.concurrent.only.each', 'it.concurrent.skip.each', 'it.each', 'it.failing', 'it.failing.each', 'it.only.failing', 'it.skip.failing', 'it.only', 'it.only.each', 'it.skip', 'it.skip.each', 'it.todo', 'test', 'test.concurrent', 'test.concurrent.each', 'test.concurrent.only.each', 'test.concurrent.skip.each', 'test.each', 'test.failing', 'test.failing.each', 'test.only.failing', 'test.skip.failing', 'test.only', 'test.only.each', 'test.skip', 'test.skip.each', 'test.todo', 'it', 'it.skip', 'it.only', 'test', 'test.skip', 'test.only', 'it', 'it.skip', 'it.todo', 'it.only', 'test', 'test.skip', 'test.todo', 'test.only', ]); const rule$2B = { meta: { messages: { missingTest: 'Add some tests to this file or delete it.', }, }, create(context) { const { filename } = context; if (!/\.spec\.|\.test\./.exec(filename)) { return {}; } let hasTest = false; return { CallExpression(node) { if (hasTest) { return; } const fqn = fullyQualifiedName(node.callee); if (APIs.has(fqn)) { hasTest = true; } }, 'Program:exit'() { if (!hasTest) { context.report({ messageId: 'missingTest', loc: { line: 0, column: 0 }, }); } }, }; }, }; function fullyQualifiedName(node) { switch (node.type) { case 'Identifier': return node.name; case 'MemberExpression': return `${fullyQualifiedName(node.object)}.${fullyQualifiedName(node.property)}`; default: return ''; } } const allEqualityOperators = ['!=', '==', '!==', '===']; const notEqualOperators$1 = ['!==', '!=']; const plusMinusOperators = ['+=', '-=']; const rule$2A = { meta: { messages: { replaceOperator: "Replace '{{operator}}' operator with one of '<=', '>=', '<', or '>' comparison operators.", }, }, create(context) { return { ForStatement: (node) => { const forStatement = node; if (!forStatement.test || !forStatement.update) { return; } const completeForStatement = node; const condition = completeForStatement.test; if (isEquality(condition) && isUpdateIncDec(completeForStatement.update) && !isException$1(completeForStatement, context)) { context.report({ messageId: 'replaceOperator', data: { operator: condition.operator, }, node: condition, }); } }, }; }, }; function isEquality(expression) { return (expression.type === 'BinaryExpression' && allEqualityOperators.includes(expression.operator)); } function isUpdateIncDec(expression) { if (isIncDec(expression) || expression.type === 'UpdateExpression') { return true; } else if (expression.type === 'SequenceExpression') { return expression.expressions.every(isUpdateIncDec); } return false; } function isIncDec(expression) { return (expression.type === 'AssignmentExpression' && plusMinusOperators.includes(expression.operator)); } function isException$1(forStatement, context) { return (isNontrivialConditionException(forStatement) || isTrivialIteratorException(forStatement, context)); } function isNontrivialConditionException(forStatement) { const condition = forStatement.test; const counters = []; collectCounters(forStatement.update, counters); return condition.left.type !== 'Identifier' || !counters.includes(condition.left.name); } function collectCounters(expression, counters) { let counter = undefined; if (isIncDec(expression)) { counter = expression.left; } else if (expression.type === 'UpdateExpression') { counter = expression.argument; } else if (expression.type === 'SequenceExpression') { expression.expressions.forEach(e => collectCounters(e, counters)); } if (counter && counter.type === 'Identifier') { counters.push(counter.name); } } function isTrivialIteratorException(forStatement, context) { const init = forStatement.init; const condition = forStatement.test; if (init && isNotEqual(condition)) { const updatedByOne = checkForUpdateByOne(forStatement.update, forStatement.body, context); if (updatedByOne !== 0) { const beginValue = getValue(init); const endValue = getValue(condition); return (beginValue !== undefined && endValue !== undefined && updatedByOne === Math.sign(endValue - beginValue)); } } return false; } function isNotEqual(node) { return node.type === 'BinaryExpression' && notEqualOperators$1.includes(node.operator); } function checkForUpdateByOne(update, loopBody, context) { if (isUpdateByOne(update, loopBody, context)) { if (update.operator === '++' || update.operator === '+=') { return +1; } if (update.operator === '--' || update.operator === '-=') { return -1; } } return 0; } function isUpdateByOne(update, loopBody, context) { return ((update.type === 'UpdateExpression' && !isUsedInsideBody$1(update.argument, loopBody, context)) || (isUpdateOnOneWithAssign(update) && !isUsedInsideBody$1(update.left, loopBody, context))); } function isUsedInsideBody$1(id, loopBody, context) { if (id.type === 'Identifier') { const variable = getVariableFromName(context, id.name, id); const bodyRange = loopBody.range; if (variable && bodyRange) { return variable.references.some(ref => isInBody(ref.identifier, bodyRange)); } } return false; } function isInBody(id, bodyRange) { return (id === null || id === void 0 ? void 0 : id.range) && id.range[0] > bodyRange[0] && id.range[1] < bodyRange[1]; } function getValue(node) { if (isNotEqual(node)) { return getInteger(node.right); } else if (isOneVarDeclaration(node)) { const variable = node.declarations[0]; return getInteger(variable.init); } else if (node.type === 'AssignmentExpression') { return getInteger(node.right); } return undefined; } function getInteger(node) { if (node && node.type === 'Literal' && typeof node.value === 'number') { return node.value; } return undefined; } function isOneVarDeclaration(node) { return node.type === 'VariableDeclaration' && node.declarations.length === 1; } function isUpdateOnOneWithAssign(expression) { if (isIncDec(expression)) { const right = expression.right; return right.type === 'Literal' && right.value === 1; } return false; } const rule$2z = { meta: { hasSuggestions: true, messages: { issue: 'Remove ".only()" from your test case.', quickfix: 'Remove ."only()".', }, }, create(context) { return { CallExpression: (node) => { if (isMethodCall(node)) { const { property, object } = node.callee; if (isIdentifier(property, 'only') && isIdentifier(object, 'describe', 'it', 'test')) { context.report({ messageId: 'issue', node: property, suggest: [ { fix: (fixer) => { const fixes = [fixer.remove(property)]; const dotBeforeOnly = context.sourceCode.getTokenBefore(property); if (dotBeforeOnly != null) { fixes.push(fixer.remove(dotBeforeOnly)); } return fixes; }, messageId: 'quickfix', }, ], }); } } }, }; }, }; function decorate$t(rule) { return interceptReport(rule, (context, reportDescriptor) => { const node = reportDescriptor.node; let reportedNode; if (node.type === 'CallExpression') { reportedNode = node.arguments[0]; } else { reportedNode = node.left; } context.report({ ...reportDescriptor, node: reportedNode }); }); } const rule$2y = decorate$t(eslintRules['no-extend-native']); function decorate$s(rule) { return interceptReport(rule, reportExempting$6(isProtectionSemicolon)); } function reportExempting$6(exemptionCondition) { return (context, reportDescriptor) => { if ('node' in reportDescriptor && !exemptionCondition(context, reportDescriptor.node)) { context.report(reportDescriptor); } }; } function isProtectionSemicolon(context, node) { if (node.type !== 'EmptyStatement') { return false; } const previousToken = context.sourceCode.getTokenBefore(node); if (!isNodeOnNewLineAfterToken(node, previousToken)) { return false; } const nextToken = context.sourceCode.getTokenAfter(node); return isParenOrBracket(nextToken); } function isNodeOnNewLineAfterToken(node, token) { if (node.loc == null) { return false; } else if (token == null) { return true; } else { return token.loc.end.line < node.loc.start.line; } } function isParenOrBracket(token) { return (token === null || token === void 0 ? void 0 : token.type) === 'Punctuator' && (token.value === '[' || token.value === '('); } const rule$2x = decorate$s(tsEslintRules['no-extra-semi']); function decorate$r(rule) { rule.meta.messages['noFindDOMNode'] = "Do not use findDOMNode. It doesn't work with function components and is deprecated in StrictMode."; return interceptReport(rule, (context, reportDescriptor) => { context.report({ ...reportDescriptor, }); }); } const rule$2w = decorate$r(react.rules['no-find-dom-node']); const rule$2v = { meta: { messages: { useForOf: 'Use "for...of" to iterate over this "{{iterable}}".', }, }, create(context) { const services = context.sourceCode.parserServices; if (!isRequiredParserServices(services)) { return {}; } return { ForInStatement: (node) => { const type = getTypeFromTreeNode$1(node.right, services); if (isIterable(type)) { const iterable = type.symbol ? type.symbol.name : 'String'; context.report({ messageId: 'useForOf', data: { iterable }, loc: context.sourceCode.getFirstToken(node).loc, }); } }, }; function isIterable(type) { return isCollection(type) || isStringType$1(type) || isArrayLikeType(type, services); } }, }; function isCollection(type) { return (type.symbol !== undefined && [ 'Array', 'Int8Array', 'Uint8Array', 'Uint8ClampedArray', 'Int16Array', 'Uint16Array', 'Int32Array', 'Uint32Array', 'Float32Array', 'Float64Array', 'BigInt64Array', 'BigUint64Array', 'Set', 'Map', ].includes(type.symbol.name)); } const rule$2u = { meta: { messages: { blockedFunction: 'Do not use function declarations within blocks.', }, }, create(context) { return { ':not(FunctionDeclaration, FunctionExpression, ArrowFunctionExpression) > BlockStatement > FunctionDeclaration': (node) => { context.report({ messageId: 'blockedFunction', loc: locations.getMainFunctionTokenLocation(node, getParent(context, node), context), }); }, }; }, }; const rule$2t = { meta: { hasSuggestions: true, messages: { removeThis: `Remove the use of "this".`, suggestRemoveThis: 'Remove "this"', suggestUseWindow: 'Replace "this" with "window" object', }, }, create(context) { return { 'MemberExpression[object.type="ThisExpression"]'(node) { const memberExpression = node; const scopeType = context.sourceCode.getScope(node).variableScope.type; const isInsideClass = context.sourceCode .getAncestors(node) .some(ancestor => ancestor.type === 'ClassDeclaration' || ancestor.type === 'ClassExpression'); if ((scopeType === 'global' || scopeType === 'module') && !isInsideClass) { const suggest = []; if (!memberExpression.computed) { const propertyText = context.sourceCode.getText(memberExpression.property); suggest.push({ messageId: 'suggestRemoveThis', fix: fixer => fixer.replaceText(node, propertyText), }, { messageId: 'suggestUseWindow', fix: fixer => fixer.replaceText(memberExpression.object, 'window'), }); } context.report({ messageId: 'removeThis', node: memberExpression.object, suggest, }); } }, }; }, }; const illegalNames = ['arguments']; const objectPrototypeProperties = [ 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf', ]; const deprecatedNames = ['escape', 'unescape']; const getDeclarationIssue = (redeclareType) => (name) => ({ messageId: 'forbidDeclaration', data: { symbol: name, type: redeclareType }, }); const getModificationIssue = (functionName) => ({ messageId: 'removeModification', data: { symbol: functionName }, }); const rule$2s = { meta: { messages: { removeModification: 'Remove the modification of "{{symbol}}".', forbidDeclaration: 'Do not use "{{symbol}}" to declare a {{type}} - use another name.', }, }, create(context) { return { 'FunctionDeclaration, FunctionExpression'(node) { const func = node; reportBadUsageOnFunction(func, func.id, context); }, ArrowFunctionExpression(node) { reportBadUsageOnFunction(node, undefined, context); }, VariableDeclaration(node) { node.declarations.forEach(decl => { reportGlobalShadowing(decl.id, getDeclarationIssue('variable'), context, decl.init != null); }); }, UpdateExpression(node) { reportGlobalShadowing(node.argument, getModificationIssue, context, true); }, AssignmentExpression(node) { reportGlobalShadowing(node.left, getModificationIssue, context, true); }, CatchClause(node) { reportGlobalShadowing(node.param, getDeclarationIssue('variable'), context, true); }, }; }, }; function reportBadUsageOnFunction(func, id, context) { reportGlobalShadowing(id, getDeclarationIssue('function'), context, true); func.params.forEach(p => { reportGlobalShadowing(p, getDeclarationIssue('parameter'), context, false); }); } function reportGlobalShadowing(node, buildMessageAndData, context, isWrite) { if (node) { switch (node.type) { case 'Identifier': { if (isGlobalShadowing(node.name, isWrite) && !isShadowingException(node.name)) { context.report({ node, ...buildMessageAndData(node.name), }); } break; } case 'RestElement': reportGlobalShadowing(node.argument, buildMessageAndData, context, true); break; case 'ObjectPattern': node.properties.forEach(prop => { if (prop.type === 'Property') { reportGlobalShadowing(prop.value, buildMessageAndData, context, true); } else { reportGlobalShadowing(prop.argument, buildMessageAndData, context, true); } }); break; case 'ArrayPattern': node.elements.forEach(elem => { reportGlobalShadowing(elem, buildMessageAndData, context, true); }); break; case 'AssignmentPattern': reportGlobalShadowing(node.left, buildMessageAndData, context, true); break; } } } function isGlobalShadowing(name, isWrite) { return isIllegalName(name) || isBuiltInName(name) || isUndefinedShadowing(isWrite, name); } function isIllegalName(name) { return illegalNames.includes(name); } function isBuiltInName(name) { return globalsByLibraries.builtin.includes(name); } function isUndefinedShadowing(isWrite, name) { return isWrite && name === 'undefined'; } function isShadowingException(name) { return isObjectPrototypeProperty(name) || isDeprecatedName(name); } function isObjectPrototypeProperty(name) { return objectPrototypeProperties.includes(name); } function isDeprecatedName(name) { return deprecatedNames.includes(name); } const rule$2r = { meta: { messages: { reviewCredential: 'Review this potentially hardcoded credential.', }, schema: [ { type: 'object', properties: { credentialWords: { type: 'array', items: { type: 'string', }, }, }, }, ], }, create(context) { const dir = path.dirname(context.physicalFilename); const parts = dir.split(path.sep).map(part => part.toLowerCase()); if (parts.includes('l10n')) { return {}; } const [{ credentialWords: variableNames }] = context.options; const literalRegExp = variableNames.map(name => new RegExp(`${name}=.+`)); return { VariableDeclarator: (node) => { const declaration = node; checkAssignment(context, variableNames, declaration.id, declaration.init); }, AssignmentExpression: (node) => { const assignment = node; checkAssignment(context, variableNames, assignment.left, assignment.right); }, Property: (node) => { const property = node; checkAssignment(context, variableNames, property.key, property.value); }, Literal: (node) => { const literal = node; checkLiteral(context, literalRegExp, literal); }, }; }, }; function checkAssignment(context, patterns, variable, initializer) { if (initializer && isStringLiteral(initializer) && initializer.value.length > 0 && patterns.some(pattern => context.sourceCode.getText(variable).includes(pattern))) { context.report({ messageId: 'reviewCredential', node: initializer, }); } } function checkLiteral(context, patterns, literal) { if (isStringLiteral(literal) && patterns.some(pattern => pattern.test(literal.value))) { context.report({ messageId: 'reviewCredential', node: literal, }); } } const netMaskRegex = /(^[^/]+)\/\d{1,3}$/; const acceptedIpAddresses = ['255.255.255.255', '::1', '::', '0:0:0:0:0:0:0:1', '0:0:0:0:0:0:0:0']; const ipV4Octets = 4; const ipV4MappedToV6Prefix = '::ffff:0:'; const acceptedIpV6Starts = [ '2001:db8:', ]; const acceptedIpV4Starts = [ '127.', '0.', '2.5', '192.0.2.', '198.51.100.', '203.0.113.', ]; const rule$2q = { meta: { messages: { checkIP: 'Make sure using a hardcoded IP address {{ip}} is safe here.', }, }, create(context) { function isException(ip) { return (acceptedIpV6Starts.some(prefix => ip.startsWith(prefix)) || acceptedIpV4Starts.some(prefix => ip.startsWith(ipV4MappedToV6Prefix + prefix) || ip.startsWith(prefix)) || acceptedIpAddresses.includes(ip)); } function isIPV4OctalOrHex(ip) { const digits = ip.split('.'); if (digits.length !== ipV4Octets) { return false; } const decimalDigits = []; for (const digit of digits) { if (digit.match(/^0[0-7]*$/)) { decimalDigits.push(parseInt(digit, 8)); } else if (digit.match(/^0[xX][0-9a-fA-F]+$/)) { decimalDigits.push(parseInt(digit, 16)); } else { return false; } } const convertedIp = `${decimalDigits[0]}.${decimalDigits[1]}.${decimalDigits[2]}.${decimalDigits[3]}`; return !isException(convertedIp) && net.isIP(convertedIp) !== 0; } return { Literal(node) { const { value } = node; if (typeof value !== 'string') { return; } let ip = value; const result = value.match(netMaskRegex); if (result) { ip = result[1]; } if ((!isException(ip) && net.isIP(ip) !== 0) || isIPV4OctalOrHex(ip)) { context.report({ node, messageId: 'checkIP', data: { ip: value, }, }); } }, }; }, }; const REACT_MODULE = 'react'; const REACT_PATTERN = /^[^a-z]/; const HOOK_FUNCTION = 'useState'; const rule$2p = { meta: { messages: { noHookSetterInBody: 'Remove this state setter call, perhaps move it to an event handler or JSX attribute', }, }, create(context) { function isHookCall(node) { return (getFullyQualifiedName(context, node) === `${REACT_MODULE}.${HOOK_FUNCTION}` && node.arguments.length === 1); } function getReactComponentScope(node) { const scope = context.sourceCode.getScope(node); const isReact = isFunctionNode(scope.block) && matchesReactComponentName(scope.block, 1); return isReact ? scope : null; } function isInsideFunctionScope(scope, node) { function searchUpperFunctionScope(current) { if (current === null) { return null; } else if (current.type === 'function') { return current; } else { return searchUpperFunctionScope(current.upper); } } return (scope !== null && searchUpperFunctionScope(context.sourceCode.getScope(node)) === scope); } function isInsideConditional(node) { return (findFirstMatchingLocalAncestor(node, n => n.type === 'IfStatement') !== undefined); } let reactComponentScope; const setters = []; return { ':function'(node) { reactComponentScope !== null && reactComponentScope !== void 0 ? reactComponentScope : (reactComponentScope = getReactComponentScope(node)); }, ':function:exit'(node) { if (context.sourceCode.getScope(node) === reactComponentScope) { reactComponentScope = null; setters.length = 0; } }, ['VariableDeclarator[init.type="CallExpression"]' + ':has(ArrayPattern[elements.length=2][elements.0.type="Identifier"][elements.1.type="Identifier"])'](node) { if (!isInsideFunctionScope(reactComponentScope, node)) { return; } const hookDeclarator = node; if (isHookCall(hookDeclarator.init)) { const variable = getVariableFromName(context, hookDeclarator.id.elements[1].name, node); if (variable != null) { setters.push(variable); } } }, 'CallExpression[callee.type="Identifier"][arguments.length=1]'(node) { if (!isInsideFunctionScope(reactComponentScope, node) || setters.length === 0 || isInsideConditional(node)) { return; } const maybeSetterCall = node; const calleeVariable = getVariableFromName(context, maybeSetterCall.callee.name, node); if (setters.some(variable => variable === calleeVariable)) { context.report({ messageId: 'noHookSetterInBody', node: node.callee, }); } }, }; }, }; function hasParent(node) { return node.parent != null; } function matchesReactComponentName(node, max = 0) { if (node == null) { return false; } else if (isIdentifier(node)) { return REACT_PATTERN.test(node.name); } else if (node.type === 'FunctionDeclaration') { return matchesReactComponentName(node.id); } else if (node.type === 'VariableDeclarator') { return matchesReactComponentName(node.id); } else if (node.type === 'AssignmentExpression') { return matchesReactComponentName(node.left); } else if (node.type === 'MemberExpression') { return matchesReactComponentName(node.property); } else if (hasParent(node) && max > 0) { return matchesReactComponentName(node.parent, max - 1); } else { return false; } } const rule$2o = { meta: { messages: { handleException: "Handle this exception or don't catch it at all.", }, }, create(context) { return { 'CatchClause[param.type="Identifier"]'(node) { const param = node.param; const scope = context.sourceCode.getScope(node); const variable = getVariableFromScope(scope, param.name); if ((variable === null || variable === void 0 ? void 0 : variable.references.length) === 0) { context.report({ messageId: 'handleException', node, }); } }, }; }, }; const rule$2n = { meta: { messages: { removeOrAddDependency: 'Either remove this import or add it as a dependency.', }, schema: [ { type: 'object', properties: { whitelist: { type: 'array', items: { type: 'string', }, }, }, }, ], }, create(context) { const options = context.options; const whitelist = options.length > 0 ? options[0].whitelist : []; const dependencies = getDependencies(context.filename); const aliasedPathsMappingPatterns = extractPathMappingPatterns(context.sourceCode.parserServices); const baseUrl = getBaseUrl(context.sourceCode.parserServices); if (aliasedPathsMappingPatterns === 'matchAll') { return {}; } return { CallExpression: (node) => { const call = node; if (call.callee.type === 'Identifier' && call.callee.name === 'require' && call.arguments.length === 1) { const [argument] = call.arguments; if (argument.type === 'Literal') { const requireToken = call.callee; raiseOnImplicitImport(argument, requireToken.loc, dependencies, whitelist, aliasedPathsMappingPatterns, baseUrl, context); } } }, ImportDeclaration: (node) => { const module = node.source; const importToken = context.sourceCode.getFirstToken(node); raiseOnImplicitImport(module, importToken.loc, dependencies, whitelist, aliasedPathsMappingPatterns, baseUrl, context); }, }; }, }; function raiseOnImplicitImport(module, loc, dependencies, whitelist, aliasedPathsMappingPatterns, baseUrl, context) { const moduleName = module.value; if (typeof moduleName !== 'string') { return; } if (ts__namespace.isExternalModuleNameRelative(moduleName)) { return; } if (aliasedPathsMappingPatterns.some(pattern => pattern.isApplicableTo(moduleName))) { return; } if (['node:', 'data:', 'file:'].some(prefix => moduleName.startsWith(prefix))) { return; } if (baseUrl) { const underBaseUrlPath = path__namespace.join(baseUrl, moduleName); const extensions = ['', '.ts', '.d.ts', '.tsx', '.js', '.jsx', '.vue', '.mjs']; if (extensions.some(extension => fs__namespace.existsSync(underBaseUrlPath + extension))) { return; } } const packageName = getPackageName(moduleName); if (!whitelist.includes(packageName) && !builtins.includes(packageName) && !dependencies.has(packageName)) { context.report({ messageId: 'removeOrAddDependency', loc, }); } } function getPackageName(name) { const parts = name.split('/'); if (!name.startsWith('@')) { return parts[0]; } else { return `${parts[0]}/${parts[1]}`; } } class PathMappingNoAsteriskPattern { constructor(value) { this.value = value; } isApplicableTo(name) { return name === this.value; } } class PathMappingSingleAsteriskPattern { constructor(prefix, suffix) { this.prefix = prefix; this.suffix = suffix; } isApplicableTo(name) { return name.startsWith(this.prefix) && name.endsWith(this.suffix); } } const PATH_MAPPING_ASTERISK_PATTERN = /^([^*]*)\*([^*]*)$/; const PATH_MAPPING_ASTERISK_PATTERN_PREFIX_IDX = 1; const PATH_MAPPING_ASTERISK_PATTERN_SUFFIX_IDX = 2; function extractPathMappingPatterns(parserServices) { var _a, _b; const compilerOptions = (_a = parserServices.program) === null || _a === void 0 ? void 0 : _a.getCompilerOptions(); const paths = (_b = compilerOptions === null || compilerOptions === void 0 ? void 0 : compilerOptions.paths) !== null && _b !== void 0 ? _b : []; const pathMappingPatterns = []; for (const p in paths) { if (p === '*') { return 'matchAll'; } else { const m = p.match(PATH_MAPPING_ASTERISK_PATTERN); if (m) { pathMappingPatterns.push(new PathMappingSingleAsteriskPattern(m[PATH_MAPPING_ASTERISK_PATTERN_PREFIX_IDX], m[PATH_MAPPING_ASTERISK_PATTERN_SUFFIX_IDX])); } else if (!p.includes('*')) { pathMappingPatterns.push(new PathMappingNoAsteriskPattern(p)); } else ; } } return pathMappingPatterns; } function getBaseUrl(parserServices) { var _a; return (_a = parserServices.program) === null || _a === void 0 ? void 0 : _a.getCompilerOptions().baseUrl; } const excludedNames = new Set(flatMap(Object.values(globalsByLibraries), globals => globals)); const rule$2m = { meta: { messages: { explicitModifier: 'Add the "let", "const" or "var" keyword to this declaration of "{{variable}}" to make it explicit.', }, }, create(context) { return { 'Program:exit'(node) { const globalScope = context.sourceCode.getScope(node); const alreadyReported = new Set(); globalScope.through .filter(ref => ref.isWrite()) .forEach(ref => { const name = ref.identifier.name; if (!alreadyReported.has(name) && !excludedNames.has(name)) { alreadyReported.add(name); context.report({ messageId: 'explicitModifier', data: { variable: name, }, node: ref.identifier, }); } }); }, }; }, }; const rule$2l = { meta: { hasSuggestions: true, messages: { inMisuse: 'Use "indexOf" or "includes" (available from ES2016) instead.', suggestIndexOf: 'Replace with "indexOf" method', suggestIncludes: 'Replace with "includes" method', }, }, create(context) { const services = context.sourceCode.parserServices; function prototypeProperty(node) { const expr = node; if (expr.type !== 'Literal' || typeof expr.value !== 'string') { return false; } return ['indexOf', 'lastIndexOf', 'forEach', 'map', 'filter', 'every', 'some'].includes(expr.value); } if (isRequiredParserServices(services)) { return { "BinaryExpression[operator='in']": (node) => { const { left, right } = node; if (isArray(right, services) && !prototypeProperty(left) && !isNumber$2(left, services)) { const leftText = context.sourceCode.getText(left); const rightText = context.sourceCode.getText(right); context.report({ messageId: 'inMisuse', node, suggest: [ { messageId: 'suggestIndexOf', fix: fixer => fixer.replaceText(node, `${rightText}.indexOf(${leftText}) > -1`), }, { messageId: 'suggestIncludes', fix: fixer => fixer.replaceText(node, `${rightText}.includes(${leftText})`), }, ], }); } }, }; } return {}; }, }; const assertionFunctions = [ 'a', 'an', 'include', 'includes', 'contain', 'contains', 'equal', 'equals', 'eq', 'eql', 'eqls', 'above', 'gt', 'greaterThan', 'least', 'gte', 'below', 'lt', 'lessThan', 'most', 'lte', 'within', 'instanceof', 'instanceOf', 'property', 'ownPropertyDescriptor', 'haveOwnPropertyDescriptor', 'lengthOf', 'length', 'match', 'matches', 'string', 'key', 'keys', 'throw', 'throws', 'Throw', 'respondTo', 'respondsTo', 'satisfy', 'satisfies', 'closeTo', 'approximately', 'members', 'oneOf', 'change', 'changes', 'increase', 'increases', 'decrease', 'decreases', 'by', 'fail', ]; const gettersOrModifiers = [ 'to', 'be', 'been', 'is', 'that', 'which', 'and', 'has', 'have', 'with', 'at', 'of', 'same', 'but', 'does', 'still', 'not', 'deep', 'nested', 'own', 'ordered', 'any', 'all', 'itself', 'should', ]; const rule$2k = { create(context) { return { ExpressionStatement(node) { const exprStatement = node; if (exprStatement.expression.type === 'MemberExpression') { const { property } = exprStatement.expression; if (isTestAssertion(exprStatement.expression)) { if (isIdentifier(property, ...assertionFunctions)) { context.report({ node: property, message: `Call this '${property.name}' assertion.`, }); } if (isIdentifier(property, ...gettersOrModifiers)) { context.report({ node: property, message: `Complete this assertion; '${property.name}' doesn't assert anything by itself.`, }); } } } if (isExpectCall(exprStatement.expression)) { const { callee } = exprStatement.expression; context.report({ node: callee, message: `Complete this assertion; '${callee.name}' doesn't assert anything by itself.`, }); } }, }; }, }; function isTestAssertion(node) { const { object, property } = node; if (isIdentifier(object) && isIdentifier(property, 'should')) { return true; } if (isExpectCall(object) || isIdentifier(object, 'assert', 'expect', 'should')) { return true; } else if (object.type === 'MemberExpression') { return isTestAssertion(object); } else if (object.type === 'CallExpression' && object.callee.type === 'MemberExpression') { return isTestAssertion(object.callee); } return false; } function isExpectCall(node) { return (node.type === 'CallExpression' && isIdentifier(node.callee, 'expect') && !isNumberLiteral(node.arguments[0])); } const rule$2j = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { const sourceCode = context.sourceCode; const functionContextStack = []; const checkOnFunctionExit = (node) => checkFunctionLikeDeclaration(node, functionContextStack[functionContextStack.length - 1]); function checkFunctionLikeDeclaration(node, functionContext) { if (!functionContext || (!!node.returnType && declaredReturnTypeContainsVoidOrNeverTypes(node.returnType.typeAnnotation))) { return; } checkFunctionForImplicitReturn(functionContext); if (hasInconsistentReturns(functionContext)) { const [secondaryLocationsHolder, secondaryLocationMessages] = getSecondaryLocations(functionContext, node); const message = toEncodedMessage$1(`Refactor this function to use "return" consistently.`, secondaryLocationsHolder, secondaryLocationMessages); context.report({ message, loc: locations.getMainFunctionTokenLocation(node, getParent(context, node), context), }); } } function checkFunctionForImplicitReturn(functionContext) { functionContext.containsImplicitReturn = functionContext.codePath.currentSegments.some(segment => segment.reachable); } function getSecondaryLocations(functionContext, node) { const secondaryLocationsHolder = functionContext.returnStatements.slice(); const secondaryLocationMessages = functionContext.returnStatements.map(returnStatement => returnStatement.argument ? 'Return with value' : 'Return without value'); if (functionContext.containsImplicitReturn) { const closeCurlyBraceToken = sourceCode.getLastToken(node, token => token.value === '}'); if (!!closeCurlyBraceToken) { secondaryLocationsHolder.push(closeCurlyBraceToken); secondaryLocationMessages.push('Implicit return without value'); } } return [secondaryLocationsHolder, secondaryLocationMessages]; } return { onCodePathStart(codePath) { functionContextStack.push({ codePath, containsReturnWithValue: false, containsReturnWithoutValue: false, containsImplicitReturn: false, returnStatements: [], }); }, onCodePathEnd() { functionContextStack.pop(); }, ReturnStatement(node) { const currentContext = functionContextStack[functionContextStack.length - 1]; if (!!currentContext) { const returnStatement = node; currentContext.containsReturnWithValue = currentContext.containsReturnWithValue || !!returnStatement.argument; currentContext.containsReturnWithoutValue = currentContext.containsReturnWithoutValue || !returnStatement.argument; currentContext.returnStatements.push(returnStatement); } }, 'FunctionDeclaration:exit': checkOnFunctionExit, 'FunctionExpression:exit': checkOnFunctionExit, 'ArrowFunctionExpression:exit': checkOnFunctionExit, }; }, }; function hasInconsistentReturns(functionContext) { return (functionContext.containsReturnWithValue && (functionContext.containsReturnWithoutValue || functionContext.containsImplicitReturn)); } function declaredReturnTypeContainsVoidOrNeverTypes(returnTypeNode) { return (isVoidType(returnTypeNode) || (returnTypeNode.type === 'TSUnionType' && returnTypeNode.types.some(declaredReturnTypeContainsVoidOrNeverTypes))); } function isVoidType(typeNode) { return (typeNode.type === 'TSUndefinedKeyword' || typeNode.type === 'TSVoidKeyword' || typeNode.type === 'TSNeverKeyword'); } const message$1 = `Review this expression to be sure that the concatenation was intended.`; const objectLikeTypes = new Set(['object', 'Object']); const rule$2i = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { const services = context.sourceCode.parserServices; if (!isRequiredParserServices(services)) { return {}; } const checker = services.program.getTypeChecker(); function isStringPlusNonString(type1, type2) { if (isLiteralType(type1) || isLiteralType(type2)) { return false; } const isObjectLike = objectLikeTypes.has(checker.typeToString(type2)); return isStringType(type1) && !isObjectLike && !checker.isTypeAssignableTo(type1, type2); } function getOperatorLocation(left, right) { return context.sourceCode .getTokensBetween(left, right) .find(token => token.value === '+' || token.value === '+=').loc; } function checkConcatenation(left, right) { if (isStringLiteral(left) || isStringLiteral(right) || isConcatenation$1(left) || isConcatenation$1(right)) { return; } const leftType = getTypeFromTreeNode$1(left, services); const rightType = getTypeFromTreeNode$1(right, services); if (isStringPlusNonString(leftType, rightType) || isStringPlusNonString(rightType, leftType)) { context.report({ message: toEncodedMessage$1(message$1, [left, right], [ `left operand has type ${checker.typeToString(leftType)}.`, `right operand has type ${checker.typeToString(rightType)}.`, ]), loc: getOperatorLocation(left, right), }); } } return { 'AssignmentExpression[operator="+="]'(node) { checkConcatenation(node.left, node.right); }, 'BinaryExpression[operator="+"]'(node) { checkConcatenation(node.left, node.right); }, }; }, }; function isStringType(typ) { return (typ.getFlags() & ts__namespace.TypeFlags.StringLike) !== 0; } function isLiteralType(type) { if (type.isUnion()) { return type.types.some(t => isLiteralType(t)); } return type.isStringLiteral(); } function isConcatenation$1(node) { return node.type === 'BinaryExpression' && node.operator === '+'; } const noUnmodifiedLoopEslint = eslintRules['no-unmodified-loop-condition']; const rule$2h = { meta: { messages: { ...noUnmodifiedLoopEslint.meta.messages }, }, create(context) { const alreadyRaisedSymbols = new Set(); const ruleDecoration = interceptReport(noUnmodifiedLoopEslint, function (context, descriptor) { var _a, _b, _c, _d, _e; const node = descriptor.node; const symbol = (_a = context.getScope().references.find(v => v.identifier === node)) === null || _a === void 0 ? void 0 : _a.resolved; if (isUndefined(node) || (symbol && alreadyRaisedSymbols.has(symbol))) { return; } for (const reference of (_b = symbol === null || symbol === void 0 ? void 0 : symbol.references) !== null && _b !== void 0 ? _b : []) { const id = reference.identifier; if (((_c = id.parent) === null || _c === void 0 ? void 0 : _c.type) === 'CallExpression' && id.parent.arguments.includes(id)) { return; } if (((_d = id.parent) === null || _d === void 0 ? void 0 : _d.type) === 'MemberExpression' && ((_e = id.parent.parent) === null || _e === void 0 ? void 0 : _e.type) === 'CallExpression' && id.parent.object === id) { return; } } if (symbol) { alreadyRaisedSymbols.add(symbol); } context.report(descriptor); }); const MESSAGE = "Correct this loop's end condition to not be invariant."; const ruleExtension = { create(context) { return { WhileStatement: checkWhileStatement, DoWhileStatement: checkWhileStatement, ForStatement: (node) => { const { test, body } = node; if (!test || (test.type === 'Literal' && test.value === true)) { const hasEndCondition = LoopVisitor.hasEndCondition(body, context); if (!hasEndCondition) { const firstToken = context.sourceCode.getFirstToken(node); context.report({ loc: firstToken.loc, message: MESSAGE, }); } } }, }; function checkWhileStatement(node) { const whileStatement = node; if (whileStatement.test.type === 'Literal' && whileStatement.test.value === true) { const hasEndCondition = LoopVisitor.hasEndCondition(whileStatement.body, context); if (!hasEndCondition) { const firstToken = context.sourceCode.getFirstToken(node); context.report({ loc: firstToken.loc, message: MESSAGE }); } } } }, }; const decorationListeners = ruleDecoration.create(context); const extensionListeners = ruleExtension.create(context); return mergeRules(decorationListeners, extensionListeners); }, }; class LoopVisitor { constructor() { this.hasEndCondition = false; } static hasEndCondition(node, context) { const visitor = new LoopVisitor(); visitor.visit(node, context); return visitor.hasEndCondition; } visit(root, context) { const visitNode = (node, isNestedLoop = false) => { switch (node.type) { case 'WhileStatement': case 'DoWhileStatement': case 'ForStatement': isNestedLoop = true; break; case 'FunctionExpression': case 'FunctionDeclaration': return; case 'BreakStatement': if (!isNestedLoop || !!node.label) { this.hasEndCondition = true; } break; case 'YieldExpression': case 'ReturnStatement': case 'ThrowStatement': this.hasEndCondition = true; return; } childrenOf$1(node, context.sourceCode.visitorKeys).forEach(child => visitNode(child, isNestedLoop)); }; visitNode(root); } } const permissions = ['geolocation', 'camera', 'microphone', 'notifications', 'persistent-storage']; const rule$2g = { meta: { messages: { checkPermission: 'Make sure the use of the {{feature}} is necessary.', }, schema: [ { type: 'object', properties: { permissions: { type: 'array', items: { type: 'string', }, }, }, }, ], }, create(context) { return { 'CallExpression[callee.type="MemberExpression"]'(node) { const call = node; const callee = call.callee; if (isNavigatorMemberExpression(callee, 'permissions', 'query') && call.arguments.length > 0) { checkPermissions(context, call); return; } if (context.options[0].permissions.includes('geolocation') && isNavigatorMemberExpression(callee, 'geolocation', 'watchPosition', 'getCurrentPosition')) { context.report({ messageId: 'checkPermission', data: { feature: 'geolocation', }, node: callee, }); return; } if (isNavigatorMemberExpression(callee, 'mediaDevices', 'getUserMedia') && call.arguments.length > 0) { const firstArg = getValueOfExpression(context, call.arguments[0], 'ObjectExpression'); checkForCameraAndMicrophonePermissions(context, callee, firstArg); return; } if (context.options[0].permissions.includes('notifications') && isMemberExpression(callee, 'Notification', 'requestPermission')) { context.report({ messageId: 'checkPermission', data: { feature: 'notifications', }, node: callee, }); return; } if (context.options[0].permissions.includes('persistent-storage') && isMemberExpression(callee.object, 'navigator', 'storage')) { context.report({ messageId: 'checkPermission', data: { feature: 'persistent-storage', }, node: callee, }); } }, NewExpression(node) { const { callee } = node; if (context.options[0].permissions.includes('notifications') && isIdentifier(callee, 'Notification')) { context.report({ messageId: 'checkPermission', data: { feature: 'notifications', }, node: callee, }); } }, }; }, }; function checkForCameraAndMicrophonePermissions(context, callee, firstArg) { if (!firstArg) { return; } const shouldCheckAudio = context.options[0].permissions.includes('microphone'); const shouldCheckVideo = context.options[0].permissions.includes('camera'); if (!shouldCheckAudio && !shouldCheckVideo) { return; } const perms = []; for (const prop of firstArg.properties) { if (prop.type === 'Property') { const { value, key } = prop; if (isIdentifier(key, 'audio') && shouldCheckAudio && isOtherThanFalse(context, value)) { perms.push('microphone'); } else if (isIdentifier(key, 'video') && shouldCheckVideo && isOtherThanFalse(context, value)) { perms.push('camera'); } } } if (perms.length > 0) { context.report({ messageId: 'checkPermission', data: { feature: perms.join(' and '), }, node: callee, }); } } function isOtherThanFalse(context, value) { const exprValue = getValueOfExpression(context, value, 'Literal'); if (exprValue && exprValue.value === false) { return false; } return true; } function checkPermissions(context, call) { const firstArg = getValueOfExpression(context, call.arguments[0], 'ObjectExpression'); if ((firstArg === null || firstArg === void 0 ? void 0 : firstArg.type) === 'ObjectExpression') { const nameProp = firstArg.properties.find(prop => hasNamePropertyWithPermission(prop, context)); if (nameProp) { const { value } = nameProp.value; context.report({ messageId: 'checkPermission', data: { feature: String(value), }, node: nameProp, }); } } } function isNavigatorMemberExpression({ object, property }, firstProperty, ...secondProperty) { return (isMemberExpression(object, 'navigator', firstProperty) && isIdentifier(property, ...secondProperty)); } function hasNamePropertyWithPermission(prop, context) { if (prop.type === 'Property' && isIdentifier(prop.key, 'name')) { const value = getValueOfExpression(context, prop.value, 'Literal'); return (value && typeof value.value === 'string' && permissions.includes(value.value) && context.options[0].permissions.includes(value.value)); } return false; } const rule$2f = { meta: { messages: { refactorAwait: "Refactor this redundant 'await' on a non-promise.", }, }, create(context) { const services = context.sourceCode.parserServices; if (isRequiredParserServices(services)) { return { AwaitExpression: (node) => { const awaitedType = getTypeFromTreeNode$1(node.argument, services); if (!isException(node, services) && !isThenable(awaitedType) && !isAny(awaitedType) && !isUnknown(awaitedType) && !isUnion(awaitedType)) { context.report({ messageId: 'refactorAwait', node, }); } }, }; } return {}; }, }; function isException(node, services) { if (node.argument.type !== 'CallExpression') { return false; } const signature = getSignatureFromCallee(node.argument, services); return (signature === null || signature === void 0 ? void 0 : signature.declaration) && hasJsDocReturn(signature.declaration); function hasJsDocReturn(declaration) { var _a; const RETURN_TAGS = ['return', 'returns']; if (!declaration.jsDoc) { return false; } for (const jsDoc of declaration.jsDoc) { if ((_a = jsDoc.tags) === null || _a === void 0 ? void 0 : _a.some(tag => RETURN_TAGS.includes(tag.tagName.escapedText.toString()))) { return true; } } return false; } } function isThenable(type) { var _a; const thenProperty = type.getProperty('then'); return (_a = thenProperty === null || thenProperty === void 0 ? void 0 : thenProperty.declarations) === null || _a === void 0 ? void 0 : _a.some(d => d.kind === ts__namespace.SyntaxKind.MethodSignature || d.kind === ts__namespace.SyntaxKind.MethodDeclaration || d.kind === ts__namespace.SyntaxKind.PropertyDeclaration); } function isAny(type) { return Boolean(type.flags & ts__namespace.TypeFlags.Any); } function isUnknown(type) { return Boolean(type.flags & ts__namespace.TypeFlags.Unknown); } function isUnion(type) { return Boolean(type.flags & ts__namespace.TypeFlags.Union); } const rule$2e = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { const functionContextStack = []; const codePathSegments = []; let currentCodePathSegments = []; const checkOnFunctionExit = (node) => checkInvariantReturnStatements(node, functionContextStack[functionContextStack.length - 1]); function checkInvariantReturnStatements(node, functionContext) { if (!functionContext || hasDifferentReturnTypes(functionContext, currentCodePathSegments)) { return; } const returnedValues = functionContext.returnStatements.map(returnStatement => returnStatement.argument); if (areAllSameValue(returnedValues, context.sourceCode.getScope(node))) { const message = toEncodedMessage$1(`Refactor this function to not always return the same value.`, returnedValues, returnedValues.map(_ => 'Returned value.'), returnedValues.length); context.report({ message, loc: locations.getMainFunctionTokenLocation(node, getParent(context, node), context), }); } } return { onCodePathStart(codePath) { functionContextStack.push({ codePath, containsReturnWithoutValue: false, returnStatements: [], }); codePathSegments.push(currentCodePathSegments); currentCodePathSegments = []; }, onCodePathEnd() { functionContextStack.pop(); currentCodePathSegments = codePathSegments.pop() || []; }, onCodePathSegmentStart: (segment) => { currentCodePathSegments.push(segment); }, onCodePathSegmentEnd() { currentCodePathSegments.pop(); }, ReturnStatement(node) { const currentContext = functionContextStack[functionContextStack.length - 1]; if (currentContext) { const returnStatement = node; currentContext.containsReturnWithoutValue = currentContext.containsReturnWithoutValue || !returnStatement.argument; currentContext.returnStatements.push(returnStatement); } }, 'FunctionDeclaration:exit': checkOnFunctionExit, 'FunctionExpression:exit': checkOnFunctionExit, 'ArrowFunctionExpression:exit': checkOnFunctionExit, }; }, }; function hasDifferentReturnTypes(functionContext, currentSegments) { const hasImplicitReturn = currentSegments.some(segment => segment.reachable); return (hasImplicitReturn || functionContext.containsReturnWithoutValue || functionContext.returnStatements.length <= 1 || functionContext.codePath.thrownSegments.length > 0); } function areAllSameValue(returnedValues, scope) { const firstReturnedValue = returnedValues[0]; const firstValue = getLiteralValue(firstReturnedValue, scope); if (firstValue !== undefined) { return returnedValues .slice(1) .every(returnedValue => getLiteralValue(returnedValue, scope) === firstValue); } else if (firstReturnedValue.type === 'Identifier') { const singleWriteVariable = getSingleWriteDefinition(firstReturnedValue.name, scope); if (singleWriteVariable) { const readReferenceIdentifiers = singleWriteVariable.variable.references .slice(1) .map(ref => ref.identifier); return returnedValues.every(returnedValue => readReferenceIdentifiers.includes(returnedValue)); } } return false; } function getSingleWriteDefinition(variableName, scope) { const variable = scope.set.get(variableName); if (variable) { const references = variable.references.slice(1); if (!references.some(ref => ref.isWrite() || isPossibleObjectUpdate(ref))) { let initExpression = null; if (variable.defs.length === 1 && variable.defs[0].type === 'Variable') { initExpression = variable.defs[0].node.init; } return { variable, initExpression }; } } return null; } function isPossibleObjectUpdate(ref) { const expressionStatement = findFirstMatchingAncestor(ref.identifier, n => n.type === 'ExpressionStatement' || FUNCTION_NODES.includes(n.type)); return (expressionStatement && expressionStatement.type === 'ExpressionStatement' && (isElementWrite(expressionStatement, ref) || expressionStatement.expression.type === 'CallExpression')); } function getLiteralValue(returnedValue, scope) { if (returnedValue.type === 'Literal') { return returnedValue.value; } else if (returnedValue.type === 'UnaryExpression') { const innerReturnedValue = getLiteralValue(returnedValue.argument, scope); return innerReturnedValue !== undefined ? evaluateUnaryLiteralExpression(returnedValue.operator, innerReturnedValue) : undefined; } else if (returnedValue.type === 'Identifier') { const singleWriteVariable = getSingleWriteDefinition(returnedValue.name, scope); if (singleWriteVariable === null || singleWriteVariable === void 0 ? void 0 : singleWriteVariable.initExpression) { return getLiteralValue(singleWriteVariable.initExpression, scope); } } return undefined; } function evaluateUnaryLiteralExpression(operator, innerReturnedValue) { switch (operator) { case '-': return -Number(innerReturnedValue); case '+': return Number(innerReturnedValue); case '~': return ~Number(innerReturnedValue); case '!': return !Boolean(innerReturnedValue); case 'typeof': return typeof innerReturnedValue; default: return undefined; } } const rule$2d = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { return { CallExpression(node) { const call = node; const { callee, arguments: args } = call; if (isSensitiveFQN(context, call) && args.length > 0) { const xfwdProp = getProperty$1(args[0], 'xfwd', context); if (!xfwdProp) { return; } const xfwdValue = getValueOfExpression(context, xfwdProp.value, 'Literal'); if ((xfwdValue === null || xfwdValue === void 0 ? void 0 : xfwdValue.value) === true) { context.report({ node: callee, message: toEncodedMessage$1('Make sure forwarding client IP address is safe here.', [ xfwdProp, ]), }); } } }, }; }, }; function isSensitiveFQN(context, call) { const fqn = getFullyQualifiedName(context, call); return (fqn && ['http-proxy.createProxyServer', 'http-proxy-middleware.createProxyMiddleware'].includes(fqn)); } const rule$2c = { meta: { messages: { removeLabel: 'Refactor the code to remove this label and the need for it.', }, }, create(context) { return { LabeledStatement(node) { const sourceCode = context.sourceCode; context.report({ messageId: 'removeLabel', loc: sourceCode.getFirstToken(node).loc, }); }, }; }, }; const NODES = new Set([ utils.TSESTree.AST_NODE_TYPES.ArrayExpression, utils.TSESTree.AST_NODE_TYPES.ClassExpression, utils.TSESTree.AST_NODE_TYPES.ObjectExpression, utils.TSESTree.AST_NODE_TYPES.Literal, utils.TSESTree.AST_NODE_TYPES.TemplateLiteral, ]); const rule$2b = { meta: { messages: { asFunction: 'Literal should not be used as function.', asTagFunction: 'Literal should not be used as tag function.', }, }, create(context) { const processNode = (node, messageId) => { if (NODES.has(node.type)) { context.report({ node, messageId, }); } }; return { CallExpression(node) { processNode(node.callee, 'asFunction'); }, TaggedTemplateExpression(node) { processNode(node.tag, 'asTagFunction'); }, }; }, }; function decorate$q(rule) { return interceptReport(rule, (context, reportDescriptor) => { if ('node' in reportDescriptor && 'messageId' in reportDescriptor) { const { node, messageId, ...rest } = reportDescriptor; if (node.type === 'IfStatement' && node.loc && messageId === 'unexpectedLonelyIf') { const { start } = node.loc; context.report({ message: "'If' statement should not be the only statement in 'else' block", loc: { start, end: { line: start.line, column: start.column + 2 }, }, ...rest, }); } } }); } const rule$2a = decorate$q(eslintRules['no-lonely-if']); const HELMET$4 = 'helmet'; const NO_SNIFF = 'noSniff'; const rule$29 = Express.SensitiveMiddlewarePropertyRule(findFalseNoSniffPropertyFromHelmet, `Make sure allowing browsers to sniff MIME types is safe here.`); function findFalseNoSniffPropertyFromHelmet(context, node) { let sensitive; const { callee, arguments: args } = node; if (getFullyQualifiedName(context, callee) === HELMET$4 && args.length === 1 && args[0].type === 'ObjectExpression') { sensitive = getPropertyWithValue(context, args[0], NO_SNIFF, false); } return sensitive ? [sensitive] : []; } const arrayMutatingMethods = ['reverse', "'reverse'", '"reverse"', ...sortLike]; const rule$28 = { meta: { hasSuggestions: true, messages: { moveMethod: 'Move this array "{{method}}" operation to a separate statement or replace it with "{{suggestedMethod}}".', suggestMethod: 'Replace with "{{suggestedMethod}}" method', }, }, create(context) { const services = context.sourceCode.parserServices; if (!isRequiredParserServices(services)) { return {}; } return { CallExpression(node) { const { callee } = node; if (callee.type === 'MemberExpression') { const propertyText = context.sourceCode.getText(callee.property); if (isArrayMutatingCall(callee, services, propertyText)) { const mutatedArray = callee.object; if (isIdentifierOrPropertyAccessExpression(mutatedArray, services) && !isInSelfAssignment(mutatedArray, node) && isForbiddenOperation(node)) { const method = formatMethod(propertyText); const suggestedMethod = method === 'sort' ? 'toSorted' : 'toReversed'; context.report({ messageId: 'moveMethod', data: { method, suggestedMethod, }, node, suggest: [ { messageId: 'suggestMethod', data: { suggestedMethod, }, fix: fixer => { const fixedPropertyText = propertyText.replace(method, suggestedMethod); return fixer.replaceText(callee.property, fixedPropertyText); }, }, ], }); } } } }, }; }, }; function formatMethod(mutatingMethod) { if (mutatingMethod.startsWith('"') || mutatingMethod.startsWith("'")) { return mutatingMethod.substring(1, mutatingMethod.length - 1); } else { return mutatingMethod; } } function isArrayMutatingCall(memberExpression, services, propertyText) { return arrayMutatingMethods.includes(propertyText) && isArray(memberExpression.object, services); } function isIdentifierOrPropertyAccessExpression(node, services) { return (node.type === 'Identifier' || (node.type === 'MemberExpression' && !isGetAccessor(node.property, services))); } function isGetAccessor(node, services) { const symbol = getSymbolAtLocation(node, services); const declarations = symbol === null || symbol === void 0 ? void 0 : symbol.declarations; return (declarations === null || declarations === void 0 ? void 0 : declarations.length) === 1 && declarations[0].kind === ts__namespace.SyntaxKind.GetAccessor; } function isInSelfAssignment(mutatedArray, node) { const parent = node.parent; return (parent !== undefined && parent.type === 'AssignmentExpression' && parent.operator === '=' && parent.left.type === 'Identifier' && mutatedArray.type === 'Identifier' && parent.left.name === mutatedArray.name); } function isForbiddenOperation(node) { return !isStandaloneExpression(node) && !isReturnedExpression(node); } function isStandaloneExpression(node) { const ancestors = localAncestorsChain(node); const returnIdx = ancestors.findIndex(ancestor => ancestor.type === 'ExpressionStatement'); return (returnIdx > -1 && ancestors .slice(0, returnIdx) .every(ancestor => ['ChainExpression', 'LogicalExpression'].includes(ancestor.type))); } function isReturnedExpression(node) { const ancestors = localAncestorsChain(node); const returnIdx = ancestors.findIndex(ancestor => ancestor.type === 'ReturnStatement'); return (returnIdx > -1 && ancestors .slice(0, returnIdx) .every(ancestor => ['ArrayExpression', 'ObjectExpression', 'ConditionalExpression', 'SpreadElement'].includes(ancestor.type))); } const flaggedNodeStarts$1 = new Map(); const noMisusedPromisesRule = tsEslintRules['no-misused-promises']; const decoratedNoMisusedPromisesRule = interceptReport(noMisusedPromisesRule, (context, descriptor) => { if ('node' in descriptor) { const node = descriptor.node; const start = node.range[0]; if (!flaggedNodeStarts$1.get(start)) { flaggedNodeStarts$1.set(start, true); if (FUNCTION_NODES.includes(node.type)) { const loc = locations.getMainFunctionTokenLocation(node, node.parent, context); context.report({ ...descriptor, loc }); } else { context.report(descriptor); } } } }); const noAsyncPromiseExecutorRule = eslintRules['no-async-promise-executor']; const decoratedNoAsyncPromiseExecutorRule = interceptReport(noAsyncPromiseExecutorRule, (context, descriptor) => { if ('node' in descriptor) { const start = descriptor.node.range[0]; if (!flaggedNodeStarts$1.get(start)) { context.report(descriptor); } } }); const rule$27 = { meta: { messages: { ...decoratedNoMisusedPromisesRule.meta.messages, ...decoratedNoAsyncPromiseExecutorRule.meta.messages, }, hasSuggestions: true, schema: [ { type: 'object', properties: {}, }, ], }, create(context) { return { 'Program:exit': () => { flaggedNodeStarts$1.clear(); }, ...mergeRules(decoratedNoAsyncPromiseExecutorRule.create(context), decoratedNoMisusedPromisesRule.create(context)), }; }, }; const HELMET$3 = 'helmet'; const HELMET_CSP = 'helmet-csp'; const DIRECTIVES = 'directives'; const CONTENT_SECURITY_POLICY = 'contentSecurityPolicy'; const BLOCK_ALL_MIXED_CONTENT_CAMEL = 'blockAllMixedContent'; const BLOCK_ALL_MIXED_CONTENT_HYPHEN = 'block-all-mixed-content'; const rule$26 = Express.SensitiveMiddlewarePropertyRule(findDirectivesWithMissingMixedContentPropertyFromHelmet, `Make sure allowing mixed-content is safe here.`); function findDirectivesWithMissingMixedContentPropertyFromHelmet(context, node) { let sensitive; const { arguments: args } = node; if (args.length === 1) { const [options] = args; const maybeDirectives = getProperty$1(options, DIRECTIVES, context); if (maybeDirectives && isMissingMixedContentProperty(maybeDirectives, context) && isValidHelmetModuleCall(context, node)) { sensitive = maybeDirectives; } } return sensitive ? [sensitive] : []; } function isValidHelmetModuleCall(context, callExpr) { const fqn = getFullyQualifiedName(context, callExpr); return fqn === `${HELMET$3}.${CONTENT_SECURITY_POLICY}` || fqn === HELMET_CSP; } function isMissingMixedContentProperty(directives, context) { return !(Boolean(getProperty$1(directives.value, BLOCK_ALL_MIXED_CONTENT_CAMEL, context)) || Boolean(getProperty$1(directives.value, BLOCK_ALL_MIXED_CONTENT_HYPHEN, context))); } const rule$25 = { meta: { messages: { extractAssignment: 'Extract the assignment of "{{symbol}}" from this expression.', }, }, create(context) { function isAssignmentStatement(parent) { return parent.type === 'ExpressionStatement'; } function isEnclosingChain(parent) { return parent.type === 'AssignmentExpression'; } function isEnclosingRelation(parent) { return (parent.type === 'BinaryExpression' && ['==', '!=', '===', '!==', '<', '<=', '>', '>='].includes(parent.operator)); } function isEnclosingSequence(parent) { return parent.type === 'SequenceExpression'; } function isEnclosingDeclarator(parent) { return parent.type === 'VariableDeclarator'; } function isLambdaBody(parent, expr) { return parent.type === 'ArrowFunctionExpression' && parent.body === expr; } function isConditionalAssignment(parent, expr) { return parent.type === 'LogicalExpression' && parent.right === expr; } function isWhileCondition(parent, expr) { return ((parent.type === 'DoWhileStatement' || parent.type === 'WhileStatement') && parent.test === expr); } function isForInitOrUpdate(parent, expr) { return parent.type === 'ForStatement' && (parent.init === expr || parent.update === expr); } return { AssignmentExpression: (node) => { const assignment = node; const parent = getParent(context, node); if (parent && !isAssignmentStatement(parent) && !isEnclosingChain(parent) && !isEnclosingRelation(parent) && !isEnclosingSequence(parent) && !isEnclosingDeclarator(parent) && !isLambdaBody(parent, assignment) && !isConditionalAssignment(parent, assignment) && !isWhileCondition(parent, assignment) && !isForInitOrUpdate(parent, assignment)) { raiseIssue(assignment, context); } }, }; }, }; function raiseIssue(node, context) { const sourceCode = context.sourceCode; const operator = sourceCode.getFirstTokenBetween(node.left, node.right, token => token.value === node.operator); const text = sourceCode.getText(node.left); context.report({ messageId: 'extractAssignment', data: { symbol: text, }, loc: operator.loc, }); } const rule$24 = { meta: { messages: { extractTernary: 'Extract this nested ternary operation into an independent statement.', }, }, create(context) { return { 'ConditionalExpression ConditionalExpression': (node) => { if (!isNestingBroken(context.sourceCode.getAncestors(node))) { context.report({ messageId: 'extractTernary', node, }); } }, }; }, }; function isNestingBroken(ancestors) { let parent = ancestors.pop(); while (parent.type !== 'ConditionalExpression') { if (breaksNesting(parent)) { return true; } parent = ancestors.pop(); } return false; } function breaksNesting(node) { return [ 'ArrayExpression', 'ObjectExpression', 'FunctionExpression', 'ArrowFunctionExpression', 'JSXExpressionContainer', ].includes(node.type); } const DEFAULT_THRESHOLD = 4; const rule$23 = { meta: { schema: [ { type: 'object', properties: { threshold: { type: 'integer', }, }, }, { type: 'string', enum: [SONAR_RUNTIME], }, ], }, create(context) { var _a; const max = ((_a = context.options[0]) === null || _a === void 0 ? void 0 : _a.threshold) || DEFAULT_THRESHOLD; const nestedStack = []; return { ':function'(node) { const fn = node; nestedStack.push(fn); if (nestedStack.length === max + 1) { const secondaries = nestedStack.slice(0, -1); context.report({ loc: locations.getMainFunctionTokenLocation(fn, fn.parent, context), message: toEncodedMessage$1(`Refactor this code to not nest functions more than ${max} levels deep.`, secondaries.map(n => ({ loc: locations.getMainFunctionTokenLocation(n, n.parent, context), })), secondaries.map(_ => 'Nesting +1')), }); } }, ':function:exit'() { nestedStack.pop(); }, }; }, }; const rule$22 = { meta: { messages: { extractOperation: 'Extract this {{incrementType}} operation into a dedicated statement.', }, }, create(context) { function reportUpdateExpression(node) { context.report({ messageId: 'extractOperation', data: { incrementType: node.operator === '++' ? 'increment' : 'decrement', }, node, }); } return { UpdateExpression(node) { if (!isIgnored(node, context.sourceCode.getAncestors(node))) { reportUpdateExpression(node); } }, }; }, }; function isIgnored(node, ancestors) { const firstAncestor = ancestors.pop(); if (firstAncestor) { switch (firstAncestor.type) { case 'ExpressionStatement': return true; case 'ForStatement': return firstAncestor.update === node; case 'SequenceExpression': { const secondAncestor = ancestors.pop(); return (secondAncestor !== undefined && secondAncestor.type === 'ForStatement' && secondAncestor.update === firstAncestor); } } } return false; } const SENSITIVE_METHODS = ['exec', 'execSync', 'spawn', 'spawnSync', 'execFile', 'execFileSync']; const REQUIRED_PATH_PREFIXES = ['./', '.\\', '../', '..\\', '/', '\\', 'C:\\']; const rule$21 = { meta: { messages: { issue: 'Make sure the "PATH" used to find this command includes only what you intend.', }, }, create(context) { return { CallExpression: (node) => { const fqn = getFullyQualifiedName(context, node); if (SENSITIVE_METHODS.some(method => fqn === `child_process.${method}`)) { const sensitiveArg = findSensitiveArgument(context, node.arguments); if (sensitiveArg !== null) { context.report({ messageId: 'issue', node: sensitiveArg, }); } } }, }; }, }; function findSensitiveArgument(context, functionArgs) { if (functionArgs.length === 0) { return null; } const pathArg = functionArgs[0]; const literalInExpression = getValueOfExpression(context, pathArg, 'Literal'); let stringLiteral; if (literalInExpression !== undefined && isStringLiteral(literalInExpression)) { stringLiteral = literalInExpression; } else { return null; } const startsWithRequiredPrefix = REQUIRED_PATH_PREFIXES.some(prefix => stringLiteral.value.startsWith(prefix)); return startsWithRequiredPrefix ? null : pathArg; } const rule$20 = { meta: { messages: { noReassignment: 'Introduce a new variable or use its initial value before reassigning "{{reference}}".', }, }, create(context) { let variableUsageContext = { type: 'global', variablesToCheckInCurrentScope: new Set(), variablesToCheck: new Set(), variablesRead: new Set(), referencesByIdentifier: new Map(), }; function checkIdentifierUsage(identifier, identifierContextType) { if (variableUsageContext.type !== identifierContextType) { return; } const variableName = identifier.name; const currentReference = getReference(variableUsageContext, identifier); if (currentReference && !currentReference.init && !variableUsageContext.variablesRead.has(variableName)) { if (variableUsageContext.variablesToCheck.has(variableName) && currentReference.isWriteOnly() && !isUsedInWriteExpression(variableName, currentReference.writeExpr)) { if (isInsideIfStatement(context, identifier) || context.sourceCode.getAncestors(identifier).some(node => node.type === 'SwitchCase')) { return; } raiseIssue(currentReference); } markAsRead(variableUsageContext, variableName); } else if (variableName === 'arguments') { markAllFunctionArgumentsAsRead(variableUsageContext); } } function isUsedInWriteExpression(variableName, writeExpr) { return (writeExpr && context.sourceCode.getFirstToken(writeExpr, token => token.value === variableName || token.value === 'arguments')); } function raiseIssue(reference) { const locationHolder = getPreciseLocationHolder(reference); context.report({ messageId: 'noReassignment', data: { reference: reference.identifier.name, }, ...locationHolder, }); } function popContext() { variableUsageContext = variableUsageContext.parentContext ? variableUsageContext.parentContext : variableUsageContext; } return { onCodePathStart(_codePath, node) { const currentScope = context.sourceCode.getScope(node); if (currentScope && currentScope.type === 'function') { const { referencesByIdentifier, variablesToCheck, variablesToCheckInCurrentScope } = computeNewContextInfo(variableUsageContext, context, node); const functionName = getFunctionName(node); if (functionName) { variablesToCheck.delete(functionName); } variableUsageContext = { type: 'function', parentContext: variableUsageContext, variablesToCheck, referencesByIdentifier, variablesToCheckInCurrentScope, variablesRead: computeSetDifference(variableUsageContext.variablesRead, variablesToCheckInCurrentScope), }; } else { variableUsageContext = { type: 'global', parentContext: variableUsageContext, variablesToCheckInCurrentScope: new Set(), variablesToCheck: new Set(), variablesRead: new Set(), referencesByIdentifier: new Map(), }; } }, onCodePathSegmentLoop(_fromSegment, _toSegment, node) { const parent = getParent(context, node); if (!isForEachLoopStart(node, parent)) { return; } const currentScope = context.sourceCode.scopeManager.acquire(parent.body); const { referencesByIdentifier, variablesToCheck, variablesToCheckInCurrentScope } = computeNewContextInfo(variableUsageContext, context, parent.left); if (currentScope) { for (const ref of currentScope.references) { referencesByIdentifier.set(ref.identifier, ref); } } resolveIdentifiers(parent.left, true) .map(identifier => identifier.name) .forEach(name => { variablesToCheck.add(name); variablesToCheckInCurrentScope.add(name); }); variableUsageContext = { type: 'foreach', parentContext: variableUsageContext, variablesToCheckInCurrentScope, variablesToCheck, variablesRead: computeSetDifference(variableUsageContext.variablesRead, variablesToCheckInCurrentScope), referencesByIdentifier, }; }, onCodePathSegmentStart(_segment, node) { if (node.type !== 'CatchClause') { return; } const { referencesByIdentifier, variablesToCheck, variablesToCheckInCurrentScope } = computeNewContextInfo(variableUsageContext, context, node); variableUsageContext = { type: 'catch', parentContext: variableUsageContext, variablesToCheckInCurrentScope, variablesToCheck, variablesRead: computeSetDifference(variableUsageContext.variablesRead, variablesToCheckInCurrentScope), referencesByIdentifier, }; }, onCodePathEnd: popContext, 'ForInStatement:exit': popContext, 'ForOfStatement:exit': popContext, 'CatchClause:exit': popContext, '*:function > BlockStatement Identifier': (node) => checkIdentifierUsage(node, 'function'), 'ForInStatement > *:statement Identifier': (node) => checkIdentifierUsage(node, 'foreach'), 'ForOfStatement > *:statement Identifier': (node) => checkIdentifierUsage(node, 'foreach'), 'CatchClause > BlockStatement Identifier': (node) => checkIdentifierUsage(node, 'catch'), }; }, }; function isInsideIfStatement(context, node) { const ancestors = context.sourceCode.getAncestors(node); for (let i = ancestors.length - 1; i >= 0; i--) { if (ancestors[i].type === 'IfStatement' && i < ancestors.length - 1 && (ancestors[i + 1] === ancestors[i].consequent || ancestors[i + 1] === ancestors[i].alternate)) { return true; } } return false; } function computeSetDifference(a, b) { return new Set([...a].filter(str => !b.has(str))); } function getFunctionName(node) { return !node.id ? null : node.id.name; } function isForEachLoopStart(node, parent) { return (node.type === 'BlockStatement' && !!parent && (parent.type === 'ForInStatement' || parent.type === 'ForOfStatement')); } function computeNewContextInfo(variableUsageContext, context, node) { const referencesByIdentifier = new Map(); const variablesToCheck = new Set(variableUsageContext.variablesToCheck); const variablesToCheckInCurrentScope = new Set(); context.sourceCode.getDeclaredVariables(node).forEach(variable => { variablesToCheck.add(variable.name); variablesToCheckInCurrentScope.add(variable.name); for (const currentRef of variable.references) { referencesByIdentifier.set(currentRef.identifier, currentRef); } }); return { referencesByIdentifier, variablesToCheck, variablesToCheckInCurrentScope }; } function markAsRead(context, variableName) { context.variablesRead.add(variableName); if (!context.variablesToCheckInCurrentScope.has(variableName) && context.parentContext) { markAsRead(context.parentContext, variableName); } } function markAllFunctionArgumentsAsRead(variableUsageContext) { let functionContext = variableUsageContext; while (functionContext && functionContext.type !== 'function') { functionContext = functionContext.parentContext; } if (functionContext) { for (const variableName of functionContext.variablesToCheckInCurrentScope) { functionContext.variablesRead.add(variableName); } } } function getPreciseLocationHolder(reference) { const identifierLoc = reference.identifier.loc; if (identifierLoc && reference.writeExpr && reference.writeExpr.loc) { return { loc: { start: identifierLoc.start, end: reference.writeExpr.loc.end } }; } return { node: reference.identifier }; } function getReference(variableUsageContext, identifier) { const identifierReference = variableUsageContext.referencesByIdentifier.get(identifier); if (!identifierReference && variableUsageContext.parentContext) { return getReference(variableUsageContext.parentContext, identifier); } return identifierReference; } const WRAPPER_TYPES = ['Boolean', 'Number', 'String']; const rule$1$ = { meta: { hasSuggestions: true, messages: { removeConstructor: 'Remove this use of "{{constructor}}" constructor.', replaceWrapper: 'Replace this "{{wrapper}}" wrapper object with primitive type "{{primitive}}".', suggestRemoveNew: 'Remove "new" operator', suggestReplaceWrapper: 'Replace "{{wrapper}}" with "{{primitive}}"', }, }, create(context) { return { NewExpression(node) { const konstructor = node.callee; if (konstructor.type === 'Identifier' && WRAPPER_TYPES.includes(konstructor.name)) { const newToken = context.sourceCode.getFirstToken(node, token => token.value === 'new'); const [begin, end] = newToken.range; context.report({ messageId: 'removeConstructor', data: { constructor: konstructor.name, }, node, suggest: [ { messageId: 'suggestRemoveNew', fix: fixer => fixer.removeRange([begin, end + 1]), }, ], }); } }, TSTypeReference(node) { const typeString = context.sourceCode.getText(node); if (WRAPPER_TYPES.includes(typeString)) { const primitiveType = typeString.toLowerCase(); context.report({ messageId: 'replaceWrapper', data: { wrapper: typeString, primitive: primitiveType, }, node, suggest: [ { messageId: 'suggestReplaceWrapper', data: { wrapper: typeString, primitive: primitiveType, }, fix: fixer => fixer.replaceText(node, primitiveType), }, ], }); } }, }; }, }; function decorate$p(rule) { return interceptReport(rule, reportExempting$5(isTypeDeclaration)); } function reportExempting$5(exemptionCondition) { return (context, reportDescriptor) => { if ('node' in reportDescriptor) { const node = reportDescriptor['node']; if (node.type === 'Identifier' && !exemptionCondition(node)) { context.report(reportDescriptor); } } }; } function isTypeDeclaration(node) { var _a; return ((_a = node.parent) === null || _a === void 0 ? void 0 : _a.type) === 'TSTypeAliasDeclaration'; } const rule$1_ = decorate$p(tsEslintRules['no-redeclare']); const rule$1Z = { meta: { messages: { reviewAssignment: 'Review this redundant assignment: "{{symbol}}" already holds the assigned value along all execution paths.', }, }, create(context) { const codePathStack = []; const reachingDefsMap = new Map(); const variableUsages = new Map(); const codePathSegments = []; let currentCodePathSegments = []; return { ':matches(AssignmentExpression, VariableDeclarator[init])': (node) => { pushAssignmentContext(node); }, ':matches(AssignmentExpression, VariableDeclarator[init]):exit': () => { popAssignmentContext(); }, Identifier: (node) => { if (isEnumConstant(node)) { return; } checkIdentifierUsage(node); }, 'Program:exit': () => { reachingDefinitions(reachingDefsMap); reachingDefsMap.forEach(defs => { checkSegment(defs); }); reachingDefsMap.clear(); variableUsages.clear(); while (codePathStack.length > 0) { codePathStack.pop(); } }, onCodePathSegmentStart: (segment) => { reachingDefsMap.set(segment.id, new ReachingDefinitions(segment)); currentCodePathSegments.push(segment); }, onCodePathStart: codePath => { pushContext(new CodePathContext(codePath)); codePathSegments.push(currentCodePathSegments); currentCodePathSegments = []; }, onCodePathEnd: () => { popContext(); currentCodePathSegments = codePathSegments.pop() || []; }, onCodePathSegmentEnd() { currentCodePathSegments.pop(); }, }; function popAssignmentContext() { const assignment = peek(codePathStack).assignmentStack.pop(); assignment.rhs.forEach(r => processReference(r)); assignment.lhs.forEach(r => processReference(r)); } function pushAssignmentContext(node) { peek(codePathStack).assignmentStack.push(new AssignmentContext(node)); } function checkSegment(reachingDefs) { const assignedValuesMap = new Map(reachingDefs.in); reachingDefs.references.forEach(ref => { const variable = ref.resolved; if (!variable || !ref.isWrite() || !shouldReport(ref)) { return; } const lhsValues = assignedValuesMap.get(variable); const rhsValues = resolveAssignedValues(variable, ref.writeExpr, assignedValuesMap, ref.from); if ((lhsValues === null || lhsValues === void 0 ? void 0 : lhsValues.type) === 'AssignedValues' && (lhsValues === null || lhsValues === void 0 ? void 0 : lhsValues.size) === 1) { const [lhsVal] = [...lhsValues]; checkRedundantAssignement(ref, ref.writeExpr, lhsVal, rhsValues, variable.name); } assignedValuesMap.set(variable, rhsValues); }); } function checkRedundantAssignement({ resolved: variable }, node, lhsVal, rhsValues, name) { if (rhsValues.type === 'UnknownValue' || rhsValues.size !== 1) { return; } const [rhsVal] = [...rhsValues]; if (!isWrittenOnlyOnce(variable) && lhsVal === rhsVal) { context.report({ node: node, messageId: 'reviewAssignment', data: { symbol: name, }, }); } } function isWrittenOnlyOnce(variable) { return variable.references.filter(ref => ref.isWrite()).length === 1; } function shouldReport(ref) { const variable = ref.resolved; return variable && shouldReportReference(ref) && !variableUsedOutsideOfCodePath(variable); } function shouldReportReference(ref) { const variable = ref.resolved; return (variable && !isDefaultParameter(ref) && !variable.name.startsWith('_') && !isCompoundAssignment(ref.writeExpr) && !isSelfAssignement(ref) && !variable.defs.some(def => def.type === 'Parameter' || (def.type === 'Variable' && !def.node.init))); } function isEnumConstant(node) { return context.sourceCode.getAncestors(node).some(n => n.type === 'TSEnumDeclaration'); } function variableUsedOutsideOfCodePath(variable) { return variableUsages.get(variable).size > 1; } function checkIdentifierUsage(node) { const { ref, variable } = resolveReference(node); if (ref) { processReference(ref); } if (variable) { updateVariableUsages(variable); } } function processReference(ref) { const assignmentStack = peek(codePathStack).assignmentStack; if (assignmentStack.length > 0) { const assignment = peek(assignmentStack); assignment.add(ref); } else { currentCodePathSegments.forEach(segment => { const reachingDefs = reachingDefsForSegment(segment); reachingDefs.add(ref); }); } } function reachingDefsForSegment(segment) { let defs; if (reachingDefsMap.has(segment.id)) { defs = reachingDefsMap.get(segment.id); } else { defs = new ReachingDefinitions(segment); reachingDefsMap.set(segment.id, defs); } return defs; } function updateVariableUsages(variable) { const codePathId = peek(codePathStack).codePath.id; if (variableUsages.has(variable)) { variableUsages.get(variable).add(codePathId); } else { variableUsages.set(variable, new Set([codePathId])); } } function pushContext(codePathContext) { codePathStack.push(codePathContext); } function popContext() { codePathStack.pop(); } function resolveReferenceRecursively(node, scope) { if (scope === null) { return { ref: null, variable: null }; } const ref = scope.references.find(r => r.identifier === node); if (ref) { return { ref, variable: ref.resolved }; } else { const variable = scope.variables.find(v => v.defs.find(def => def.name === node)); if (variable) { return { ref: null, variable }; } return resolveReferenceRecursively(node, scope.upper); } } function resolveReference(node) { return resolveReferenceRecursively(node, context.sourceCode.getScope(node)); } }, }; class CodePathContext { constructor(codePath) { this.reachingDefinitionsMap = new Map(); this.reachingDefinitionsStack = []; this.segments = new Map(); this.assignmentStack = []; this.codePath = codePath; } } class AssignmentContext { constructor(node) { this.lhs = new Set(); this.rhs = new Set(); this.node = node; } isRhs(node) { return this.node.type === 'AssignmentExpression' ? this.node.right === node : this.node.init === node; } isLhs(node) { return this.node.type === 'AssignmentExpression' ? this.node.left === node : this.node.id === node; } add(ref) { let parent = ref.identifier; while (parent) { if (this.isLhs(parent)) { this.lhs.add(ref); break; } if (this.isRhs(parent)) { this.rhs.add(ref); break; } parent = parent.parent; } if (parent === null) { throw new Error('failed to find assignment lhs/rhs'); } } } function peek(arr) { return arr[arr.length - 1]; } function isSelfAssignement(ref) { var _a; const lhs = ref.resolved; if (((_a = ref.writeExpr) === null || _a === void 0 ? void 0 : _a.type) === 'Identifier') { const rhs = getVariableFromIdentifier(ref.writeExpr, ref.from); return lhs === rhs; } return false; } function isCompoundAssignment(writeExpr) { if (writeExpr === null || writeExpr === void 0 ? void 0 : writeExpr.hasOwnProperty('parent')) { const node = writeExpr.parent; return node && node.type === 'AssignmentExpression' && node.operator !== '='; } return false; } function isDefaultParameter(ref) { if (ref.identifier.type !== 'Identifier') { return false; } const parent = ref.identifier.parent; return parent && parent.type === 'AssignmentPattern'; } const rule$1Y = { meta: { hasSuggestions: true, schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { if (!isRequiredParserServices(context.sourceCode.parserServices)) { return {}; } function checkProperty(node) { const tsNode = node; const optionalToken = context.sourceCode.getFirstToken(node, token => token.value === '?'); if (!tsNode.optional || !optionalToken) { return; } const typeNode = getUndefinedTypeAnnotation(tsNode.typeAnnotation); if (typeNode) { const suggest = getQuickFixSuggestions(context, optionalToken, typeNode); const secondaryLocations = [typeNode]; const message = toEncodedMessage$1("Consider removing 'undefined' type or '?' specifier, one of them is redundant.", secondaryLocations); context.report({ message, loc: optionalToken.loc, suggest, }); } } return { 'PropertyDefinition, TSPropertySignature': (node) => checkProperty(node), }; }, }; function getUndefinedTypeAnnotation(tsTypeAnnotation) { if (tsTypeAnnotation) { return getUndefinedTypeNode(tsTypeAnnotation.typeAnnotation); } return undefined; } function getUndefinedTypeNode(typeNode) { if (typeNode.type === 'TSUndefinedKeyword') { return typeNode; } else if (typeNode.type === 'TSUnionType') { return typeNode.types.map(getUndefinedTypeNode).find(tpe => tpe !== undefined); } return undefined; } function getQuickFixSuggestions(context, optionalToken, undefinedType) { var _a; const suggestions = [ { desc: 'Remove "?" operator', fix: fixer => fixer.remove(optionalToken), }, ]; if (((_a = undefinedType.parent) === null || _a === void 0 ? void 0 : _a.type) === 'TSUnionType') { suggestions.push(getUndefinedRemovalSuggestion(context, undefinedType)); } return suggestions; } function getUndefinedRemovalSuggestion(context, undefinedType) { return { desc: 'Remove "undefined" type annotation', fix: fixer => { const fixes = []; const unionType = undefinedType.parent; if (unionType.types.length === 2) { const unionTypeNode = unionType; const otherType = unionType.types[0] === undefinedType ? unionType.types[1] : unionType.types[0]; const otherTypeText = context.sourceCode.getText(otherType); fixes.push(fixer.replaceText(unionTypeNode, otherTypeText)); const tokenBefore = context.sourceCode.getTokenBefore(unionTypeNode); const tokenAfter = context.sourceCode.getTokenAfter(unionTypeNode); if ((tokenBefore === null || tokenBefore === void 0 ? void 0 : tokenBefore.value) === '(' && (tokenAfter === null || tokenAfter === void 0 ? void 0 : tokenAfter.value) === ')') { fixes.push(fixer.remove(tokenBefore)); fixes.push(fixer.remove(tokenAfter)); } } else { const index = unionType.types.indexOf(undefinedType); if (index === 0) { fixes.push(fixer.removeRange([undefinedType.range[0], unionType.types[1].range[0]])); } else { fixes.push(fixer.removeRange([unionType.types[index - 1].range[1], undefinedType.range[1]])); } } return fixes; }, }; } const parenthesized = { DoWhileStatement: 'test', IfStatement: 'test', SwitchStatement: 'discriminant', WhileStatement: 'test', WithStatement: 'object', ArrowFunctionExpression: 'body', ImportExpression: 'source', }; const rule$1X = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], hasSuggestions: true, }, create(context) { return { '*'(node) { checkRedundantParentheses(context.sourceCode, node, context); }, }; }, }; function checkRedundantParentheses(sourceCode, node, context) { const parenthesesPairsAroundNode = getParenthesesPairsAround(sourceCode, node, node); const parent = getParent(context, node); if (!!parent && isInParentNodeParentheses(node, parent)) { parenthesesPairsAroundNode.pop(); } parenthesesPairsAroundNode.shift(); parenthesesPairsAroundNode.forEach(parentheses => { context.report({ message: toEncodedMessage$1(`Remove these redundant parentheses.`, [ parentheses.closingParenthesis, ]), loc: parentheses.openingParenthesis.loc, suggest: [ { desc: 'Remove these redundant parentheses', fix(fixer) { return [ fixer.remove(parentheses.openingParenthesis), fixer.remove(parentheses.closingParenthesis), ]; }, }, ], }); }); } function getParenthesesPairsAround(sourceCode, start, end) { const tokenBefore = sourceCode.getTokenBefore(start); const tokenAfter = sourceCode.getTokenAfter(end); if (!!tokenBefore && !!tokenAfter && tokenBefore.value === '(' && tokenAfter.value === ')') { return [ { openingParenthesis: tokenBefore, closingParenthesis: tokenAfter }, ...getParenthesesPairsAround(sourceCode, tokenBefore, tokenAfter), ]; } return []; } function isInParentNodeParentheses(node, parent) { const parentAttribute = parenthesized[parent.type]; const nodeIsInConditionOfParent = parentAttribute && node === parent[parentAttribute]; const nodeIsArgumentOfCallExpression = (parent.type === 'CallExpression' || parent.type === 'NewExpression') && parent.arguments.includes(node); return nodeIsInConditionOfParent || nodeIsArgumentOfCallExpression; } function decorate$o(rule) { return interceptReport(rule, reportExempting$4); } function reportExempting$4(context, descriptor) { if ('node' in descriptor) { const { node, ...rest } = descriptor; if (exemptionCondition(node, descriptor)) { return; } context.report({ node, ...rest }); } } function exemptionCondition(node, descriptor) { const data = descriptor.data; return (((data === null || data === void 0 ? void 0 : data['typeName']) === 'any' && node.type !== 'TSAnyKeyword') || ((data === null || data === void 0 ? void 0 : data['typeName']) === 'unknown' && node.type !== 'TSUnknownKeyword')); } const rule$1W = decorate$o(tsEslintRules['no-redundant-type-constituents']); const vueMacroNames = new Set([ 'defineProps', 'defineEmits', 'defineExpose', 'defineOptions', 'defineSlots', 'withDefaults', ]); const rule$1V = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { const excludedNames = new Set(); const undeclaredIdentifiersByName = new Map(); return { 'Program:exit'(node) { excludedNames.clear(); undeclaredIdentifiersByName.clear(); const globalScope = context.sourceCode.getScope(node); globalScope.through.forEach(ref => { const identifier = ref.identifier; if (excludedNames.has(identifier.name)) { return; } if (ref.writeExpr || hasTypeOfOperator(identifier) || isWithinWithStatement(identifier)) { excludedNames.add(identifier.name); return; } if (vueMacroNames.has(identifier.name) && isInsideVueSetupScript(identifier, context)) { return; } const undeclaredIndentifiers = undeclaredIdentifiersByName.get(identifier.name); if (undeclaredIndentifiers) { undeclaredIndentifiers.push(identifier); } else { undeclaredIdentifiersByName.set(identifier.name, [identifier]); } }); undeclaredIdentifiersByName.forEach((identifiers, name) => { context.report({ node: identifiers[0], message: toEncodedMessage$1(`"${name}" does not exist. Change its name or declare it so that its usage doesn't result in a "ReferenceError".`, identifiers.slice(1)), }); }); }, }; }, }; function isWithinWithStatement(node) { return !!findFirstMatchingAncestor(node, ancestor => ancestor.type === 'WithStatement'); } function hasTypeOfOperator(node) { const parent = node.parent; return (parent === null || parent === void 0 ? void 0 : parent.type) === 'UnaryExpression' && parent.operator === 'typeof'; } const HELMET$2 = 'helmet'; const POLICY = 'policy'; const REFERRER_POLICY = 'referrerPolicy'; const UNSAFE_REFERRER_POLICY_VALUES = ['', 'unsafe-url', 'no-referrer-when-downgrade']; const rule$1U = Express.SensitiveMiddlewarePropertyRule(findNoReferrerPolicyPropertyFromHelmet, `Make sure disabling strict HTTP no-referrer policy is safe here.`); function findNoReferrerPolicyPropertyFromHelmet(context, node) { let sensitive; const { callee, arguments: args } = node; if (args.length === 1) { const [options] = args; const fqn = getFullyQualifiedName(context, callee); if (fqn === HELMET$2 && options.type === 'ObjectExpression') { sensitive = getPropertyWithValue(context, options, REFERRER_POLICY, false); } else if (fqn === `${HELMET$2}.${REFERRER_POLICY}`) { const maybePolicy = getProperty$1(options, POLICY, context); if (maybePolicy && !isSafePolicy(maybePolicy)) { sensitive = maybePolicy; } } } return sensitive ? [sensitive] : []; } function isSafePolicy(policy) { const { value } = policy; const values = value.type === 'ArrayExpression' ? value.elements : [value]; const sensitiveValue = values.find(v => (v === null || v === void 0 ? void 0 : v.type) === 'Literal' && typeof v.value === 'string' && UNSAFE_REFERRER_POLICY_VALUES.includes(v.value)); return !Boolean(sensitiveValue); } const rule$1T = { meta: { messages: { standardImport: 'Use a standard "import" statement instead of "{{adhocImport}}".', }, }, create(context) { const services = context.sourceCode.parserServices; return { 'CallExpression[callee.type="Identifier"]': (node) => { if (context.sourceCode.getScope(node).type !== 'module' && context.sourceCode.getScope(node).type !== 'global') { return; } const callExpression = node; const identifier = callExpression.callee; if (isAmdImport(callExpression, identifier, services) || isCommonJsImport(callExpression, identifier, services)) { context.report({ node: identifier, messageId: 'standardImport', data: { adhocImport: identifier.name, }, }); } }, }; }, }; function isString(node, services) { return ((isRequiredParserServices(services) && isString$1(node, services)) || isStringLiteral(node)); } function isCommonJsImport(callExpression, identifier, services) { return (callExpression.arguments.length === 1 && isString(callExpression.arguments[0], services) && identifier.name === 'require'); } function isAmdImport(callExpression, identifier, services) { if (identifier.name !== 'require' && identifier.name !== 'define') { return false; } if (callExpression.arguments.length !== 2 && callExpression.arguments.length !== 3) { return false; } return (isRequiredParserServices(services) && isFunction$1(callExpression.arguments[callExpression.arguments.length - 1], services)); } const rule$1S = { meta: { messages: { removeOrChangeType: 'Remove this return type or change it to a more specific.', }, }, create(context) { const services = context.sourceCode.parserServices; if (isRequiredParserServices(services)) { const returnedExpressions = []; return { ReturnStatement(node) { if (returnedExpressions.length > 0) { returnedExpressions[returnedExpressions.length - 1].push(node.argument); } }, FunctionDeclaration() { returnedExpressions.push([]); }, 'FunctionDeclaration:exit'(node) { const returnType = node.returnType; if (returnType && returnType.typeAnnotation.type === 'TSAnyKeyword' && returnedExpressions.length > 0 && allReturnTypesEqual(returnedExpressions[returnedExpressions.length - 1], services)) { context.report({ messageId: 'removeOrChangeType', loc: returnType.loc, }); } returnedExpressions.pop(); }, }; } return {}; }, }; function allReturnTypesEqual(returns, services) { const firstReturnType = getTypeFromTreeNode(returns.pop(), services); if (!!firstReturnType && !!isPrimitiveType(firstReturnType)) { return returns.every(nextReturn => { const nextReturnType = getTypeFromTreeNode(nextReturn, services); return !!nextReturnType && nextReturnType.flags === firstReturnType.flags; }); } return false; } function getTypeFromTreeNode(node, services) { const checker = services.program.getTypeChecker(); return checker.getTypeAtLocation(services.esTreeNodeToTSNodeMap.get(node)); } function isPrimitiveType({ flags }) { return (flags & ts__namespace.TypeFlags.BooleanLike || flags & ts__namespace.TypeFlags.NumberLike || flags & ts__namespace.TypeFlags.StringLike || flags & ts__namespace.TypeFlags.EnumLike); } const rule$1R = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { if (!Chai.isImported(context)) { return {}; } return { ExpressionStatement(node) { const { expression } = node; checkExpect(context, expression); checkShould(context, expression); checkAssert(context, expression); }, }; }, }; function checkAssert(context, expression) { if (expression.type === 'CallExpression') { const { callee, arguments: args } = expression; if (callee.type === 'MemberExpression' && isIdentifier(callee.object, 'assert')) { findDuplicates(context, args); } } } function checkExpect(context, expression) { let currentExpression = expression; let args = []; while (true) { if (currentExpression.type === 'CallExpression') { args = [...currentExpression.arguments, ...args]; currentExpression = currentExpression.callee; } else if (currentExpression.type === 'MemberExpression') { currentExpression = currentExpression.object; } else if (isIdentifier(currentExpression, 'expect')) { break; } else { return; } } findDuplicates(context, args); } function checkShould(context, expression) { let currentExpression = expression; let args = []; let hasShould = false; while (true) { if (currentExpression.type === 'CallExpression') { args = [...currentExpression.arguments, ...args]; currentExpression = currentExpression.callee; } else if (currentExpression.type === 'MemberExpression') { if (isIdentifier(currentExpression.property, 'should')) { hasShould = true; } currentExpression = currentExpression.object; } else if (isIdentifier(currentExpression, 'should')) { break; } else if (hasShould) { args = [currentExpression, ...args]; break; } else { return; } } findDuplicates(context, args); } function findDuplicates(context, args) { const castedContext = context.sourceCode; for (let i = 0; i < args.length; i++) { for (let j = i + 1; j < args.length; j++) { const duplicates = equivalence.areEquivalent(args[i], args[j], castedContext); if (duplicates && !isLiteral$2(args[i])) { const message = toEncodedMessage$1(`Replace this argument or its duplicate.`, [args[j]]); context.report({ message, node: args[i] }); } } } } function decorate$n(rule) { return interceptReport(rule, (context, reportDescriptor) => { rule.meta.hasSuggestions = true; if ('node' in reportDescriptor && 'messageId' in reportDescriptor) { const { node, messageId, ...rest } = reportDescriptor, operators = new Set(['===', '==', '!==', '!=']); if (node.type === 'BinaryExpression' && operators.has(node.operator) && node.left.type !== 'Literal') { const prefix = node.operator.startsWith('!') ? '' : '!', value = context.sourceCode.getText(node.left), suggest = [ { desc: 'Replace self-compare with Number.isNaN()', fix: fixer => fixer.replaceText(node, `${prefix}Number.isNaN(${value})`), }, ]; context.report({ node, message: "Use 'Number.isNaN()' to check for 'NaN' value", ...rest, suggest, }); } } }); } const rule$1Q = decorate$n(eslintRules['no-self-compare']); const rule$1P = { meta: { messages: { replaceTab: 'Replace all tab characters in this file by sequences of white-spaces.', }, }, create(context) { return { 'Program:exit'() { const firstTab = context.sourceCode.lines .map((content, line) => ({ content, line })) .find(t => t.content.includes('\t')); if (firstTab !== undefined) { context.report({ messageId: 'replaceTab', loc: { line: firstTab.line + 1, column: 0 }, }); } }, }; }, }; const rule$1O = { meta: { messages: { noLayoutTable: 'Replace this layout table with a CSS layout.', }, }, create(context) { return { JSXOpeningElement(node) { const jsxNode = node; if (isPresentationTable(context, jsxNode)) { context.report({ node, messageId: 'noLayoutTable', }); } }, }; }, }; function decorate$m(rule) { return interceptReport(rule, reportExempting$3(isReferencedInsideGenerators)); } function reportExempting$3(exemptionCondition) { return (context, reportDescriptor) => { if ('node' in reportDescriptor) { const node = reportDescriptor['node']; if (!exemptionCondition(context, node)) { context.report(reportDescriptor); } } }; } function isReferencedInsideGenerators(context, node) { const variable = getVariableFromName(context, node.name, node); if (variable) { for (const reference of variable.references) { let scope = reference.from; while (scope !== null && !scope.variables.includes(variable)) { if (isGenerator(scope.block)) { return true; } scope = scope.upper; } } } return false; function isGenerator(node) { return ((node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression') && node.generator === true); } } const rule$1N = decorate$m(tsEslintRules['no-this-alias']); function decorate$l(rule) { rule.meta.hasSuggestions = true; return interceptReport(rule, (context, reportDescriptor) => { const suggest = []; if ('node' in reportDescriptor) { const { argument: thrown } = reportDescriptor.node; if (isStringLike(thrown)) { const thrownText = context.sourceCode.getText(thrown); suggest.push({ desc: 'Throw an error object', fix: fixer => fixer.replaceText(thrown, `new Error(${thrownText})`), }); } } context.report({ ...reportDescriptor, suggest, }); }); } function isStringLike(node) { return isStringLiteral(node) || isStringConcatenation(node); } function isStringConcatenation(node) { return isBinaryPlus(node) && (isStringLike(node.left) || isStringLike(node.right)); } const rule$1M = decorate$l(eslintRules['no-throw-literal']); const rule$1L = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { const services = context.sourceCode.parserServices; if (isRequiredParserServices(services)) { return { TryStatement: (node) => visitTryStatement(node, context, services), }; } return {}; }, }; function visitTryStatement(tryStmt, context, services) { if (tryStmt.handler) { const openPromises = []; const capturedPromises = []; let hasPotentiallyThrowingCalls = false; CallLikeExpressionVisitor.getCallExpressions(tryStmt.block, context).forEach(callLikeExpr => { if (callLikeExpr.type === 'AwaitExpression' || !isThenable$1(callLikeExpr, services)) { hasPotentiallyThrowingCalls = true; return; } if (isAwaitLike(callLikeExpr) || isThened(callLikeExpr) || isCatch(callLikeExpr)) { return; } (isCaught(callLikeExpr) ? capturedPromises : openPromises).push(callLikeExpr); }); if (!hasPotentiallyThrowingCalls) { checkForWrongCatch(tryStmt, openPromises, context); checkForUselessCatch(tryStmt, openPromises, capturedPromises, context); } } } class CallLikeExpressionVisitor { constructor() { this.callLikeExpressions = []; } static getCallExpressions(node, context) { const visitor = new CallLikeExpressionVisitor(); visitor.visit(node, context); return visitor.callLikeExpressions; } visit(root, context) { const visitNode = (node) => { switch (node.type) { case 'AwaitExpression': case 'CallExpression': case 'NewExpression': this.callLikeExpressions.push(node); break; case 'FunctionDeclaration': case 'FunctionExpression': case 'ArrowFunctionExpression': return; } childrenOf(node, context.sourceCode.visitorKeys).forEach(visitNode); }; visitNode(root); } } function checkForWrongCatch(tryStmt, openPromises, context) { if (openPromises.length > 0) { const ending = openPromises.length > 1 ? 's' : ''; const message = `Consider using 'await' for the promise${ending} inside this 'try' or replace it with 'Promise.prototype.catch(...)' usage${ending}.`; const token = context.sourceCode.getFirstToken(tryStmt); context.report({ message: toEncodedMessage$1(message, openPromises, Array(openPromises.length).fill('Promise')), loc: token.loc, }); } } function checkForUselessCatch(tryStmt, openPromises, capturedPromises, context) { if (openPromises.length === 0 && capturedPromises.length > 0) { const ending = capturedPromises.length > 1 ? 's' : ''; const message = `Consider removing this 'try' statement as promise${ending} rejection is already captured by '.catch()' method.`; const token = context.sourceCode.getFirstToken(tryStmt); context.report({ message: toEncodedMessage$1(message, capturedPromises, Array(capturedPromises.length).fill('Caught promise')), loc: token.loc, }); } } function isAwaitLike(callExpr) { return (callExpr.parent && (callExpr.parent.type === 'AwaitExpression' || callExpr.parent.type === 'YieldExpression')); } function isThened(callExpr) { return (callExpr.parent && callExpr.parent.type === 'MemberExpression' && callExpr.parent.property.type === 'Identifier' && callExpr.parent.property.name === 'then'); } function isCaught(callExpr) { return (callExpr.parent && callExpr.parent.type === 'MemberExpression' && callExpr.parent.property.type === 'Identifier' && callExpr.parent.property.name === 'catch'); } function isCatch(callExpr) { return (callExpr.type === 'CallExpression' && callExpr.callee.type === 'MemberExpression' && callExpr.callee.property.type === 'Identifier' && callExpr.callee.property.name === 'catch'); } function childrenOf(node, visitorKeys) { const keys = visitorKeys[node.type]; const children = []; if (keys) { for (const key of keys) { const child = node[key]; if (Array.isArray(child)) { children.push(...child); } else { children.push(child); } } } return children.filter(Boolean); } const rule$1K = { meta: { hasSuggestions: true, messages: { removeUndefined: 'Remove this redundant "undefined".', suggestRemoveUndefined: 'Remove this redundant argument', }, }, create(context) { const services = context.sourceCode.parserServices; if (isRequiredParserServices(services)) { return { CallExpression: (node) => { const call = node; const { arguments: args } = call; if (args.length === 0) { return; } const lastArgument = args[args.length - 1]; if (isUndefined(lastArgument) && isOptionalParameter(args.length - 1, call, services)) { context.report({ messageId: 'removeUndefined', node: lastArgument, suggest: [ { messageId: 'suggestRemoveUndefined', fix: fixer => { if (call.arguments.length === 1) { const openingParen = context.sourceCode.getTokenAfter(call.callee); const closingParen = context.sourceCode.getLastToken(node); const [, begin] = openingParen.range; const [end] = closingParen.range; return fixer.removeRange([begin, end]); } else { const [, begin] = args[args.length - 2].range; const [, end] = lastArgument.range; return fixer.removeRange([begin, end]); } }, }, ], }); } }, }; } return {}; }, }; function isOptionalParameter(paramIndex, node, services) { const signature = services.program .getTypeChecker() .getResolvedSignature(services.esTreeNodeToTSNodeMap.get(node)); if (signature) { const declaration = signature.declaration; if (declaration && isFunctionLikeDeclaration(declaration)) { const { parameters } = declaration; const parameter = parameters[paramIndex]; return parameter && (parameter.initializer || parameter.questionToken); } } return false; } function isFunctionLikeDeclaration(declaration) { return [ ts__namespace.SyntaxKind.FunctionDeclaration, ts__namespace.SyntaxKind.FunctionExpression, ts__namespace.SyntaxKind.ArrowFunction, ts__namespace.SyntaxKind.MethodDeclaration, ts__namespace.SyntaxKind.Constructor, ts__namespace.SyntaxKind.GetAccessor, ts__namespace.SyntaxKind.SetAccessor, ].includes(declaration.kind); } const rule$1J = { meta: { messages: { useNull: 'Use null instead.', }, }, create(context) { function raiseOnUndefined(node) { if (isUndefined(node)) { context.report({ messageId: 'useNull', node, }); } } return { VariableDeclarator: (node) => { const { init } = node; if (init) { raiseOnUndefined(init); } }, AssignmentExpression: (node) => { const { right } = node; raiseOnUndefined(right); }, Property: (node) => { const { value } = node; raiseOnUndefined(value); }, }; }, }; const NestingStatementLike = [ 'IfStatement', 'ForStatement', 'ForInStatement', 'ForOfStatement', 'WhileStatement', ]; const rule$1I = { create(context) { return { Program: (node) => checkStatements(node.body, context), BlockStatement: (node) => checkStatements(node.body, context), TSModuleBlock: (node) => checkStatements(node.body, context), }; }, }; function checkStatements(statements, context) { chain(statements) .filter(chainedStatements => chainedStatements.areUnenclosed()) .forEach(unenclosedConsecutives => { if (unenclosedConsecutives.areAdjacent()) { raiseAdjacenceIssue(unenclosedConsecutives, context); } else if (unenclosedConsecutives.areBothIndented()) { raiseBlockIssue(unenclosedConsecutives, countStatementsInTheSamePile(unenclosedConsecutives.prev, statements), context); } else if (unenclosedConsecutives.areInlinedAndIndented()) { raiseInlineAndIndentedIssue(unenclosedConsecutives, context); } }); } function chain(statements) { return statements .reduce((result, statement, i, array) => { if (i < array.length - 1 && isNestingStatement(statement)) { result.push({ prev: statement, next: array[i + 1] }); } return result; }, new Array()) .map(pair => { return new ChainedStatements(pair.prev, extractLastBody(pair.prev), pair.next); }); } function extractLastBody(statement) { if (statement.type === 'IfStatement') { if (statement.alternate) { return statement.alternate; } else { return statement.consequent; } } else { return statement.body; } } function countStatementsInTheSamePile(reference, statements) { const startOfPile = position(reference).start; let lastLineOfPile = startOfPile.line; for (const statement of statements) { const currentPosition = position(statement); const currentLine = currentPosition.end.line; const currentIndentation = currentPosition.start.column; if (currentLine > startOfPile.line) { if (currentIndentation === startOfPile.column) { lastLineOfPile = currentPosition.end.line; } else { break; } } } return lastLineOfPile - startOfPile.line + 1; } function raiseAdjacenceIssue(adjacentStatements, context) { context.report({ message: `This statement will not be executed ${adjacentStatements.includedStatementQualifier()}; only the first statement will be. ` + `The rest will execute ${adjacentStatements.excludedStatementsQualifier()}.`, node: adjacentStatements.next, }); } function raiseBlockIssue(piledStatements, sizeOfPile, context) { context.report({ message: `This line will not be executed ${piledStatements.includedStatementQualifier()}; only the first line of this ${sizeOfPile}-line block will be. ` + `The rest will execute ${piledStatements.excludedStatementsQualifier()}.`, node: piledStatements.next, }); } function raiseInlineAndIndentedIssue(chainedStatements, context) { context.report({ message: `This line will not be executed ${chainedStatements.includedStatementQualifier()}; only the first statement will be. ` + `The rest will execute ${chainedStatements.excludedStatementsQualifier()}.`, node: chainedStatements.next, }); } function isNestingStatement(node) { return NestingStatementLike.includes(node.type); } class ChainedStatements { constructor(topStatement, prev, next) { this.topStatement = topStatement; this.prev = prev; this.next = next; const topPosition = position(topStatement); const prevPosition = position(prev); const nextPosition = position(next); this.positions = { prevTopStart: topPosition.start, prevTopEnd: topPosition.end, prevStart: prevPosition.start, prevEnd: prevPosition.end, nextStart: nextPosition.start, nextEnd: nextPosition.end, }; } areUnenclosed() { return this.prev.type !== 'BlockStatement'; } areAdjacent() { return this.positions.prevEnd.line === this.positions.nextStart.line; } areBothIndented() { return (this.positions.prevStart.column === this.positions.nextStart.column && this.prevIsIndented()); } areInlinedAndIndented() { return (this.positions.prevStart.line === this.positions.prevTopEnd.line && this.positions.nextStart.column > this.positions.prevTopStart.column); } includedStatementQualifier() { return this.topStatement.type === 'IfStatement' ? 'conditionally' : 'in a loop'; } excludedStatementsQualifier() { return this.topStatement.type === 'IfStatement' ? 'unconditionally' : 'only once'; } prevIsIndented() { return this.positions.prevStart.column > this.positions.prevTopStart.column; } } function position(node) { return node.loc; } const rule$1H = { meta: { messages: { noGeneratedKeys: 'Do not use generated values for keys of React list components.', }, }, create(context) { return { "JSXAttribute[name.name='key']": (pNode) => { const node = pNode; const value = node.value; if (!value || value.type !== 'JSXExpressionContainer') { return; } checkPropValue(context, value.expression); }, }; }, }; function checkPropValue(context, node) { if (isGeneratedExpression(node)) { context.report({ messageId: 'noGeneratedKeys', node: node, }); return; } if (node.type === 'TemplateLiteral') { node.expressions.filter(isGeneratedExpression).forEach(() => { context.report({ messageId: 'noGeneratedKeys', node: node, }); }); return; } if (node.type === 'BinaryExpression') { const callExpressions = getCallExpressionsFromBinaryExpression(node); callExpressions.filter(isGeneratedExpression).forEach(() => { context.report({ messageId: 'noGeneratedKeys', node: node, }); }); return; } if (node.type === 'CallExpression' && node.callee && node.callee.type === 'MemberExpression' && node.callee.object && isGeneratedExpression(node.callee.object) && node.callee.property && node.callee.property.type === 'Identifier' && node.callee.property.name === 'toString') { context.report({ messageId: 'noGeneratedKeys', node: node, }); return; } if (node.type === 'CallExpression' && node.callee && node.callee.type === 'Identifier' && node.callee.name === 'String' && Array.isArray(node.arguments) && node.arguments.length > 0 && isGeneratedExpression(node.arguments[0])) { context.report({ messageId: 'noGeneratedKeys', node: node.arguments[0], }); } } function isGeneratedExpression(node) { return isMathRandom(node) || isDateNow(node); function isMathRandom(node) { return (node.type === 'CallExpression' && isMemberExpression(node.callee, 'Math', 'random')); } function isDateNow(node) { return (node.type === 'CallExpression' && isMemberExpression(node.callee, 'Date', 'now')); } } function getCallExpressionsFromBinaryExpression(side) { if (side.type === 'CallExpression') { return side; } if (side.type === 'BinaryExpression') { const left = getCallExpressionsFromBinaryExpression(side.left); const right = getCallExpressionsFromBinaryExpression(side.right); return [].concat(left, right).filter(Boolean); } return null; } function decorate$k(rule) { rule.meta.hasSuggestions = true; return interceptReport(rule, (context, descriptor) => { const { messageId, fix, data, ...rest } = descriptor; if (messageId !== 'unknownPropWithStandardName') { context.report(descriptor); return; } const suggest = [ { desc: `Replace with '${data.standardName}'`, fix, }, ]; context.report({ messageId, data, suggest, ...rest }); }); } const noUnkownProp = react.rules['no-unknown-property']; const decoratedNoUnkownProp = decorate$k(noUnkownProp); const flaggedNodeStarts = new Map(); const ariaPropsRule = jsxA11y.rules['aria-props']; const decoratedAriaPropsRule = interceptReport(ariaPropsRule, (context, descriptor) => { if ('node' in descriptor) { const start = descriptor.node.range[0]; if (!flaggedNodeStarts.get(start)) { flaggedNodeStarts.set(start, true); context.report(descriptor); } } }); const twiceDecoratedNoUnkownProp = interceptReport(decoratedNoUnkownProp, (context, descriptor) => { if ('node' in descriptor) { const start = descriptor.node.range[0]; if (!flaggedNodeStarts.get(start)) { context.report(descriptor); } } }); const rule$1G = { meta: { hasSuggestions: true, messages: { ...decoratedAriaPropsRule.meta.messages, ...twiceDecoratedNoUnkownProp.meta.messages, }, schema: [ { type: 'object', properties: { ignore: { type: 'array', items: { type: 'string', }, }, }, }, ], }, create(context) { const ariaPropsListener = decoratedAriaPropsRule.create(context); const noUnkownPropListener = twiceDecoratedNoUnkownProp.create(context); return mergeRules(ariaPropsListener, noUnkownPropListener); }, }; function decorate$j(rule) { rule.meta.hasSuggestions = true; return interceptReport(rule, (context, reportDescriptor) => { const loc = reportDescriptor.loc; const node = reportDescriptor.node; context.report({ ...reportDescriptor, suggest: [ { desc: 'Remove unreachable code', fix: fixer => removeNodeWithLeadingWhitespaces(context, node, fixer, context.sourceCode.getIndexFromLoc(loc.end)), }, ], }); }); } const rule$1F = decorate$j(eslintRules['no-unreachable']); function decorate$i(rule) { rule.meta.messages['unsafeMethod'] = '{{method}} is unsafe for use in async rendering.'; return interceptReportForReact(rule, (context, descriptor) => { const { node: { key }, } = descriptor; context.report({ ...descriptor, loc: key.loc }); }); } const rule$1E = decorate$i(react.rules['no-unsafe']); const rule$1D = { meta: { messages: { safeExpanding: 'Make sure that expanding this archive file is safe here.', }, }, create(context) { function canBeProperty(prop, name) { return (prop.type === 'SpreadElement' || isIdentifier(prop.key, name) || (isLiteral$2(prop.key) && prop.key.value === name)); } function isSensiteTarCall(call, fqn) { if (fqn === 'tar.x') { const firstArg = call.arguments.length > 0 ? call.arguments[0] : null; if (!firstArg) { return false; } const firstArgValue = getValueOfExpression(context, firstArg, 'ObjectExpression'); return (!!firstArgValue && !firstArgValue.properties.some(prop => canBeProperty(prop, 'filter'))); } return false; } function isSensiteExtractZipCall(call, fqn) { if (fqn === 'extract-zip') { const secondArg = call.arguments.length > 1 ? call.arguments[1] : null; if (!secondArg) { return false; } const secondArgValue = getValueOfExpression(context, secondArg, 'ObjectExpression'); return (!!secondArgValue && !secondArgValue.properties.some(prop => canBeProperty(prop, 'onEntry'))); } return false; } return { CallExpression(node) { const call = node; const fqn = getFullyQualifiedName(context, call); if (isSensiteTarCall(call, fqn) || isSensiteExtractZipCall(call, fqn) || fqn === 'jszip.loadAsync' || fqn === 'yauzl.open' || fqn === 'adm-zip.extractAllTo') { context.report({ messageId: 'safeExpanding', node: call.callee, }); } }, }; }, }; function decorate$h(rule) { return interceptReportForReact(rule, (context, report) => { const message = 'Move this component definition out of the parent component and pass data as props.'; const { node } = report; const loc = getMainNodeLocation(node, context); if (loc) { context.report({ ...report, loc, message }); } else { context.report({ ...report, message }); } }); function getMainNodeLocation(node, context) { var _a; if (node.type === 'ClassDeclaration' || node.type === 'ClassExpression') { if (node.id) { return node.id.loc; } else { return (_a = context.sourceCode.getFirstToken(node, token => token.value === 'class')) === null || _a === void 0 ? void 0 : _a.loc; } } if (functionLike$1.has(node.type)) { const fun = node; const ctx = context; return locations.getMainFunctionTokenLocation(fun, fun.parent, ctx); } return node.loc; } } const rule$1C = decorate$h(react.rules['no-unstable-nested-components']); const rule$1B = { meta: { hasSuggestions: true, messages: { throwOrRemoveError: 'Throw this error or remove this useless statement.', suggestThrowError: 'Throw this error', }, }, create(context) { function looksLikeAnError(expression) { const text = context.sourceCode.getText(expression); return text.endsWith('Error') || text.endsWith('Exception'); } return { 'ExpressionStatement > NewExpression'(node) { const expression = node.callee; if (looksLikeAnError(expression)) { context.report({ messageId: 'throwOrRemoveError', node, suggest: [ { messageId: 'suggestThrowError', fix: fixer => fixer.insertTextBefore(getParent(context, node), 'throw '), }, ], }); } }, }; }, }; function decorate$g(rule) { return interceptReport(rule, reportExempting$2(expr => isNegatedIife(expr) || containsChaiExpect(expr) || containsValidChaiShould(expr) || isAuraLightningComponent$1(expr) || isSequenceWithSideEffects(expr))); } function reportExempting$2(exemptionCondition) { return (context, reportDescriptor) => { if ('node' in reportDescriptor) { const n = reportDescriptor['node']; const expr = n.expression; if (!exemptionCondition(expr)) { context.report(reportDescriptor); } } }; } function containsChaiExpect(node) { if (node.type === 'CallExpression') { if (node.callee.type === 'Identifier' && node.callee.name === 'expect') { return true; } else { return containsChaiExpect(node.callee); } } else if (node.type === 'MemberExpression') { return containsChaiExpect(node.object); } return false; } function containsValidChaiShould(node, isSubexpr = false) { if (node.type === 'CallExpression') { return containsValidChaiShould(node.callee, true); } else if (node.type === 'MemberExpression') { if (node.property && node.property.type === 'Identifier' && node.property.name === 'should') { return isSubexpr; } else { return containsValidChaiShould(node.object, true); } } return false; } function isNegatedIife(node) { return node.type === 'UnaryExpression' && node.operator === '!' && isIife(node.argument); } function isIife(node) { return (node.type === 'CallExpression' && (node.callee.type === 'FunctionExpression' || node.callee.type === 'ArrowFunctionExpression')); } function isSequenceWithSideEffects(node) { return (node.type === 'SequenceExpression' && node.expressions[node.expressions.length - 1].type === 'AssignmentExpression'); } function isAuraLightningComponent$1(node) { var _a, _b; return (node.type === 'ObjectExpression' && node.properties.length > 0 && ((_b = (_a = node.parent) === null || _a === void 0 ? void 0 : _a.parent) === null || _b === void 0 ? void 0 : _b.type) === 'Program'); } const rule$1A = decorate$g(tsEslintRules['no-unused-expressions']); const rule$1z = { meta: { hasSuggestions: true, messages: { removeOrRenameParameter: 'Remove the unused function parameter "{{param}}" or rename it to "_{{param}}" to make intention explicit.', suggestRemoveParameter: 'Remove "{{param}}" (beware of call sites)', suggestRenameParameter: 'Rename "{{param}}" to "_{{param}}"', }, }, create(context) { return { 'FunctionDeclaration, FunctionExpression'(node) { reportUnusedArgument(node, node.id, context); }, ArrowFunctionExpression: (node) => { reportUnusedArgument(node, undefined, context); }, }; }, }; function reportUnusedArgument(node, functionId, context) { const parent = node.parent; if (parent && parent.type === 'Property' && parent.kind === 'set') { return; } if (context.sourceCode .getScope(node) .variables.some(v => v.name === 'arguments' && v.identifiers.length === 0 && v.references.length > 0)) { return; } let parametersVariable = context.sourceCode.getDeclaredVariables(node); if (functionId) { parametersVariable = parametersVariable.filter(v => v.name !== functionId.name); } for (const param of parametersVariable) { if (isUnusedVariable(param) && !isIgnoredParameter(param) && !isParameterProperty(param) && !isThisParameter(param)) { context.report({ messageId: 'removeOrRenameParameter', node: param.identifiers[0], data: { param: param.name, }, suggest: getSuggestions(param, context), }); } } } function getSuggestions(paramVariable, context) { const paramIdentifier = paramVariable.identifiers[0]; const suggestions = [ { messageId: 'suggestRenameParameter', data: { param: paramVariable.name, }, fix: fixer => fixer.insertTextBefore(paramIdentifier, '_'), }, ]; const func = paramVariable.defs[0].node; if (paramIdentifier.parent === func) { suggestions.push(getParameterRemovalSuggestion(func, paramVariable, paramIdentifier, context)); } return suggestions; } function getParameterRemovalSuggestion(func, paramVariable, paramIdentifier, context) { return { messageId: 'suggestRemoveParameter', data: { param: paramVariable.name, }, fix: fixer => { const paramIndex = func.params.indexOf(paramIdentifier); const param = func.params[paramIndex]; if (func.params.length === 1) { const openingParenthesis = context.sourceCode.getTokenBefore(param); const closingParenthesis = context.sourceCode.getTokenAfter(param, token => token.value === ')'); let [start, end] = param.range; if (openingParenthesis && openingParenthesis.value === '(') { start = openingParenthesis.range[0]; end = closingParenthesis.range[1]; } return fixer.replaceTextRange([start, end], '()'); } else if (func.params.length - 1 === paramIndex) { const commaAfter = context.sourceCode.getTokenAfter(param, token => token.value === ','); const commaBefore = context.sourceCode.getTokenBefore(param, token => token.value === ','); let start = commaBefore.range[1]; let end = param.range[1]; if (commaAfter) { end = commaAfter.range[1]; } else { start = commaBefore.range[0]; } return fixer.removeRange([start, end]); } else { const [start] = func.params[paramIndex].range; const [end] = func.params[paramIndex + 1].range; return fixer.removeRange([start, end]); } }, }; } function isUnusedVariable(variable) { const refs = variable.references; return refs.length === 0 || (refs.length === 1 && refs[0].init); } function isIgnoredParameter(variable) { return variable.name.startsWith('_'); } function isParameterProperty(variable) { return variable.defs.some(def => { var _a; const parent = def.name.parent; return ((parent === null || parent === void 0 ? void 0 : parent.type) === 'TSParameterProperty' || ((parent === null || parent === void 0 ? void 0 : parent.type) === 'AssignmentPattern' && ((_a = parent.parent) === null || _a === void 0 ? void 0 : _a.type) === 'TSParameterProperty')); }); } function isThisParameter(variable) { return variable.name === 'this'; } function decorate$f(rule) { rule.meta.hasSuggestions = true; return interceptReport(rule, (context, reportDescriptor) => { const suggest = []; const node = reportDescriptor.node; suggest.push({ desc: 'Remove unused private class member', fix: fixer => fixer.remove(node), }); context.report({ ...reportDescriptor, suggest }); }); } const rule$1y = decorate$f(eslintRules['no-unused-private-class-members']); function decorate$e(rule) { rule.meta.hasSuggestions = true; return interceptReport(rule, (context, reportDescriptor) => { const suggest = []; const node = reportDescriptor.node; if (node.type === 'CallExpression') { const { callee, arguments: args } = node; if (callee.type === 'MemberExpression') { const { object, property } = callee; if (property.type === 'Identifier' && property.name === 'call') { const desc = 'Remove redundant call()'; if (args.length > 1) { addFixForCall(suggest, desc, object.range, args[1].range); } else { addFixForCallNoArgs(suggest, desc, object.range, node.range); } } if (property.type === 'Identifier' && property.name === 'apply') { const desc = 'Remove redundant apply()', argsText = context.sourceCode.getText(args[1], -1, -1); addFixForApply(suggest, desc, argsText, object.range, node.range); } } } context.report({ ...reportDescriptor, suggest }); }); } function addFixForCall(suggest, desc, startRange, endRange) { if (startRange && endRange) { suggest.push({ desc, fix: fixer => fixer.replaceTextRange([startRange[1], endRange[0]], '('), }); } } function addFixForCallNoArgs(suggest, desc, startRange, endRange) { if (startRange && endRange) { suggest.push({ desc, fix: fixer => fixer.replaceTextRange([startRange[1], endRange[1]], '()'), }); } } function addFixForApply(suggest, desc, argsText, startRange, endRange) { if (startRange && endRange) { suggest.push({ desc, fix: fixer => fixer.replaceTextRange([startRange[1], endRange[1]], `(${argsText})`), }); } } const rule$1x = decorate$e(eslintRules['no-useless-call']); function decorate$d(rule) { rule.meta.hasSuggestions = true; return interceptReport(rule, (context, reportDescriptor) => { const suggest = []; const node = reportDescriptor.node; if (node.type === 'MethodDefinition' && node.kind === 'constructor') { suggest.push({ desc: 'Remove constructor', fix: fixer => fixer.remove(node), }); } context.report({ ...reportDescriptor, suggest }); }); } function checkAccessibility(node) { switch (node.accessibility) { case 'protected': case 'private': return false; case 'public': if (node.parent.type === 'ClassBody' && 'superClass' in node.parent.parent && node.parent.parent.superClass) { return false; } break; } return true; } function checkParams(node) { return !node.value.params.some(param => { var _a; return param.type === 'TSParameterProperty' || ((_a = param.decorators) === null || _a === void 0 ? void 0 : _a.length) > 0; }); } function checkDecorator(node) { var _a, _b; return !(((_a = node.parent.parent) === null || _a === void 0 ? void 0 : _a.type) === 'ClassDeclaration' && ((_b = node.parent.parent.decorators) === null || _b === void 0 ? void 0 : _b.length) > 0); } function checkInheritance(node, context) { var _a; if (node.parent.type === 'ClassBody' && 'superClass' in node.parent.parent && node.parent.parent.superClass) { const superClass = node.parent.parent.superClass; const variable = getVariableFromName(context, superClass.name, node); for (const def of (_a = variable === null || variable === void 0 ? void 0 : variable.defs) !== null && _a !== void 0 ? _a : []) { if (def.type === 'ImportBinding') { return false; } if (def.node.type === 'ClassDeclaration') { const decl = def.node; if (decl.body.body.some(member => member.type === 'MethodDefinition' && member.kind === 'constructor' && member.accessibility === 'protected')) { return false; } } } } return true; } const eslintNoUselessConstructor = eslintRules['no-useless-constructor']; const originalRule = { meta: { hasSuggestions: true, messages: eslintNoUselessConstructor.meta.messages, }, create(context) { const rules = eslintNoUselessConstructor.create(context); return { MethodDefinition(node) { if (node.value.type === 'FunctionExpression' && node.kind === 'constructor' && checkAccessibility(node) && checkParams(node) && checkDecorator(node) && checkInheritance(node, context)) { rules.MethodDefinition(node); } }, }; }, }; const rule$1w = decorate$d(originalRule); const rule$1v = { meta: { messages: { removeIncrement: 'Remove this {{updateOperator}}rement or correct the code not to waste it.', }, }, create(context) { function reportUpdateExpression(updateExpression) { const updateOperator = updateExpression.operator === '++' ? 'inc' : 'dec'; context.report({ messageId: 'removeIncrement', data: { updateOperator, }, node: updateExpression, }); } return { 'ReturnStatement > UpdateExpression'(node) { const updateExpression = node; const argument = updateExpression.argument; if (!updateExpression.prefix && argument.type === 'Identifier' && isLocalIdentifier(argument, context.sourceCode.getScope(node))) { reportUpdateExpression(updateExpression); } }, AssignmentExpression(node) { const assignment = node; const rhs = assignment.right; if (rhs.type === 'UpdateExpression' && !rhs.prefix) { const lhs = assignment.left; if (lhs.type === 'Identifier' && rhs.argument.type === 'Identifier' && rhs.argument.name === lhs.name) { reportUpdateExpression(rhs); } } }, }; }, }; function isLocalIdentifier(id, scope) { return scope.variables.some(v => v.identifiers.some(i => i.name === id.name)); } const rule$1u = { meta: { messages: { removeIntersection: 'Remove this type without members or change this type intersection.', simplifyIntersection: 'Simplify this intersection as it always has type "{{type}}".', }, }, create(context) { const services = context.sourceCode.parserServices; if (isRequiredParserServices(services)) { return { TSIntersectionType: (node) => { const intersection = node; const anyOrNever = intersection.types.find(typeNode => ['TSAnyKeyword', 'TSNeverKeyword'].includes(typeNode.type)); if (anyOrNever) { context.report({ messageId: 'simplifyIntersection', data: { type: anyOrNever.type === 'TSAnyKeyword' ? 'any' : 'never', }, node, }); } else { intersection.types.forEach(typeNode => { const tp = services.program .getTypeChecker() .getTypeAtLocation(services.esTreeNodeToTSNodeMap.get(typeNode)); if (isTypeWithoutMembers(tp)) { context.report({ messageId: 'removeIntersection', node: typeNode, }); } }); } }, }; } return {}; }, }; function isTypeWithoutMembers(tp) { return isNullLike(tp) || (isEmptyInterface(tp) && isStandaloneInterface(tp.symbol)); } function isNullLike(tp) { return (Boolean(tp.flags & ts__namespace.TypeFlags.Null) || Boolean(tp.flags & ts__namespace.TypeFlags.Undefined) || Boolean(tp.flags & ts__namespace.TypeFlags.Void)); } function isEmptyInterface(tp) { return (tp.getProperties().length === 0 && (!tp.declaredIndexInfos || tp.declaredIndexInfos.length === 0)); } function isStandaloneInterface(typeSymbol) { if (!typeSymbol) { return false; } const { declarations } = typeSymbol; return (!declarations || declarations.every(declaration => { var _a; return (isInterfaceDeclaration(declaration) && ((_a = declaration.heritageClauses) !== null && _a !== void 0 ? _a : []).length === 0); })); } function isInterfaceDeclaration(declaration) { return declaration.kind === ts__namespace.SyntaxKind.InterfaceDeclaration; } const declarationSelector = [ ':matches(', [ 'VariableDeclarator[init.callee.name="useState"]', 'VariableDeclarator[init.callee.object.type="Identifier"][init.callee.property.name="useState"]', ].join(','), ')', '[id.type="ArrayPattern"]', '[id.elements.length=2]', '[id.elements.0.type="Identifier"]', '[id.elements.1.type="Identifier"]', ].join(''); const callSelector = [ 'CallExpression[callee.type="Identifier"]', '[arguments.length=1]', '[arguments.0.type="Identifier"]', ].join(''); const rule$1t = { meta: { messages: { uselessSetState: 'Change the argument of this setter to not use its matching state variable', }, }, create(context) { const referencesBySetterName = {}; return { [declarationSelector](node) { if (isReactCall(context, node.init)) { const { elements } = node.id; const setter = elements[1].name; referencesBySetterName[setter] = { setter: getVariableFromName(context, setter, node), value: getVariableFromName(context, elements[0].name, node), }; } }, [callSelector](node) { const setter = getVariableFromName(context, node.callee.name, node); const value = getVariableFromName(context, node.arguments[0].name, node); const key = setter === null || setter === void 0 ? void 0 : setter.name; if (setter && value && referencesBySetterName.hasOwnProperty(key) && referencesBySetterName[key].setter === setter && referencesBySetterName[key].value === value) { context.report({ messageId: 'uselessSetState', node, }); } }, }; }, }; function isReactCall(context, callExpr) { const fqn = getFullyQualifiedName(context, callExpr); if (fqn) { const [module] = fqn.split('.'); return module === 'react'; } return false; } function decorate$c(rule) { return interceptReport(rule, (context, reportDescriptor) => { if ('node' in reportDescriptor) { const { node, ...rest } = reportDescriptor; const { declarations: [firstDecl, ..._], } = node; const varToken = context.sourceCode.getTokenBefore(firstDecl.id); const identifierEnd = firstDecl.id.loc.end; if (varToken == null) { return; } context.report({ loc: { start: varToken.loc.start, end: identifierEnd, }, ...rest, }); } }); } const rule$1s = decorate$c(eslintRules['no-var']); const rule$1r = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { return { "VariableDeclaration[kind='var']": (node) => { const variables = context.sourceCode.getDeclaredVariables(node); for (const variable of variables) { const declaration = variable.identifiers[0]; const misused = variable.references .filter(reference => !reference.init && comesBefore(reference.identifier, declaration)) .map(reference => reference.identifier); if (misused.length > 0) { context.report({ message: toEncodedMessage$1(`Move the declaration of "${declaration.name}" before this usage.`, [declaration], ['Declaration']), node: misused[0], }); } } }, }; }, }; function comesBefore(node, other) { const nodeLine = line(node), otherLine = line(other); return nodeLine < otherLine || (nodeLine === otherLine && column(node) < column(other)); } function line(node) { return node.loc.start.line; } function column(node) { return node.loc.start.column; } const rule$1q = { meta: { messages: { safeVueBypassing: 'Make sure bypassing Vue built-in sanitization is safe here.', }, }, create(context) { const services = context.sourceCode.parserServices; function attrsHref(calleeName) { return `CallExpression[callee.name='${calleeName}'] ObjectExpression.arguments:nth-child(2) > Property[key.name='attrs'] > ObjectExpression.value > Property[key.name='href']`; } const ruleListener = { ["JSXAttribute[name.name='domPropsInnerHTML']," + "Property[key.name='domProps'] > ObjectExpression.value > Property[key.name='innerHTML']"](node) { context.report({ node, messageId: 'safeVueBypassing' }); }, [`${attrsHref('createElement')},${attrsHref('h')}`](node) { context.report({ node, messageId: 'safeVueBypassing' }); }, }; if (services.defineTemplateBodyVisitor) { const templateBodyVisitor = context.sourceCode.parserServices.defineTemplateBodyVisitor({ ["VAttribute[directive=true][key.name.name='html']," + "VAttribute[directive=true][key.argument.name='href']"](node) { context.report({ loc: node.loc, messageId: 'safeVueBypassing', }); }, }); Object.assign(ruleListener, templateBodyVisitor); } return ruleListener; }, }; const WEAK_CIPHERS = ['bf', 'blowfish', 'des', 'rc2', 'rc4']; const rule$1p = { meta: { messages: { strongerCipher: 'Use a strong cipher algorithm.', }, }, create(context) { return { CallExpression(node) { var _a; const callExpression = node; if (getFullyQualifiedName(context, callExpression) === 'crypto.createCipheriv') { const algorithm = getValueOfExpression(context, callExpression.arguments[0], 'Literal'); const algorithmValue = (_a = algorithm === null || algorithm === void 0 ? void 0 : algorithm.value) === null || _a === void 0 ? void 0 : _a.toString().toLowerCase(); if (algorithm && algorithmValue && WEAK_CIPHERS.findIndex(cipher => algorithmValue.startsWith(cipher)) >= 0) { context.report({ messageId: 'strongerCipher', node: algorithm, }); } } }, }; }, }; const MINIMAL_MODULUS_LENGTH = 2048; const MINIMAL_DIVISOR_LENGTH = 224; const WEAK_CURVES = [ 'secp112r1', 'secp112r2', 'secp128r1', 'secp128r2', 'secp160k1', 'secp160r1', 'secp160r2', 'secp160r2', 'secp192k1', 'secp192r1', 'prime192v2', 'prime192v3', 'sect113r1', 'sect113r2', 'sect131r1', 'sect131r2', 'sect163k1', 'sect163r1', 'sect163r2', 'sect193r1', 'sect193r2', 'c2tnb191v1', 'c2tnb191v2', 'c2tnb191v3', ]; const rule$1o = { meta: { messages: { modulusLength: 'Use a modulus length of at least {{minimalLength}} bits for {{algorithm}} cipher algorithm.', divisorLength: 'Use a divisor length of at least {{minimalLength}} bits for {{algorithm}} cipher algorithm.', strongerCurve: `{{curve}} doesn't provide enough security. Use a stronger curve.`, }, }, create(context) { function getNumericValue(node) { const literal = getValueOfExpression(context, node, 'Literal'); if (literal && typeof literal.value === 'number') { return literal.value; } return undefined; } function checkRsaAndDsaOptions(algorithm, options) { const modulusProperty = getProperty$1(options, 'modulusLength', context); const modulusLength = getNumericValue(modulusProperty === null || modulusProperty === void 0 ? void 0 : modulusProperty.value); if (modulusProperty && modulusLength && modulusLength < MINIMAL_MODULUS_LENGTH) { context.report({ node: modulusProperty, messageId: 'modulusLength', data: { minimalLength: MINIMAL_MODULUS_LENGTH.toString(), algorithm, }, }); } const divisorProperty = getProperty$1(options, 'divisorLength', context); const divisorLength = getNumericValue(divisorProperty === null || divisorProperty === void 0 ? void 0 : divisorProperty.value); if (divisorProperty && divisorLength && divisorLength < MINIMAL_DIVISOR_LENGTH) { context.report({ node: divisorProperty, messageId: 'divisorLength', data: { minimalLength: MINIMAL_DIVISOR_LENGTH.toString(), algorithm, }, }); } } function checkEcCurve(options) { var _a, _b; const namedCurveProperty = getProperty$1(options, 'namedCurve', context); const namedCurve = (_b = (_a = getValueOfExpression(context, namedCurveProperty === null || namedCurveProperty === void 0 ? void 0 : namedCurveProperty.value, 'Literal')) === null || _a === void 0 ? void 0 : _a.value) === null || _b === void 0 ? void 0 : _b.toString(); if (namedCurveProperty && namedCurve && WEAK_CURVES.includes(namedCurve)) { context.report({ node: namedCurveProperty, messageId: 'strongerCurve', data: { curve: namedCurve, }, }); } } return { CallExpression: (node) => { var _a; const callExpression = node; const { callee } = callExpression; if (callee.type === 'MemberExpression' && isIdentifier(callee.property, 'generateKeyPair', 'generateKeyPairSync')) { if (callExpression.arguments.length < 2) { return; } const [algorithmArg, options] = callExpression.arguments; const optionsArg = getValueOfExpression(context, options, 'ObjectExpression'); if (!optionsArg) { return; } const algorithm = (_a = getValueOfExpression(context, algorithmArg, 'Literal')) === null || _a === void 0 ? void 0 : _a.value; if (algorithm === 'rsa' || algorithm === 'dsa') { checkRsaAndDsaOptions(algorithm, optionsArg); } else if (algorithm === 'ec') { checkEcCurve(optionsArg); } } }, }; }, }; const rule$1n = { meta: { messages: { wildcardImport: 'Explicitly {{xPort}} the specific member needed.', }, }, create(context) { function report(node, xPort) { context.report({ messageId: 'wildcardImport', data: { xPort }, node, }); } return { ImportNamespaceSpecifier: (node) => report(node, 'import'), ExportAllDeclaration: (node) => report(node, 'export'), }; }, }; const MESSAGE = 'Convert this operand into a number.'; const rule$1m = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { const services = context.sourceCode.parserServices; if (!isRequiredParserServices(services)) { return {}; } return { BinaryExpression: (node) => { const binaryExpression = node; const operator = binaryExpression.operator; const leftType = getTypeFromTreeNode$1(binaryExpression.left, services); const rightType = getTypeFromTreeNode$1(binaryExpression.right, services); if (operator === '+') { checkPlus(leftType, rightType, binaryExpression, context); } if (operator === '<' || operator === '>' || operator === '<=' || operator === '>=') { checkComparison(leftType, rightType, binaryExpression, context); } if (operator === '-' || operator === '*' || operator === '/' || operator === '%') { checkArithmetic(leftType, rightType, binaryExpression, context); } }, AssignmentExpression: (node) => { const assignmentExpression = node; const operator = assignmentExpression.operator; const leftType = getTypeFromTreeNode$1(assignmentExpression.left, services); const rightType = getTypeFromTreeNode$1(assignmentExpression.right, services); if (operator === '+=') { checkPlus(leftType, rightType, assignmentExpression, context); } if (operator === '-=' || operator === '*=' || operator === '/=' || operator === '%=') { checkArithmetic(leftType, rightType, assignmentExpression, context); } }, 'UnaryExpression[operator="-"]': (node) => { const unaryExpression = node; const type = getTypeFromTreeNode$1(unaryExpression.argument, services); if (isBooleanStringOrDate(type)) { context.report({ node: unaryExpression.argument, message: toEncodedMessage$1(MESSAGE, []), }); } }, UpdateExpression: (node) => { const updateExpression = node; const type = getTypeFromTreeNode$1(updateExpression.argument, services); if (isBooleanStringOrDate(type)) { context.report({ node: updateExpression.argument, message: toEncodedMessage$1(MESSAGE, []), }); } }, }; }, }; function isDateMinusDateException(leftType, rightType, operator) { var _a, _b, _c; if (operator !== '-' && operator !== '-=') { return false; } if (((_a = leftType.symbol) === null || _a === void 0 ? void 0 : _a.name) === 'Date' && (((_b = rightType.symbol) === null || _b === void 0 ? void 0 : _b.name) === 'Date' || (rightType.flags & ts.TypeFlags.Any) > 0)) { return true; } if (((_c = rightType.symbol) === null || _c === void 0 ? void 0 : _c.name) === 'Date' && (leftType.flags & ts.TypeFlags.Any) > 0) { return true; } return false; } function checkPlus(leftType, rightType, expression, context) { if (isNumber$1(leftType) && isBooleanOrDate(rightType)) { context.report({ node: expression.right, message: toEncodedMessage$1(MESSAGE, [expression.left]), }); } if (isNumber$1(rightType) && isBooleanOrDate(leftType)) { context.report({ node: expression.left, message: toEncodedMessage$1(MESSAGE, [expression.right]), }); } } function checkComparison(leftType, rightType, expression, context) { if (isBooleanOrNumber(leftType) && isBooleanStringOrDate(rightType)) { context.report({ node: expression.right, message: toEncodedMessage$1(MESSAGE, []), }); } else if (isBooleanOrNumber(rightType) && isBooleanStringOrDate(leftType)) { context.report({ node: expression.left, message: toEncodedMessage$1(MESSAGE, []), }); } } function checkArithmetic(leftType, rightType, expression, context) { if (isDateMinusDateException(leftType, rightType, expression.operator)) { return; } const secondaryLocations = []; if (isBooleanStringOrDate(leftType)) { secondaryLocations.push(expression.left); } if (isBooleanStringOrDate(rightType)) { secondaryLocations.push(expression.right); } if (secondaryLocations.length !== 0) { context.report({ node: expression, message: toEncodedMessage$1('Convert the operands of this operation into numbers.', secondaryLocations), }); } } function isBooleanOrDate(type) { var _a; if (isBoolean(type)) { return true; } return ((_a = type.symbol) === null || _a === void 0 ? void 0 : _a.name) === 'Date'; } function isBooleanOrNumber(type) { return isBoolean(type) || isNumber$1(type); } function isBoolean(type) { var _a; return (type.flags & ts.TypeFlags.BooleanLike) > 0 || ((_a = type.symbol) === null || _a === void 0 ? void 0 : _a.name) === 'Boolean'; } function isNumber$1(type) { var _a; return (type.flags & ts.TypeFlags.NumberLike) > 0 || ((_a = type.symbol) === null || _a === void 0 ? void 0 : _a.name) === 'Number'; } function isBooleanStringOrDate(type) { var _a; return isBoolean(type) || isStringType$1(type) || ((_a = type.symbol) === null || _a === void 0 ? void 0 : _a.name) === 'Date'; } var Null; (function (Null) { Null[Null["confirmed"] = 0] = "confirmed"; Null[Null["discarded"] = 1] = "discarded"; Null[Null["unknown"] = 2] = "unknown"; })(Null || (Null = {})); function isNull(n) { return isNullLiteral(n) || isUndefined(n); } const equalOperators = ['==', '===']; const notEqualOperators = ['!=', '!==']; const rule$1l = { meta: { messages: { nullDereference: 'TypeError can be thrown as "{{symbol}}" might be null or undefined here.', shortCircuitError: 'TypeError can be thrown as expression might be null or undefined here.', }, }, create(context) { if (!isRequiredParserServices(context.sourceCode.parserServices)) { return {}; } const alreadyRaisedSymbols = new Set(); return { MemberExpression(node) { const { object, optional } = node; if (!optional) { checkNullDereference(object, context, alreadyRaisedSymbols); } }, 'LogicalExpression MemberExpression'(node) { const { object, optional } = node; if (!optional) { const ancestors = context.sourceCode.getAncestors(node); const enclosingLogicalExpression = ancestors.find(n => n.type === 'LogicalExpression'); checkLogicalNullDereference(enclosingLogicalExpression, object, context); } }, ForOfStatement(node) { const { right } = node; checkNullDereference(right, context, alreadyRaisedSymbols); }, 'Program:exit'() { alreadyRaisedSymbols.clear(); }, }; }, }; function getNullState(expr, node, context) { const { left, right } = expr; if ((isNull(right) && equivalence.areEquivalent(left, node, context.getSourceCode())) || (isNull(left) && equivalence.areEquivalent(right, node, context.getSourceCode()))) { if (notEqualOperators.includes(expr.operator)) { return Null.discarded; } if (equalOperators.includes(expr.operator)) { return Null.confirmed; } } return Null.unknown; } function checkLogicalNullDereference(expr, node, context) { if (expr.left.type === 'BinaryExpression') { const nullState = getNullState(expr.left, node, context); if ((nullState === Null.confirmed && expr.operator === '&&') || (nullState === Null.discarded && expr.operator === '||')) { context.report({ messageId: 'shortCircuitError', node, }); } } } function isWrittenInInnerFunction(symbol, fn) { return symbol.references.some(ref => { if (ref.isWrite() && ref.identifier.hasOwnProperty('parent')) { const enclosingFn = findFirstMatchingAncestor(ref.identifier, node => functionLike$1.has(node.type)); return enclosingFn && enclosingFn !== fn; } return false; }); } function checkNullDereference(node, context, alreadyRaisedSymbols) { var _a; if (node.type !== 'Identifier') { return; } const scope = context.sourceCode.getScope(node); const symbol = (_a = scope.references.find(v => v.identifier === node)) === null || _a === void 0 ? void 0 : _a.resolved; if (!symbol) { return; } const enclosingFunction = context.sourceCode .getAncestors(node) .find(n => functionLike$1.has(n.type)); if (!alreadyRaisedSymbols.has(symbol) && !isWrittenInInnerFunction(symbol, enclosingFunction) && isUndefinedOrNull(node, context.sourceCode.parserServices)) { alreadyRaisedSymbols.add(symbol); context.report({ messageId: 'nullDereference', data: { symbol: node.name, }, node, }); } } const rule$1k = { meta: { messages: { addContent: 'Add an accessible content to this "" tag.', }, }, create(context) { const elementType = getElementType(context); function hasVisibleChildren(children) { return children.some((child) => { switch (child.type) { case 'JSXText': return !!child.value.trim(); case 'JSXFragment': return hasVisibleChildren(child.children); case 'JSXElement': return !isHiddenFromScreenReader(elementType(child.openingElement), child.openingElement.attributes); case 'JSXExpressionContainer': if (child.expression.type === 'Identifier') { return child.expression.name !== 'undefined'; } return child.expression.type !== 'JSXEmptyExpression'; default: return false; } }); } return { JSXElement(node) { const jsxNode = node; const type = elementType(jsxNode.openingElement); if (type.toLowerCase() !== 'object') { return; } if (!hasVisibleChildren(jsxNode.children)) { context.report({ node, messageId: 'addContent', }); } }, }; }, }; function decorate$b(rule) { return interceptReport(rule, reportExempting$1(isAuraLightningComponent)); } function reportExempting$1(exemptionCondition) { return (context, reportDescriptor) => { if ('node' in reportDescriptor) { const property = reportDescriptor['node']; if (!exemptionCondition(property)) { context.report({ ...reportDescriptor, node: property.key }); } } }; } function isAuraLightningComponent(property) { const { parent, value } = property; return (parent.parent.type === 'ExpressionStatement' && parent.parent.parent.type === 'Program' && value.type === 'FunctionExpression'); } const rule$1j = decorate$b(eslintRules['object-shorthand']); const BINARY_OPERATORS = ['/', '*', '%', '-', '-=', '*=', '/=', '%=']; const UNARY_OPERATORS = ['++', '--', '+', '-']; const rule$1i = { meta: { messages: { noEvaluatedNaN: 'Change the expression which uses this operand so that it can\'t evaluate to "NaN" (Not a Number).', }, }, create(context) { const services = context.sourceCode.parserServices; if (!isRequiredParserServices(services)) { return {}; } function isObjectType(...types) { return types.some(t => { var _a; return !!(t.getFlags() & ts.TypeFlags.Object) && !isDate(t) && ((_a = t.symbol) === null || _a === void 0 ? void 0 : _a.name) !== 'Number'; }); } function isDate(type) { const { typeToString } = services.program.getTypeChecker(); return typeToString(type) === 'Date'; } return { 'BinaryExpression, AssignmentExpression': (node) => { const expression = node; if (!BINARY_OPERATORS.includes(expression.operator)) { return; } const leftType = getTypeFromTreeNode$1(expression.left, services); const rightType = getTypeFromTreeNode$1(expression.right, services); if (isObjectType(leftType)) { context.report({ node: expression.left, messageId: 'noEvaluatedNaN' }); } if (isObjectType(rightType)) { context.report({ node: expression.right, messageId: 'noEvaluatedNaN' }); } }, 'UnaryExpression, UpdateExpression': (node) => { const expr = node; if (!UNARY_OPERATORS.includes(expr.operator)) { return; } const argType = getTypeFromTreeNode$1(expr.argument, services); if (isObjectType(argType)) { context.report({ node, messageId: 'noEvaluatedNaN' }); } }, }; }, }; const EXEC_FUNCTIONS = ['exec', 'execSync']; const SPAWN_EXEC_FILE_FUNCTIONS = ['spawn', 'spawnSync', 'execFile', 'execFileSync']; const CHILD_PROCESS_MODULE = 'child_process'; const rule$1h = { meta: { messages: { safeOSCommand: 'Make sure that executing this OS command is safe here.', }, }, create(context) { return { CallExpression: (node) => checkOSCommand(context, node), }; }, }; function checkOSCommand(context, call) { const { callee, arguments: args } = call; const fqn = getFullyQualifiedName(context, call); if (!fqn) { return; } const [module, method] = fqn.split('.'); if (module === CHILD_PROCESS_MODULE && isQuestionable$1(method, args)) { context.report({ node: callee, messageId: 'safeOSCommand', }); } } function isQuestionable$1(method, [command, ...otherArguments]) { if (!command || isLiteral$2(command) || isStaticTemplateLiteral(command)) { return false; } if (SPAWN_EXEC_FILE_FUNCTIONS.includes(method)) { return containsShellOption(otherArguments); } return EXEC_FUNCTIONS.includes(method); } function containsShellOption(otherArguments) { return otherArguments.some(arg => arg.type === 'ObjectExpression' && arg.properties.filter(v => v.type === 'Property').some(({ key, value }) => isIdentifier(key, 'shell') && value.type === 'Literal' && value.value === true)); } const POST_MESSAGE = 'postMessage'; const ADD_EVENT_LISTENER = 'addEventListener'; const rule$1g = { meta: { messages: { specifyTarget: `Specify a target origin for this message.`, verifyOrigin: `Verify the origin of the received message.`, }, }, create(context) { const services = context.sourceCode.parserServices; if (!isRequiredParserServices(services)) { return {}; } return { [`CallExpression:matches([callee.name="${POST_MESSAGE}"], [callee.property.name="${POST_MESSAGE}"])`]: (node) => { checkPostMessageCall(node, context); }, [`CallExpression[callee.property.name="${ADD_EVENT_LISTENER}"]`]: (node) => { checkAddEventListenerCall(node, context); }, }; }, }; function isWindowObject(node, context) { const type = getTypeAsString(node, context.sourceCode.parserServices); const hasWindowName = WindowNameVisitor.containsWindowName(node, context); return type.match(/window/i) || type.match(/globalThis/i) || hasWindowName; } function checkPostMessageCall(callExpr, context) { var _a; const { callee } = callExpr; if (![2, 3].includes(callExpr.arguments.length) || ((_a = getValueOfExpression(context, callExpr.arguments[1], 'Literal')) === null || _a === void 0 ? void 0 : _a.value) !== '*') { return; } if (callee.type === 'Identifier') { context.report({ node: callee, messageId: 'specifyTarget', }); } if (callee.type !== 'MemberExpression') { return; } if (isWindowObject(callee.object, context)) { context.report({ node: callee, messageId: 'specifyTarget', }); } } function checkAddEventListenerCall(callExpr, context) { const { callee, arguments: args } = callExpr; if (!isWindowObject(callee, context) || args.length < 2 || !isMessageTypeEvent(args[0], context)) { return; } let listener = resolveFunction(context, args[1]); if ((listener === null || listener === void 0 ? void 0 : listener.body.type) === 'CallExpression') { listener = resolveFunction(context, listener.body); } if (!listener || listener.params.length === 0) { return; } const event = listener.params[0]; if (event.type !== 'Identifier') { return; } if (!hasVerifiedOrigin(context, listener, event)) { context.report({ node: callee, messageId: 'verifyOrigin', }); } } function hasVerifiedOrigin(context, listener, event) { const scope = context.sourceCode.scopeManager.acquire(listener); const eventVariable = scope === null || scope === void 0 ? void 0 : scope.variables.find(v => v.name === event.name); if (eventVariable) { const eventIdentifiers = eventVariable.references.map(e => e.identifier); for (const reference of eventVariable.references) { const eventRef = reference.identifier; if (isEventOriginCompared(eventRef) || isEventOriginalEventCompared(eventRef)) { return true; } const unionEvent = findUnionEvent(eventRef, eventIdentifiers); if (unionEvent !== null && isReferenceCompared(scope, unionEvent)) { return true; } const unionOrigin = findUnionOrigin(eventRef, eventIdentifiers); if (unionOrigin !== null && isEventOriginReferenceCompared(scope, unionOrigin)) { return true; } } } return false; function findUnionEvent(event, eventIdentifiers) { const logicalExpr = event.parent; if ((logicalExpr === null || logicalExpr === void 0 ? void 0 : logicalExpr.type) !== 'LogicalExpression') { return null; } if ((logicalExpr.left === event && isEventOriginalEvent(logicalExpr.right, eventIdentifiers)) || (logicalExpr.right === event && isEventOriginalEvent(logicalExpr.left, eventIdentifiers))) { return extractVariableDeclaratorIfExists(logicalExpr); } return null; } function findUnionOrigin(eventRef, eventIdentifiers) { var _a; const memberExpr = eventRef.parent; if (!((memberExpr === null || memberExpr === void 0 ? void 0 : memberExpr.type) === 'MemberExpression' && ((_a = memberExpr.parent) === null || _a === void 0 ? void 0 : _a.type) === 'LogicalExpression')) { return null; } const logicalExpr = memberExpr.parent; if (!(logicalExpr.left === memberExpr && isEventOriginalEventOrigin(logicalExpr.right, eventIdentifiers)) && !(logicalExpr.right === memberExpr && isEventOriginalEventOrigin(logicalExpr.left, eventIdentifiers))) { return null; } return extractVariableDeclaratorIfExists(logicalExpr); function isEventOriginalEventOrigin(memberExpr, eventIdentifiers) { const subMemberExpr = memberExpr.object; if ((subMemberExpr === null || subMemberExpr === void 0 ? void 0 : subMemberExpr.type) !== 'MemberExpression') { return false; } const isOrigin = memberExpr.property.type === 'Identifier' && memberExpr.property.name === 'origin'; return isEventOriginalEvent(subMemberExpr, eventIdentifiers) && isOrigin; } } } function isReferenceCompared(scope, identifier) { function getGrandParent(node) { var _a; return (_a = node === null || node === void 0 ? void 0 : node.parent) === null || _a === void 0 ? void 0 : _a.parent; } return checkReference(scope, identifier, getGrandParent); } function isEventOriginReferenceCompared(scope, identifier) { function getParent(node) { return node === null || node === void 0 ? void 0 : node.parent; } return checkReference(scope, identifier, getParent); } function checkReference(scope, identifier, callback) { const identifierVariable = scope === null || scope === void 0 ? void 0 : scope.variables.find(v => v.name === identifier.name); if (!identifierVariable) { return false; } for (const reference of identifierVariable.references) { const binaryExpressionCandidate = callback(reference.identifier); if (isInIfStatement(binaryExpressionCandidate)) { return true; } } return false; } function isEventOriginalEvent(memberExpr, eventIdentifiers) { const isEvent = memberExpr.object.type === 'Identifier' && eventIdentifiers.includes(memberExpr.object); const isOriginalEvent = memberExpr.property.type === 'Identifier' && memberExpr.property.name === 'originalEvent'; return isEvent && isOriginalEvent; } function extractVariableDeclaratorIfExists(node) { var _a; if (((_a = node.parent) === null || _a === void 0 ? void 0 : _a.type) !== 'VariableDeclarator') { return null; } return node.parent.id; } function isEventOriginCompared(event) { const memberExpr = findEventOrigin(event); return isInIfStatement(memberExpr); } function isEventOriginalEventCompared(event) { const eventOriginalEvent = findEventOriginalEvent(event); if (!(eventOriginalEvent === null || eventOriginalEvent === void 0 ? void 0 : eventOriginalEvent.parent)) { return false; } if (!isPropertyOrigin(eventOriginalEvent.parent)) { return false; } return isInIfStatement(eventOriginalEvent); } function findEventOrigin(event) { const parent = event.parent; if ((parent === null || parent === void 0 ? void 0 : parent.type) !== 'MemberExpression') { return null; } if (isPropertyOrigin(parent)) { return parent; } else { return null; } } function isPropertyOrigin(node) { return isIdentifier(node.property, 'origin'); } function findEventOriginalEvent(event) { const memberExpr = event.parent; if ((memberExpr === null || memberExpr === void 0 ? void 0 : memberExpr.type) !== 'MemberExpression') { return null; } const { object: eventCandidate, property: originalEventIdentifierCandidate } = memberExpr; if (eventCandidate === event && isIdentifier(originalEventIdentifierCandidate, 'originalEvent')) { return memberExpr; } return null; } function isInIfStatement(node) { if (node == null) { return false; } return findFirstMatchingLocalAncestor(node, nodes.isIfStatement) != null; } function isMessageTypeEvent(eventNode, context) { const eventValue = getValueOfExpression(context, eventNode, 'Literal'); return typeof (eventValue === null || eventValue === void 0 ? void 0 : eventValue.value) === 'string' && eventValue.value.toLowerCase() === 'message'; } class WindowNameVisitor { constructor() { this.hasWindowName = false; } static containsWindowName(node, context) { const visitor = new WindowNameVisitor(); visitor.visit(node, context); return visitor.hasWindowName; } visit(root, context) { const visitNode = (node) => { if (node.type === 'Identifier' && node.name.match(/window/i)) { this.hasWindowName = true; } childrenOf$1(node, context.sourceCode.visitorKeys).forEach(visitNode); }; visitNode(root); } } const rule$1f = { meta: { messages: { defaultLast: 'Move this "default" clause to the end of this "switch" statement.', }, }, create(context) { const sourceCode = context.sourceCode; return { SwitchStatement(node) { const cases = node.cases; const defaultPosition = cases.findIndex(c => c.test === null); if (defaultPosition >= 0 && defaultPosition !== cases.length - 1) { context.report({ messageId: 'defaultLast', loc: sourceCode.getFirstToken(cases[defaultPosition]).loc, }); } }, }; }, }; function decorate$a(rule) { rule.meta.hasSuggestions = true; return interceptReport(rule, (context, descriptor) => { const enumMember = descriptor.node; const enumDecl = enumMember.parent; if (anyInitialized(enumDecl) && !numericalOrder(enumDecl)) { context.report(descriptor); } }); } function anyInitialized(enumDecl) { return enumDecl.members.some(m => m.initializer !== undefined); } function numericalOrder(enumDecl) { var _a; const firstMember = enumDecl.members[0]; const membersRest = enumDecl.members.slice(1); return (((_a = firstMember.initializer) === null || _a === void 0 ? void 0 : _a.type) === 'Literal' && isNumberLiteral(firstMember.initializer) && membersRest.every(m => m.initializer === undefined)); } const rule$1e = decorate$a(tsEslintRules['prefer-enum-initializers']); const element = 'element'; function decorate$9(rule) { rule.meta.hasSuggestions = true; return interceptReport(rule, (context, reportDescriptor) => { const forStmt = reportDescriptor.node; const suggest = []; if (isFixable(context.sourceCode.getScope(forStmt))) { suggest.push({ desc: 'Replace with "for of" loop', fix: fixer => rewriteForStatement(forStmt, context, fixer), }); } context.report({ ...reportDescriptor, suggest, }); }); } function isFixable(scope) { return (scope.references.every(reference => reference.identifier.name !== element) && scope.childScopes.every(isFixable)); } function rewriteForStatement(forStmt, context, fixer) { const fixes = []; const openingParenthesis = context.sourceCode.getFirstToken(forStmt, token => token.value === '('); const closingParenthesis = context.sourceCode.getTokenBefore(forStmt.body, token => token.value === ')'); const arrayExpr = extractArrayExpression(forStmt); const arrayText = context.sourceCode.getText(arrayExpr); const headerRange = [openingParenthesis.range[1], closingParenthesis.range[0]]; const headerText = `const ${element} of ${arrayText}`; fixes.push(fixer.replaceTextRange(headerRange, headerText)); const [indexVar] = context.sourceCode.getDeclaredVariables(forStmt.init); for (const reference of indexVar.references) { const id = reference.identifier; if (contains(forStmt.body, id)) { const arrayAccess = id.parent; fixes.push(fixer.replaceText(arrayAccess, element)); } } return fixes; } function extractArrayExpression(forStmt) { return forStmt.test.right.object; } function contains(outer, inner) { return outer.range[0] <= inner.range[0] && outer.range[1] >= inner.range[1]; } const rule$1d = decorate$9(tsEslintRules['prefer-for-of']); function decorate$8(rule) { rule.meta.messages['functionTypeOverCallableType'] = '{{ literalOrInterface }} has only a call signature, you should use a function type instead.'; return interceptReport(rule, (context, reportDescriptor) => { context.report({ ...reportDescriptor, }); }); } const rule$1c = decorate$8(tsEslintRules['prefer-function-type']); function decorate$7(rule) { return interceptReport(rule, (context, descriptor) => { const { node } = descriptor; const moduleKeyword = context.sourceCode.getFirstToken(node, token => token.value === 'module'); if (moduleKeyword === null || moduleKeyword === void 0 ? void 0 : moduleKeyword.loc) { context.report({ ...descriptor, loc: moduleKeyword.loc }); } else { context.report(descriptor); } }); } const rule$1b = decorate$7(tsEslintRules['prefer-namespace-keyword']); const preferNullishCoalescingRule = tsEslintRules['prefer-nullish-coalescing']; const rule$1a = interceptReport(preferNullishCoalescingRule, (context, reportDescriptor) => { const { node: token, messageId } = reportDescriptor; if (messageId === 'preferNullishOverOr') { const services = context.sourceCode.parserServices; const rangeIndex = token.range[0]; const node = context.sourceCode.getNodeByRangeIndex(rangeIndex); const leftOperand = node.left; const leftOperandType = getTypeFromTreeNode$1(leftOperand, services); if (leftOperandType.isUnion() && leftOperandType.types.some(isNullOrUndefinedType) && (leftOperandType.types.some(isBooleanType) || leftOperandType.types.some(isObjectType))) { return; } } context.report(reportDescriptor); }); function decorate$6(rule) { return interceptReport(rule, (context, reportDescriptor) => { if ('node' in reportDescriptor) { const { node, ...rest } = reportDescriptor; const call = node; context.report({ node: call.callee, ...rest, }); } }); } const decorated = decorate$6(eslintRules['prefer-object-spread']); const rule$19 = { meta: decorated.meta, create(context) { if (!isSupported(context.filename, { node: '8.3.0' })) { return {}; } return decorated.create(context); }, }; const rule$18 = { meta: { hasSuggestions: true, messages: { promiseAction: 'Replace this trivial promise with "Promise.{{action}}".', suggestPromiseAction: 'Replace with "Promise.{{action}}"', }, }, create(context) { return { NewExpression: (node) => { const newExpr = node; const executor = getPromiseExecutor(newExpr, context); if (executor) { checkExecutor(newExpr, executor, context); } }, }; }, }; function getPromiseExecutor(node, context) { if (node.callee.type === 'Identifier' && context.sourceCode.getText(node.callee) === 'Promise' && node.arguments.length === 1) { return node.arguments[0]; } return undefined; } function checkExecutor(newExpr, executor, context) { if (!isFunctionNode(executor)) { return; } const { params, body } = executor; const [resolveParameterDeclaration, rejectParameterDeclaration] = params; const resolveParameterName = getParameterName(resolveParameterDeclaration); const rejectParameterName = getParameterName(rejectParameterDeclaration); const bodyExpression = getOnlyBodyExpression(body); if (bodyExpression && bodyExpression.type === 'CallExpression') { const { callee, arguments: args } = bodyExpression; if (callee.type === 'Identifier') { const action = getPromiseAction(callee.name, resolveParameterName, rejectParameterName); if (action && args.length === 1) { context.report({ messageId: 'promiseAction', data: { action, }, node: newExpr.callee, suggest: [ { messageId: 'suggestPromiseAction', data: { action, }, fix: fixer => { const argText = context.sourceCode.getText(args[0]); return fixer.replaceText(newExpr, `Promise.${action}(${argText})`); }, }, ], }); } } } } function getOnlyBodyExpression(node) { let bodyExpression; if (node.type === 'BlockStatement') { if (node.body.length === 1) { const statement = node.body[0]; if (statement.type === 'ExpressionStatement') { bodyExpression = statement.expression; } } } else { bodyExpression = node; } return bodyExpression; } function getPromiseAction(callee, resolveParameterName, rejectParameterName) { switch (callee) { case resolveParameterName: return 'resolve'; case rejectParameterName: return 'reject'; default: return undefined; } } function getParameterName(node) { return node && node.type === 'Identifier' ? node.name : undefined; } function decorate$5(rule) { rule.meta.hasSuggestions = true; return interceptReport(rule, (context, reportDescriptor) => { const suggest = []; const node = reportDescriptor.node; if (node.type === 'CallExpression' && node.callee.type === 'MemberExpression' && node.arguments.length === 2) { const { callee: { object, property }, arguments: [, args], } = node; if (property.type === 'Identifier' && property.name === 'apply' && object.range && args.range) { const range = [object.range[1], args.range[0]]; suggest.push({ desc: 'Replace apply() with spread syntax', fix: fixer => fixer.replaceTextRange(range, '(...'), }); } } context.report({ ...reportDescriptor, suggest }); }); } const rule$17 = decorate$5(eslintRules['prefer-spread']); function decorate$4(rule) { rule.meta.hasSuggestions = true; return interceptReport(rule, (context, descriptor) => { const { fix, messageId } = descriptor; const suggest = [ { messageId, fix, }, ]; delete descriptor['fix']; context.report({ ...descriptor, suggest }); }); } const rule$16 = decorate$4(tsEslintRules['prefer-string-starts-ends-with']); function decorate$3(rule) { return interceptReport(rule, reportExempting(isTwoOperands)); } function reportExempting(exemptionCondition) { return (context, reportDescriptor) => { if ('node' in reportDescriptor) { const expr = reportDescriptor['node']; if (!exemptionCondition(expr)) { context.report(reportDescriptor); } } }; } function isTwoOperands(node) { return node.right.type !== 'BinaryExpression' && node.left.type !== 'BinaryExpression'; } const rule$15 = decorate$3(eslintRules['prefer-template']); const rule$14 = { meta: { hasSuggestions: true, messages: { useTypePredicate: 'Declare this function return type using type predicate "{{castedExpressionText}} is {{castedTypeText}}".', suggestTypePredicate: 'Use type predicate', }, }, create(context) { return { "MethodDefinition[kind='method'] FunctionExpression"(node) { checkFunctionLikeDeclaration(node, context); }, FunctionDeclaration(node) { checkFunctionLikeDeclaration(node, context); }, }; }, }; function checkFunctionLikeDeclaration(functionDeclaration, context) { if (functionDeclaration.returnType && functionDeclaration.returnType.typeAnnotation.type === 'TSTypePredicate') { return; } const body = functionDeclaration.body; const returnedExpression = getReturnedExpression(body); if (!returnedExpression) { return; } if (isInequalityBinaryExpression(returnedExpression)) { const { left, right } = returnedExpression; if (isUndefined(right)) { checkCastedType(functionDeclaration, left, context); } else if (isUndefined(left)) { checkCastedType(functionDeclaration, right, context); } } else if (isBooleanCall(returnedExpression)) { checkCastedType(functionDeclaration, returnedExpression.arguments[0], context); } else if (isNegation(returnedExpression) && isNegation(returnedExpression.argument)) { checkCastedType(functionDeclaration, returnedExpression.argument.argument, context); } } function getReturnedExpression(block) { if (block && block.body.length === 1) { const statement = block.body[0]; if (statement.type === 'ReturnStatement') { return statement.argument; } } return undefined; } function isInequalityBinaryExpression(returnExpression) { return (returnExpression.type === 'BinaryExpression' && (returnExpression.operator === '!==' || returnExpression.operator === '!=')); } function checkCastedType(node, expression, context) { const sourceCode = context.sourceCode; const castedType = getCastTupleFromMemberExpression(expression); if (castedType && castedType[1].type !== 'TSAnyKeyword') { const nOfParam = node.params.length; if (nOfParam === 1 || (nOfParam === 0 && castedType[0].type === 'ThisExpression')) { const castedExpressionText = sourceCode.getText(castedType[0]); const castedTypeText = sourceCode.getText(castedType[1]); const predicate = `: ${castedExpressionText} is ${castedTypeText}`; const suggest = getTypePredicateSuggestion(node, context, predicate); context.report({ messageId: 'useTypePredicate', data: { castedExpressionText, castedTypeText, }, loc: locations.getMainFunctionTokenLocation(node, getParent(context, node), context), suggest, }); } } } function getTypePredicateSuggestion(node, context, predicate) { const suggestions = []; let fix; if (node.returnType) { fix = fixer => fixer.replaceText(node.returnType, predicate); } else { const closingParenthesis = context.sourceCode.getTokenBefore(node.body, token => token.value === ')'); fix = fixer => fixer.insertTextAfter(closingParenthesis, predicate); } suggestions.push({ messageId: 'suggestTypePredicate', fix }); return suggestions; } function getCastTupleFromMemberExpression(node) { if (node.type === 'MemberExpression') { const object = node.object; if (object.type === 'TSAsExpression' || object.type === 'TSTypeAssertion') { return [object.expression, object.typeAnnotation]; } } return undefined; } function isNegation(node) { return node.type === 'UnaryExpression' && node.prefix && node.operator === '!'; } function isBooleanCall(node) { if (node.type === 'CallExpression') { const callee = node.callee; return node.arguments.length === 1 && callee.type === 'Identifier' && callee.name === 'Boolean'; } return false; } const rule$13 = { meta: { messages: { safeArg: `Make sure that command line arguments are used safely here.`, }, }, create(context) { return { MemberExpression(node) { if (isMemberExpression(node, 'process', 'argv')) { context.report({ messageId: 'safeArg', node, }); } }, }; }, }; const ERRORHANDLER_MODULE = 'errorhandler'; const rule$12 = { meta: { messages: { deactivateDebug: 'Make sure this debug feature is deactivated before delivering the code in production.', }, }, create(context) { return { CallExpression(node) { const callExpression = node; checkErrorHandlerMiddleware(context, callExpression); }, }; }, }; function checkErrorHandlerMiddleware(context, callExpression) { const { callee, arguments: args } = callExpression; if (isMemberWithProperty$1(callee, 'use') && args.length > 0 && !isInsideConditional(context, callExpression)) { for (const m of flattenArgs(context, args)) { const middleware = getUniqueWriteUsageOrNode(context, m); if (middleware.type === 'CallExpression' && getFullyQualifiedName(context, middleware) === ERRORHANDLER_MODULE) { context.report({ node: middleware, messageId: 'deactivateDebug', }); } } } } function isInsideConditional(context, node) { const ancestors = context.sourceCode.getAncestors(node); return ancestors.some(ancestor => ancestor.type === 'IfStatement'); } const rule$11 = { meta: { messages: { safeGenerator: 'Make sure that using this pseudorandom number generator is safe here.', }, }, create(context) { return { CallExpression(node) { const fqn = getFullyQualifiedName(context, node); if (fqn === 'Math.random') { context.report({ messageId: 'safeGenerator', node, }); } }, }; }, }; const rule$10 = { meta: { hasSuggestions: true, messages: { message: `Make this public static property readonly.`, fix: 'Add "readonly" keyword', }, }, create(context) { return { 'PropertyDefinition[readonly!=true][static=true][accessibility!="private"][accessibility!="protected"]'(node) { context.report({ messageId: 'message', node: node.key, suggest: [ { fix: fixer => { const tokens = context.sourceCode.getTokens(node); const staticToken = tokens.find(t => t.value === 'static'); return fixer.insertTextAfter(staticToken, ' readonly'); }, messageId: 'fix', }, ], }); }, }; }, }; const UNIX_DIRECTORIES = [ '/tmp/', '/var/tmp/', '/usr/tmp/', '/dev/shm/', '/dev/mqueue/', '/run/lock/', '/var/run/lock/', '/library/caches/', '/users/shared/', '/private/tmp/', '/private/var/tmp/', ].map(v => new RegExp(`^${v}`, 'i')); const WINDOWS_DIRECTORIES_PATTERN = new RegExp('^[^\\\\]*(\\\\){1,2}(Windows(\\\\){1,2}Temp|Temp|TMP)(\\\\.*|$)', 'i'); const SENSITIVE_ENV_VARIABLES = ['TMPDIR', 'TMP', 'TEMPDIR', 'TEMP']; const rule$$ = { meta: { messages: { safeDirectory: 'Make sure publicly writable directories are used safely here.', }, }, create(context) { return { Literal: (node) => { var _a; const literal = node; const value = (_a = literal.raw) === null || _a === void 0 ? void 0 : _a.slice(1, literal.raw.length - 1); if (value && (UNIX_DIRECTORIES.find(i => value.match(i)) || value.match(WINDOWS_DIRECTORIES_PATTERN))) { context.report({ node: literal, messageId: 'safeDirectory', }); } }, MemberExpression: (node) => { const memberExpression = node; const { object, property } = memberExpression; if (property.type !== 'Identifier' || !SENSITIVE_ENV_VARIABLES.includes(property.name) || object.type !== 'MemberExpression') { return; } if (object.property.type === 'Identifier' && object.property.name === 'env' && object.object.type === 'Identifier' && object.object.name === 'process') { context.report({ node: memberExpression, messageId: 'safeDirectory' }); } }, }; }, }; const rule$_ = { meta: { messages: { message: 'Add an initial value to this "reduce()" call.', }, }, create(context) { const services = context.sourceCode.parserServices; function isArray$1(node) { if (isRequiredParserServices(services)) { return isArray(node, services); } else { return isArrayExpression(getUniqueWriteUsageOrNode(context, node)); } } return { CallExpression(node) { if (isCallingMethod(node, 1, 'reduce') && isArray$1(node.callee.object)) { context.report({ node: node.callee.property, messageId: 'message', }); } }, }; }, }; const COMMON_NODE_TYPES = new Set([ 'TSAnyKeyword', 'TSBigIntKeyword', 'TSBooleanKeyword', 'TSNeverKeyword', 'TSNullKeyword', 'TSNumberKeyword', 'TSStringKeyword', 'TSSymbolKeyword', 'TSUndefinedKeyword', 'TSUnknownKeyword', 'TSVoidKeyword', ]); const rule$Z = { meta: { messages: { redundantTypeAlias: 'Remove this redundant type alias and replace its occurrences with "{{type}}".', }, }, create(context) { return { TSTypeAliasDeclaration(node) { const { id, typeAnnotation } = node; if (COMMON_NODE_TYPES.has(typeAnnotation.type) || isTypeAlias(typeAnnotation, context)) { const sourceCode = context.sourceCode; const tpe = sourceCode.getTokens(typeAnnotation)[0]; context.report({ messageId: 'redundantTypeAlias', node: id, data: { type: tpe.value, }, }); } }, }; }, }; const DEFAULT_THESHOLD = 20; const rule$Y = { meta: { schema: [ { type: 'object', properties: { threshold: { type: 'integer', }, }, }, { type: 'string', enum: [SONAR_RUNTIME], }, ], }, create(context) { const options = context.options; const threshold = options.length > 0 ? options[0].threshold : DEFAULT_THESHOLD; const services = context.sourceCode.parserServices; const regexNodes = []; return { 'Literal[regex]:exit': (node) => { regexNodes.push(node); }, 'NewExpression:exit': (node) => { if (isRegExpConstructor(node)) { regexNodes.push(node); } }, 'CallExpression:exit': (node) => { const callExpr = node; if (isRequiredParserServices(services) && isStringRegexMethodCall(callExpr, services)) { regexNodes.push(callExpr.arguments[0]); } else if (isRegExpConstructor(callExpr)) { regexNodes.push(callExpr); } }, 'Program:exit': () => { regexNodes.forEach(regexNode => checkRegexComplexity(regexNode, threshold, context)); }, }; }, }; function checkRegexComplexity(regexNode, threshold, context) { for (const regexParts of findRegexParts(regexNode, context)) { let complexity = 0; const secondaryLocations = []; const secondaryMessages = []; for (const regexPart of regexParts) { const calculator = new ComplexityCalculator(regexPart, context); calculator.visit(); calculator.components.forEach(component => { secondaryLocations.push(component.location); secondaryMessages.push(component.message); }); complexity += calculator.complexity; } if (complexity > threshold) { context.report({ message: toEncodedMessage$1(`Simplify this regular expression to reduce its complexity from ${complexity} to the ${threshold} allowed.`, secondaryLocations, secondaryMessages, complexity - threshold), node: regexParts[0], }); } } } function findRegexParts(node, context) { const finder = new RegexPartFinder(context); finder.find(node); return finder.parts; } class RegexPartFinder { constructor(context) { this.context = context; this.parts = []; this.handledIdentifiers = []; } find(node) { if (isRegExpConstructor(node)) { this.find(node.arguments[0]); } else if (isRegexLiteral(node)) { this.parts.push([node]); } else if (isStringLiteral(node)) { this.parts.push([node]); } else if (isStaticTemplateLiteral(node)) { this.parts.push([node]); } else if (isIdentifier(node)) { if (!this.handledIdentifiers.includes(node)) { this.handledIdentifiers.push(node); const initializer = getUniqueWriteUsage(this.context, node.name, node); if (initializer) { this.find(initializer); } } } else if (isBinaryPlus(node)) { const literals = []; this.findInStringConcatenation(node.left, literals); this.findInStringConcatenation(node.right, literals); if (literals.length > 0) { this.parts.push(literals); } } } findInStringConcatenation(node, literals) { if (isStringLiteral(node)) { literals.push(node); } else if (isBinaryPlus(node)) { this.findInStringConcatenation(node.left, literals); this.findInStringConcatenation(node.right, literals); } else { this.find(node); } } } class ComplexityCalculator { constructor(regexPart, context) { this.regexPart = regexPart; this.context = context; this.nesting = 1; this.complexity = 0; this.components = []; this.regexPartAST = getParsedRegex(regexPart, context); } visit() { if (!this.regexPartAST) { return; } regexpp__namespace.visitRegExpAST(this.regexPartAST, { onAssertionEnter: (node) => { if (node.kind === 'lookahead' || node.kind === 'lookbehind') { const [start, end] = getRegexpRange(this.regexPart, node); this.increaseComplexity(this.nesting, node, [ 0, -(end - start - 1) + (node.kind === 'lookahead' ? '?='.length : '?<='.length), ]); this.nesting++; this.onDisjunctionEnter(node); } }, onAssertionLeave: (node) => { if (node.kind === 'lookahead' || node.kind === 'lookbehind') { this.onDisjunctionLeave(node); this.nesting--; } }, onBackreferenceEnter: (node) => { this.increaseComplexity(1, node); }, onCapturingGroupEnter: (node) => { this.onDisjunctionEnter(node); }, onCapturingGroupLeave: (node) => { this.onDisjunctionLeave(node); }, onCharacterClassEnter: (node) => { const [start, end] = getRegexpRange(this.regexPart, node); this.increaseComplexity(1, node, [0, -(end - start - 1)]); this.nesting++; }, onCharacterClassLeave: (_node) => { this.nesting--; }, onGroupEnter: (node) => { this.onDisjunctionEnter(node); }, onGroupLeave: (node) => { this.onDisjunctionLeave(node); }, onPatternEnter: (node) => { this.onDisjunctionEnter(node); }, onPatternLeave: (node) => { this.onDisjunctionLeave(node); }, onQuantifierEnter: (node) => { const [start] = getRegexpRange(this.regexPart, node); const [, end] = getRegexpRange(this.regexPart, node.element); this.increaseComplexity(this.nesting, node, [end - start, 0]); this.nesting++; }, onQuantifierLeave: (_node) => { this.nesting--; }, }); } increaseComplexity(increment, node, offset) { this.complexity += increment; let message = '+' + increment; if (increment > 1) { message += ` (incl ${increment - 1} for nesting)`; } const loc = getRegexpLocation(this.regexPart, node, this.context, offset); if (loc) { this.components.push({ location: { loc, }, message, }); } } onDisjunctionEnter(node) { if (node.alternatives.length > 1) { let { alternatives } = node; let increment = this.nesting; while (alternatives.length > 1) { const [start, end] = getRegexpRange(this.regexPart, alternatives[1]); this.increaseComplexity(increment, alternatives[1], [-1, -(end - start)]); increment = 1; alternatives = alternatives.slice(1); } this.nesting++; } } onDisjunctionLeave(node) { if (node.alternatives.length > 1) { this.nesting--; } } } const stringMethods = ['match', 'search', 'split']; const minPatternLength = 3; const specialChars = ['+', '*', '{']; const rule$X = { meta: { messages: { safeRegex: 'Make sure that using a regular expression is safe here.', }, }, create(context) { return { Literal(node) { const { regex } = node; if (regex) { const { pattern } = regex; if (isUnsafeRegexLiteral(pattern)) { context.report({ messageId: 'safeRegex', node, }); } } }, CallExpression(node) { const { callee, arguments: args } = node; if (isMemberWithProperty$1(callee, ...stringMethods)) { checkFirstArgument(args, context); } }, NewExpression(node) { const { callee, arguments: args } = node; if (isIdentifier(callee, 'RegExp')) { checkFirstArgument(args, context); } }, }; }, }; function checkFirstArgument(args, context) { const firstArg = args[0]; if (firstArg && firstArg.type === 'Literal' && typeof firstArg.value === 'string' && isUnsafeRegexLiteral(firstArg.value)) { context.report({ messageId: 'safeRegex', node: firstArg, }); } } function isUnsafeRegexLiteral(value) { return value.length >= minPatternLength && hasEnoughNumberOfSpecialChars(value); } function hasEnoughNumberOfSpecialChars(value) { let numberOfSpecialChars = 0; for (const c of value) { if (specialChars.includes(c)) { numberOfSpecialChars++; } if (numberOfSpecialChars === 2) { return true; } } return false; } const rulesOfHooks = reactHooks.rules['rules-of-hooks']; const rule$W = { meta: rulesOfHooks.meta, create(context) { function overrideContext(overrides) { Object.setPrototypeOf(overrides, context); return overrides; } let isReact = false; const detectReactListener = rule$4E.create(overrideContext({ report(_descriptor) { isReact = true; }, })); const rulesOfHooksListener = rulesOfHooks.create(overrideContext({ report(descriptor) { if (isReact) { context.report(descriptor); } }, })); return mergeRules(detectReactListener, rulesOfHooksListener); }, }; function decorate$2(rule) { return interceptReport(rule, fixLocation); } function fixLocation(context, reportDescriptor) { var _a; const report = reportDescriptor; if (((_a = report.loc) === null || _a === void 0 ? void 0 : _a.start) && report.messageId === 'missingSemi') { report.loc = report.loc.start; } context.report(reportDescriptor); } const rule$V = decorate$2(tsEslintRules['semi']); const rule$U = { meta: { messages: { createSession: 'Create a new session during user authentication to prevent session fixation attacks.', }, }, create(context) { let sessionRegenerate = false; function isSessionRegenerate(node) { return (node.type === 'CallExpression' && node.callee.type === 'MemberExpression' && isIdentifier(node.callee.property, 'regenerate')); } function visitCallback(node) { if (sessionRegenerate) { return; } if (isSessionRegenerate(node)) { sessionRegenerate = true; return; } childrenOf$1(node, context.sourceCode.visitorKeys).forEach(visitCallback); } function hasSessionFalseOption(callExpression) { const opt = callExpression.arguments[1]; if ((opt === null || opt === void 0 ? void 0 : opt.type) === 'ObjectExpression') { const sessionProp = getPropertyWithValue(context, opt, 'session', false); return !!sessionProp; } return false; } return { CallExpression: (node) => { const callExpression = node; if (getFullyQualifiedName(context, callExpression) === 'passport.authenticate') { if (hasSessionFalseOption(callExpression)) { return; } const parent = last(context.sourceCode.getAncestors(node)); if (parent.type === 'CallExpression') { const callback = getValueOfExpression(context, parent.arguments[2], 'FunctionExpression'); if (callback && callback.type === 'FunctionExpression') { sessionRegenerate = false; visitCallback(callback); if (!sessionRegenerate) { context.report({ node: callback, messageId: 'createSession' }); } } } } }, }; }, }; const rule$T = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { function raiseIssue(node, begin, end, positionMessage) { const properties = node.properties; const secondaryNodes = []; const secondaryMessages = []; for (let i = begin; i < end; i++) { const prop = properties[i]; if (prop.shorthand) { secondaryNodes.push(prop); secondaryMessages.push(`Move to ${positionMessage}`); } } const message = toEncodedMessage$1(`Group all shorthand properties at ${positionMessage} of this object declaration.`, secondaryNodes, secondaryMessages); context.report({ message, loc: context.sourceCode.getFirstToken(node).loc, }); } return { ObjectExpression(node) { const objectExpression = node; const objectExpressionProperties = objectExpression.properties; if (objectExpressionProperties.some(p => p.type !== 'Property')) { return; } const isShorthandPropertyList = objectExpressionProperties.map(p => p.shorthand); const shorthandPropertiesNumber = isShorthandPropertyList.filter(b => b).length; const numberOfShorthandAtBeginning = getNumberOfTrueAtBeginning(isShorthandPropertyList); const numberOfShorthandAtEnd = getNumberOfTrueAtBeginning([...isShorthandPropertyList].reverse()); const allAtBeginning = numberOfShorthandAtBeginning === shorthandPropertiesNumber; const allAtEnd = numberOfShorthandAtEnd === shorthandPropertiesNumber; const propertiesNumber = isShorthandPropertyList.length; if (!allAtBeginning && numberOfShorthandAtBeginning > numberOfShorthandAtEnd) { raiseIssue(objectExpression, numberOfShorthandAtBeginning, propertiesNumber, 'the beginning'); } else if (!allAtEnd && numberOfShorthandAtEnd > numberOfShorthandAtBeginning) { raiseIssue(objectExpression, 0, propertiesNumber - numberOfShorthandAtEnd, 'the end'); } else if (!allAtBeginning && !allAtEnd) { raiseIssue(objectExpression, 0, propertiesNumber, 'either the beginning or end'); } }, }; }, }; function getNumberOfTrueAtBeginning(list) { let numberOfTrueAtBeginning = 0; for (const b of list) { if (b) { numberOfTrueAtBeginning++; } else { break; } } return numberOfTrueAtBeginning; } const FORBIDDEN_TYPES = [ 'EscapeCharacterSet', 'UnicodePropertyCharacterSet', 'Character', 'CharacterSet', ]; const EXCEPTION_META_CHARACTERS = '[{(.?+*$^\\\\'; const rule$S = createRegExpRule(context => { return { onCharacterClassEnter: (node) => { if (hasSingleForbiddenCharacter(node.elements) && !node.negate) { context.reportRegExpNode({ messageId: 'issue', node: context.node, regexpNode: node, }); } }, }; }, { meta: { messages: { issue: 'Replace this character class by the character itself.', }, }, }); function hasSingleForbiddenCharacter(elems) { return (elems.length === 1 && FORBIDDEN_TYPES.includes(elems[0].type) && !EXCEPTION_META_CHARACTERS.includes(elems[0].raw)); } const rule$R = createRegExpRule(context => { function checkAlternation(alternation) { const { alternatives } = alternation; if (alternatives.length <= 1) { return; } if (alternatives.every(alt => alt.elements.length === 1 && alt.elements[0].type === 'Character')) { context.reportRegExpNode({ message: 'Replace this alternation with a character class.', node: context.node, regexpNode: alternation, }); } } return { onPatternEnter: checkAlternation, onGroupEnter: checkAlternation, onCapturingGroupEnter: checkAlternation, onAssertionEnter(node) { if (node.kind === 'lookahead' || node.kind === 'lookbehind') { checkAlternation(node); } }, }; }); const message = `Make sure the regex used here, which is vulnerable to super-linear runtime due to backtracking, cannot lead to denial of service.`; const rule$Q = createRegExpRule(context => { return { onRegExpLiteralEnter: (node) => { const { reports } = scslre.analyse(node); if (reports.length > 0) { context.report({ message, node: context.node, }); } }, }; }); const rule$P = { meta: { messages: { safeSocket: 'Make sure that sockets are used safely here.', }, }, create(context) { return { NewExpression: (node) => checkCallExpression$1(node, context, 'net.Socket'), CallExpression: (node) => checkCallExpression$1(node, context, 'net.createConnection', 'net.connect'), }; }, }; function checkCallExpression$1(callExpr, context, ...sensitiveFqns) { const callFqn = getFullyQualifiedName(context, callExpr); if (sensitiveFqns.some(sensitiveFqn => sensitiveFqn === callFqn)) { context.report({ messageId: 'safeSocket', node: callExpr.callee }); } } const rule$O = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { let scopeRanges = []; let reported = []; function enterScope(node) { scopeRanges.push(node.range); } function exitScope() { scopeRanges.pop(); } return { Program(node) { scopeRanges = [node.range]; reported = []; }, BlockStatement: enterScope, 'BlockStatement:exit': exitScope, ForStatement: enterScope, 'ForStatement:exit': exitScope, ForInStatement: enterScope, 'ForInStatement:exit': exitScope, ForOfStatement: enterScope, 'ForOfStatement:exit': exitScope, SwitchStatement: enterScope, 'SwitchStatement:exit': exitScope, VariableDeclaration: (node) => { const varDeclaration = node; if (varDeclaration.kind !== 'var') { return; } const scopeRange = scopeRanges[scopeRanges.length - 1]; function isOutsideOfScope(reference) { const idRange = reference.range; return idRange[0] < scopeRange[0] || idRange[1] > scopeRange[1]; } context.sourceCode.getDeclaredVariables(node).forEach(variable => { const referencesOutside = variable.references .map(ref => ref.identifier) .filter(isOutsideOfScope); if (referencesOutside.length === 0) { return; } const definition = variable.defs.find(def => varDeclaration.declarations.includes(def.node)); if (definition && !reported.includes(definition.name)) { context.report({ node: definition.name, message: toEncodedMessage$1(`Consider moving declaration of '${variable.name}' ` + `as it is referenced outside current binding context.`, referencesOutside, Array(referencesOutside.length).fill('Outside reference.')), }); variable.defs.map(def => def.name).forEach(defId => reported.push(defId)); } }); }, }; }, }; const detectReactNativeSelector = [ ':matches(', [ 'CallExpression[callee.name="require"][arguments.0.value="react-native"]', 'ImportDeclaration[source.value="react-native"]', ].join(','), ')', ].join(''); const rule$N = { meta: { hasSuggestions: true, messages: { nonBooleanMightRender: 'Convert the conditional to a boolean to avoid leaked value', suggestConversion: 'Convert the conditional to a boolean', }, }, create(context) { if (!isRequiredParserServices(context.sourceCode.parserServices)) { return {}; } let usesReactNative = false; return { [detectReactNativeSelector]() { usesReactNative = true; }, 'JSXExpressionContainer > LogicalExpression[operator="&&"]'(node) { const leftSide = node.left; checkNonBoolean(context, usesReactNative ? isStringOrNumber : isNumber, leftSide); }, }; }, }; function report$1(node, context) { context.report({ messageId: 'nonBooleanMightRender', node, suggest: [ { messageId: 'suggestConversion', fix: fixer => { const sourceCode = context.sourceCode; const previousToken = sourceCode.getTokenBefore(node); const nextToken = sourceCode.getTokenAfter(node); const fixes = []; if (!!previousToken && !!nextToken && node.range !== undefined && previousToken.value === '(' && previousToken.range[1] <= node.range[0] && nextToken.value === ')' && nextToken.range[0] >= node.range[1]) { fixes.push(fixer.remove(previousToken)); fixes.push(fixer.remove(nextToken)); } fixes.push(fixer.replaceText(node, `!!(${sourceCode.getText(node)})`)); return fixes; }, }, ], }); } function isStringOrNumber(node, context) { const type = getTypeFromTreeNode$1(node, context.sourceCode.parserServices); return isStringType$1(type) || isBigIntType(type) || isNumberType(type); } function isNumber(node, context) { const type = getTypeFromTreeNode$1(node, context.sourceCode.parserServices); return isBigIntType(type) || isNumberType(type); } function checkNonBoolean(context, isLeakingType, node) { if (node.type === 'LogicalExpression') { checkNonBoolean(context, isLeakingType, node.left); checkNonBoolean(context, isLeakingType, node.right); } else if (isLeakingType(node, context)) { report$1(node, context); } } const rule$M = { meta: { messages: { functionMaxLine: 'This function has {{lineCount}} lines, which is greater than the {{threshold}} lines authorized. Split it into smaller functions.', }, schema: [ { type: 'object', properties: { maximum: { type: 'integer', }, }, }, ], }, create(context) { const [{ maximum: threshold }] = context.options; const sourceCode = context.sourceCode; const lines = sourceCode.lines; const commentLineNumbers = getCommentLineNumbers(sourceCode.getAllComments()); const functionStack = []; const functionKnowledge = new Map(); return { 'FunctionDeclaration, FunctionExpression, ArrowFunctionExpression': (node) => { functionStack.push(node); const parent = getParent(context, node); if (!node.loc || isIIFE(node, parent)) { return; } const lineCount = getLocsNumber(node.loc, lines, commentLineNumbers); const startsWithCapital = nameStartsWithCapital(node); functionKnowledge.set(node, { node, lineCount, startsWithCapital, returnsJSX: false }); }, ReturnStatement: (node) => { const returnStatement = node; const knowledge = functionKnowledge.get(last(functionStack)); if (knowledge && returnStatement.argument && returnStatement.argument.type.startsWith('JSX')) { knowledge.returnsJSX = true; } }, 'FunctionDeclaration:exit': () => { functionStack.pop(); }, 'FunctionExpression:exit': () => { functionStack.pop(); }, 'ArrowFunctionExpression:exit': () => { functionStack.pop(); }, 'Program:exit': () => { for (const knowledge of functionKnowledge.values()) { const { node, lineCount } = knowledge; if (lineCount > threshold && !isReactFunctionComponent(knowledge)) { const functionLike = node; context.report({ messageId: 'functionMaxLine', data: { lineCount: lineCount.toString(), threshold: `${threshold}`, }, loc: locations.getMainFunctionTokenLocation(functionLike, functionLike.parent, context), }); } } }, }; }, }; function getLocsNumber(loc, lines, commentLineNumbers) { let lineCount = 0; for (let i = loc.start.line - 1; i < loc.end.line; ++i) { const line = lines[i]; const comment = commentLineNumbers.get(i + 1); if (comment && isFullLineComment(line, i + 1, comment)) { continue; } if (line.match(/^\s*$/u)) { continue; } lineCount++; } return lineCount; } function getCommentLineNumbers(comments) { const map = new Map(); comments.forEach(comment => { if (comment.loc) { for (let i = comment.loc.start.line; i <= comment.loc.end.line; i++) { map.set(i, comment); } } }); return map; } function isFullLineComment(line, lineNumber, comment) { if (!comment.loc) { return false; } const { start, end } = comment.loc; const isFirstTokenOnLine = start.line === lineNumber && !line.slice(0, start.column).trim(); const isLastTokenOnLine = end.line === lineNumber && !line.slice(end.column).trim(); return (comment && (start.line < lineNumber || isFirstTokenOnLine) && (end.line > lineNumber || isLastTokenOnLine)); } function isIIFE(node, parent) { return (node.type === 'FunctionExpression' && parent && parent.type === 'CallExpression' && parent.callee === node); } function isReactFunctionComponent(knowledge) { return knowledge.startsWithCapital && knowledge.returnsJSX; } function nameStartsWithCapital(node) { var _a; const identifier = (_a = getIdentifierFromNormalFunction(node)) !== null && _a !== void 0 ? _a : getIdentifierFromArrowFunction(node); if (!identifier) { return false; } return isIdentifierUppercase(identifier); function getIdentifierFromArrowFunction(node) { if (node.type !== 'ArrowFunctionExpression') { return null; } const parent = getNodeParent(node); if (!parent) { return null; } if (parent.type === 'VariableDeclarator') { return parent.id; } else { return null; } } function getIdentifierFromNormalFunction(node) { if (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression') { return node.id; } } function isIdentifierUppercase(node) { return node.name.startsWith(node.name[0].toUpperCase()); } } const rule$L = { meta: { messages: { maxFileLine: 'This file has {{lineCount}} lines, which is greater than {{threshold}} authorized. Split it into smaller files.', }, schema: [ { type: 'object', properties: { maximum: { type: 'integer', }, }, }, ], }, create(context) { const [{ maximum: threshold }] = context.options; const sourceCode = context.sourceCode; const lines = sourceCode.lines; const commentLineNumbers = getCommentLineNumbers(sourceCode.getAllComments()); return { 'Program:exit': (node) => { if (!node.loc) { return; } const lineCount = getLocsNumber(node.loc, lines, commentLineNumbers); if (lineCount > threshold) { context.report({ messageId: 'maxFileLine', data: { lineCount: lineCount.toString(), threshold: `${threshold}`, }, loc: { line: 0, column: 0 }, }); } }, }; }, }; var _a$1; const eslintMaxParams = eslintRules['max-params']; const rule$K = { meta: { messages: { ...(_a$1 = eslintMaxParams.meta) === null || _a$1 === void 0 ? void 0 : _a$1.messages }, schema: [ { type: 'object', properties: { max: { type: 'integer', }, }, }, ], }, create(context) { const ruleDecoration = interceptReport(eslintMaxParams, function (context, descriptor) { const [{ max }] = context.options; if ('node' in descriptor) { const functionLike = descriptor.node; if (!isException(functionLike)) { context.report(descriptor); } } function isException(functionLike) { return isBeyondMaxParams(functionLike) || isAngularConstructor(functionLike); } function isBeyondMaxParams(functionLike) { return functionLike.params.filter(p => p.type !== 'TSParameterProperty').length <= max; } function isAngularConstructor(functionLike) { var _a; const maybeConstructor = functionLike.parent; if (!isConstructor(maybeConstructor)) { return false; } const maybeComponent = (_a = maybeConstructor.parent) === null || _a === void 0 ? void 0 : _a.parent; if (!isAngularComponent(maybeComponent)) { return false; } return true; function isConstructor(node) { return ((node === null || node === void 0 ? void 0 : node.type) === 'MethodDefinition' && isIdentifier(node.key, 'constructor')); } function isAngularComponent(node) { var _a; return ((node === null || node === void 0 ? void 0 : node.type) === 'ClassDeclaration' && ((_a = node.decorators) === null || _a === void 0 ? void 0 : _a.some(decorator => { const node = decorator.expression; return (isFunctionCall(node) && getFullyQualifiedName(context, node.callee) === '@angular.core.Component'); }))); } } }); const ruleExtension = { meta: { messages: { ...ruleDecoration.meta.messages }, }, create(context) { return { TSDeclareFunction: checkFunction, TSEmptyBodyFunctionExpression: checkFunction, }; function checkFunction(node) { const functionLike = node; const [{ max }] = context.options; const numParams = functionLike.params.length; if (numParams > max) { context.report({ messageId: 'exceed', loc: getFunctionHeaderLocation(functionLike), data: { name: getFunctionNameWithKind(functionLike), count: numParams.toString(), max: max.toString(), }, }); } function getFunctionHeaderLocation(functionLike) { const sourceCode = context.sourceCode; const functionNode = (functionLike.type === 'TSEmptyBodyFunctionExpression' ? functionLike.parent : functionLike); const headerStart = sourceCode.getFirstToken(functionNode); const headerEnd = sourceCode.getFirstToken(functionNode, token => token.value === '('); return { start: headerStart.loc.start, end: headerEnd.loc.start, }; } function getFunctionNameWithKind(functionLike) { let name; let kind = 'function'; switch (functionLike.type) { case 'TSDeclareFunction': kind = 'Function declaration'; if (functionLike.id) { name = functionLike.id.name; } break; case 'TSEmptyBodyFunctionExpression': { kind = 'Empty function'; const parent = functionLike.parent; if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'MethodDefinition' && parent.key.type === 'Identifier') { name = parent.key.name; } break; } } if (name) { return `${kind} '${name}'`; } else { return kind; } } } }, }; const decorationListeners = ruleDecoration.create(context); const extensionListeners = ruleExtension.create(context); return mergeRules(decorationListeners, extensionListeners); }, }; const EXCEPTIONS = ['\t', '\n']; const rule$J = createRegExpRule(context => { return { onCharacterEnter: (character) => { const { value, raw } = character; if (value >= 0x00 && value <= 0x1f && (isSameInterpreted(raw, value) || raw.startsWith('\\x') || raw.startsWith('\\u')) && !EXCEPTIONS.includes(raw)) { context.reportRegExpNode({ message: 'Remove this control character.', node: context.node, regexpNode: character, }); } }, }; }); function isSameInterpreted(raw, value) { return raw.codePointAt(0) === value; } function decorate$1(rule) { rule.meta.hasSuggestions = true; return interceptReport(rule, (context, reportDescriptor) => { context.report({ ...reportDescriptor, suggest: [ { desc: 'Remove this duplicate property', fix(fixer) { const propertyToRemove = getPropertyNode(reportDescriptor, context); const commaAfter = context.sourceCode.getTokenAfter(propertyToRemove, token => token.value === ','); const commaBefore = context.sourceCode.getTokenBefore(propertyToRemove, token => token.value === ','); let start = commaBefore.range[1]; let end = propertyToRemove.range[1]; if (commaAfter) { end = commaAfter.range[1]; } else { start = commaBefore.range[0]; } return fixer.removeRange([start, end]); }, }, ], }); }); } function getPropertyNode(reportDescriptor, context) { if ('node' in reportDescriptor && 'loc' in reportDescriptor) { const objectLiteral = reportDescriptor['node']; const loc = reportDescriptor['loc']; const transformPosToIndex = (p) => context.sourceCode.getIndexFromLoc(p); return objectLiteral.properties.find(property => { var _a, _b; return transformPosToIndex((_a = property.loc) === null || _a === void 0 ? void 0 : _a.start) <= transformPosToIndex(loc === null || loc === void 0 ? void 0 : loc.start) && transformPosToIndex((_b = property.loc) === null || _b === void 0 ? void 0 : _b.end) >= transformPosToIndex(loc === null || loc === void 0 ? void 0 : loc.end); }); } else { throw new Error('Missing properties in report descriptor for rule S1534'); } } const noDupeKeysRule = decorate$1(eslintRules['no-dupe-keys']); const noDupeClassMembersRule = tsEslintRules['no-dupe-class-members']; const jsxNoDuplicatePropsRule = react.rules['jsx-no-duplicate-props']; const rule$I = { meta: { hasSuggestions: true, messages: { ...noDupeClassMembersRule.meta.messages, ...jsxNoDuplicatePropsRule.meta.messages, }, }, create(context) { const noDupeKeysListener = noDupeKeysRule.create(context); const noDupeClassMembersListener = noDupeClassMembersRule.create(context); const jsxNoDuplicatePropsListener = jsxNoDuplicatePropsRule.create(context); return mergeRules(noDupeKeysListener, noDupeClassMembersListener, jsxNoDuplicatePropsListener); }, }; const rule$H = createRegExpRule(context => { return { onCharacterClassEnter: (node) => { if (node.elements.length === 0 && !node.negate) { context.reportRegExpNode({ messageId: 'issue', node: context.node, regexpNode: node, }); } }, }; }, { meta: { messages: { issue: "Rework this empty character class that doesn't match anything.", }, }, }); const rule$G = { meta: { messages: { switchEnd: 'End this switch case with an unconditional break, continue, return or throw statement.', }, }, create(context) { let currentCodePath = null; let currentCodeSegment = null; let enteringSwitchCase = false; const segmentsWithExit = new Set(); const initialSegmentBySwitchCase = new Map(); const switchCaseStack = []; function noComment(node) { return context.sourceCode.getCommentsAfter(node).length === 0; } function isAfterProcessExitCall(segment, initialSegment) { const stack = []; const visitedSegments = new Set(); stack.push(segment); while (stack.length !== 0) { const current = stack.pop(); visitedSegments.add(current.id); if (!segmentsWithExit.has(current.id)) { if (current === initialSegment) { return false; } current.prevSegments.filter(p => !visitedSegments.has(p.id)).forEach(p => stack.push(p)); } } return true; } return { onCodePathStart(codePath) { currentCodePath = codePath; }, onCodePathEnd() { currentCodePath = currentCodePath.upper; }, onCodePathSegmentStart(segment) { currentCodeSegment = segment; if (enteringSwitchCase) { initialSegmentBySwitchCase.set(switchCaseStack.pop(), currentCodeSegment); enteringSwitchCase = false; } }, CallExpression(node) { const callExpr = node; if (isProcessExitCall(callExpr)) { segmentsWithExit.add(currentCodeSegment.id); } }, SwitchCase(node) { enteringSwitchCase = true; switchCaseStack.push(node); }, 'SwitchCase:exit'(node) { const switchCase = node; const initialSegment = initialSegmentBySwitchCase.get(switchCase); const isReachable = currentCodePath.currentSegments.some(s => s.reachable && !isAfterProcessExitCall(s, initialSegment)); const { cases } = getParent(context, node); if (isReachable && switchCase.consequent.length > 0 && cases[cases.length - 1] !== node && noComment(switchCase)) { context.report({ messageId: 'switchEnd', loc: context.sourceCode.getFirstToken(node).loc, }); } }, }; }, }; function isProcessExitCall(callExpr) { return (callExpr.callee.type === 'MemberExpression' && callExpr.callee.object.type === 'Identifier' && callExpr.callee.object.name === 'process' && callExpr.callee.property.type === 'Identifier' && callExpr.callee.property.name === 'exit'); } const validator = new regexpp.RegExpValidator(); const rule$F = { create(context) { function getFlags(node) { if (node.arguments.length < 2) { return ''; } if (isStringLiteral(node.arguments[1])) { return node.arguments[1].value; } return null; } function validateRegExpPattern(pattern, uFlag) { try { validator.validatePattern(pattern, undefined, undefined, uFlag); return null; } catch (err) { return err.message; } } function validateRegExpFlags(flags) { try { validator.validateFlags(flags); return null; } catch (_a) { return `Invalid flags supplied to RegExp constructor '${flags}'`; } } function isRegExpConstructor(call) { const { callee } = call; return callee.type === 'Identifier' && callee.name === 'RegExp'; } function isStringMatch(call) { const services = context.sourceCode.parserServices; if (!isRequiredParserServices(services)) { return false; } const { callee } = call; return (callee.type === 'MemberExpression' && isStringType$1(getTypeFromTreeNode$1(callee.object, services)) && isIdentifier(callee.property, 'match')); } function getPattern(call) { if (isStringLiteral(call.arguments[0])) { return call.arguments[0].value; } return null; } return { 'CallExpression, NewExpression'(node) { const call = node; if (!isRegExpConstructor(call) && !isStringMatch(call)) { return; } const pattern = getPattern(call); if (!pattern) { return; } const flags = getFlags(call); const message = (flags && validateRegExpFlags(flags)) || (flags === null ? validateRegExpPattern(pattern, true) && validateRegExpPattern(pattern, false) : validateRegExpPattern(pattern, flags.includes('u'))); if (message) { context.report({ node, message, }); } }, }; }, }; const rule$E = { meta: { messages: { noMagic: 'No magic number: {{raw}}.', }, schema: [ { type: 'object', properties: {}, }, ], }, create(context) { const baseRule = tsEslintRules['no-magic-numbers'].create(context); return { Literal: (node) => { if (!isNumericLiteral(node)) { return; } const numericLiteral = getNumericLiteral(node); if (!numericLiteral) { return; } const { value, parent } = numericLiteral; if (isPower(value) || isJSX(context, node) || isBitwiseOperator(parent) || isJsonStringify(parent)) { return; } baseRule.Literal(node); }, }; }, }; function getNumericLiteral(node) { var _a; let numberNode; let raw; let value = numericLiteralValue(node); let parent = getNodeParent(node); if (!parent || !value) { return undefined; } if (parent.type === 'UnaryExpression' && parent.operator === '-') { numberNode = parent; parent = getNodeParent(parent); value = -value; raw = `-${node.raw}`; } else { numberNode = node; raw = (_a = node.raw) !== null && _a !== void 0 ? _a : ''; } return { numberNode, raw, value, parent }; } function numericLiteralValue(node) { if (typeof node.value === 'number') { return node.value; } } function isNumericLiteral(node) { return (node.type === 'Literal' && (typeof node.value === 'number' || typeof node.value === 'bigint')); } function isPower(value) { return Number.isInteger(Math.log10(value)) || Number.isInteger(Math.log2(value)); } function isJSX(context, node) { return context.sourceCode.getAncestors(node).some(node => node.type.startsWith('JSX')); } function isBitwiseOperator(node) { return (node.type === 'BinaryExpression' && ['&', '|', '^', '<<', '>>', '>>>'].includes(node.operator)); } function isJsonStringify(node) { return node.type === 'CallExpression' && isMethodInvocation(node, 'JSON', 'stringify', 3); } const MODIFIABLE_REGEXP_FLAGS_TYPES = [ 'Literal', 'TemplateLiteral', 'TaggedTemplateExpression', ]; const metadata = { meta: { hasSuggestions: true, }, }; const rule$D = createRegExpRule(context => { function characters(nodes) { let current = []; const sequences = [current]; for (const node of nodes) { if (node.type === 'Character') { current.push(node); } else if (node.type === 'CharacterClassRange') { current.push(node.min); current = [node.max]; sequences.push(current); } else if (node.type === 'CharacterSet' && current.length > 0) { current = []; sequences.push(current); } } return sequences; } function checkSequence(sequence) { for (let index = 0; index < sequence.length; index++) { if (checkCharacter(sequence[index], index, sequence)) { return; } } } function checkCharacter(character, index, characters) { for (const check of characterChecks) { if (check(character, index, characters)) { return true; } } return false; } function checkCombinedCharacter(character, index, characters) { let reported = false; if (index !== 0 && isCombiningCharacter(character.value) && !isCombiningCharacter(characters[index - 1].value)) { const combinedChar = characters[index - 1].raw + characters[index].raw; const message = `Move this Unicode combined character '${combinedChar}' outside of the character class`; context.reportRegExpNode({ regexpNode: characters[index], node: context.node, message }); reported = true; } return reported; } function checkSurrogatePairTailCharacter(character, index, characters) { var _a; let reported = false; if (index !== 0 && isSurrogatePair(characters[index - 1].value, character.value)) { const surrogatePair = characters[index - 1].raw + characters[index].raw; const message = `Move this Unicode surrogate pair '${surrogatePair}' outside of the character class or use 'u' flag`; const pattern = (_a = getPatternFromNode(context.node, context)) === null || _a === void 0 ? void 0 : _a.pattern; let suggest; if (pattern && isValidWithUnicodeFlag(pattern)) { suggest = [ { desc: "Add unicode 'u' flag to regex", fix: fixer => addUnicodeFlag(fixer, context.node), }, ]; } context.reportRegExpNode({ regexpNode: characters[index], node: context.node, message, suggest, }); reported = true; } return reported; } function addUnicodeFlag(fixer, node) { var _a; if (isRegexLiteral(node)) { return insertTextAfter(fixer, node, 'u'); } const regExpConstructor = getRegExpConstructor(node); if (!regExpConstructor) { return null; } const args = regExpConstructor.arguments; if (args.length === 1) { const token = sourceCode.getLastToken(regExpConstructor, { skip: 1 }); return insertTextAfter(fixer, token, ', "u"'); } if (args.length > 1 && ((_a = args[1]) === null || _a === void 0 ? void 0 : _a.range) && hasModifiableFlags(regExpConstructor)) { const [start, end] = args[1].range; return fixer.insertTextAfterRange([start, end - 1], 'u'); } return null; } function checkModifiedEmojiCharacter(character, index, characters) { let reported = false; if (index !== 0 && isEmojiModifier(character.value) && !isEmojiModifier(characters[index - 1].value)) { const modifiedEmoji = characters[index - 1].raw + characters[index].raw; const message = `Move this Unicode modified Emoji '${modifiedEmoji}' outside of the character class`; context.reportRegExpNode({ regexpNode: characters[index], node: context.node, message }); reported = true; } return reported; } function checkRegionalIndicatorCharacter(character, index, characters) { let reported = false; if (index !== 0 && isRegionalIndicator(character.value) && isRegionalIndicator(characters[index - 1].value)) { const regionalIndicator = characters[index - 1].raw + characters[index].raw; const message = `Move this Unicode regional indicator '${regionalIndicator}' outside of the character class`; context.reportRegExpNode({ regexpNode: characters[index], node: context.node, message }); reported = true; } return reported; } function checkZeroWidthJoinerCharacter(character, index, characters) { let reported = false; if (index !== 0 && index !== characters.length - 1 && isZeroWidthJoiner(character.value) && !isZeroWidthJoiner(characters[index - 1].value) && !isZeroWidthJoiner(characters[index + 1].value)) { const message = 'Move this Unicode joined character sequence outside of the character class'; context.reportRegExpNode({ regexpNode: characters[index - 1], node: context.node, message }); reported = true; } return reported; } function isValidWithUnicodeFlag(pattern) { try { validator.validatePattern(pattern, undefined, undefined, true); return true; } catch (_a) { return false; } } const sourceCode = context.sourceCode; const validator = new regexpp.RegExpValidator(); const characterChecks = [ checkCombinedCharacter, checkZeroWidthJoinerCharacter, checkModifiedEmojiCharacter, checkRegionalIndicatorCharacter, checkSurrogatePairTailCharacter, ]; return { onCharacterClassEnter(ccNode) { for (const chars of characters(ccNode.elements)) { checkSequence(chars); } }, }; }, metadata); function isCombiningCharacter(codePoint) { return /^[\p{Mc}\p{Me}\p{Mn}]$/u.test(String.fromCodePoint(codePoint)); } function isSurrogatePair(lead, tail) { return lead >= 0xd800 && lead < 0xdc00 && tail >= 0xdc00 && tail < 0xe000; } function isEmojiModifier(code) { return code >= 0x1f3fb && code <= 0x1f3ff; } function isRegionalIndicator(code) { return code >= 0x1f1e6 && code <= 0x1f1ff; } function isZeroWidthJoiner(code) { return code === 0x200d; } function getRegExpConstructor(node) { return ancestorsChain(node, new Set(['CallExpression', 'NewExpression'])).find(n => isRegExpConstructor(n)); } function hasModifiableFlags(regExpConstructor) { var _a, _b, _c, _d; const args = regExpConstructor.arguments; return (typeof ((_b = (_a = args[1]) === null || _a === void 0 ? void 0 : _a.range) === null || _b === void 0 ? void 0 : _b[0]) === 'number' && typeof ((_d = (_c = args[1]) === null || _c === void 0 ? void 0 : _c.range) === null || _d === void 0 ? void 0 : _d[1]) === 'number' && getFlags(regExpConstructor) != null && MODIFIABLE_REGEXP_FLAGS_TYPES.includes(args[1].type)); } function insertTextAfter(fixer, node, text) { return node ? fixer.insertTextAfter(node, text) : null; } const rule$C = createRegExpRule(context => { let rawPattern; return { onRegExpLiteralEnter: (node) => { rawPattern = node.raw; }, onCharacterEnter: (node) => { if (node.raw !== ' ' || node.parent.type === 'CharacterClass') { return; } const nextChar = rawPattern[node.start + 1]; if (nextChar !== ' ') { const spacesBefore = countSpacesBefore(rawPattern, node.start); if (spacesBefore > 0) { const spacesNumber = spacesBefore + 1; const quantifier = `{${spacesNumber}}`; const [start, end] = getRegexpRange(context.node, node); const range = [start - spacesNumber + 1, end]; context.reportRegExpNode({ message: `If multiple spaces are required here, use number quantifier (${quantifier}).`, regexpNode: node, offset: [-spacesNumber + 1, 0], node: context.node, suggest: [ { desc: `Use quantifier ${quantifier}`, fix: fixer => fixer.replaceTextRange(range, ` ${quantifier}`), }, ], }); } } }, }; }, { meta: { hasSuggestions: true, }, }); function countSpacesBefore(pattern, index) { let counter = 0; for (let i = index - 1; i > 0; i--) { if (pattern[i] === ' ') { counter++; } else { break; } } return counter; } const noUnusedClassComponentMethod = react.rules['no-unused-class-component-methods']; function overrideContext(context, overrides) { Object.setPrototypeOf(overrides, context); return overrides; } const rule$B = { meta: { messages: { unused: 'Remove this property or method or refactor this component, as "{{name}}" is not used inside component body', unusedWithClass: 'Remove this property or method or refactor "{{className}}", as "{{name}}" is not used inside component body', }, }, create(context) { let isReact = false; const detectReactListener = rule$4E.create(overrideContext(context, { report(_descriptor) { isReact = true; }, })); const noUnusedClassComponentMethodListener = noUnusedClassComponentMethod.create(overrideContext(context, { report(descriptor) { if (isReact) { context.report(descriptor); } }, })); return mergeRules(detectReactListener, noUnusedClassComponentMethodListener); }, }; const rule$A = { meta: { messages: { unusedFunction: `Remove unused function '{{symbol}}'.`, unusedVariable: `Remove the declaration of the unused '{{symbol}}' variable.`, }, }, create(context) { let toIgnore = []; let jsxComponentsToIgnore = []; function checkVariable(v, toCheck) { if (v.defs.length === 0) { return; } const type = v.defs[0].type; if (type !== 'Variable' && type !== 'FunctionName') { return; } if (toCheck === 'let-const-function') { const def = v.defs[0]; if (def.parent && def.parent.type === 'VariableDeclaration' && def.parent.kind === 'var') { return; } } const defs = v.defs.map(def => def.name); const unused = v.references.every(ref => defs.includes(ref.identifier)); if (unused && !toIgnore.includes(defs[0]) && !jsxComponentsToIgnore.includes(v.name)) { const messageAndData = getMessageAndData(v.name, type === 'FunctionName'); defs.forEach(def => context.report({ node: def, ...messageAndData, })); } } function isParentOfModuleScope(scope) { return scope.childScopes.some(s => s.type === 'module'); } function checkScope(scope, checkedInParent) { let toCheck = checkedInParent; if (scope.type === 'function' && !isParentOfModuleScope(scope)) { toCheck = 'all'; } else if (checkedInParent === 'nothing' && scope.type === 'block') { toCheck = 'let-const-function'; } if (toCheck !== 'nothing' && scope.type !== 'function-expression-name') { scope.variables.forEach(v => checkVariable(v, toCheck)); } scope.childScopes.forEach(childScope => checkScope(childScope, toCheck)); } return { ObjectPattern: (node) => { const elements = node.properties; const hasRest = elements.some(element => element.type === 'RestElement'); if (!hasRest) { return; } elements.forEach(element => { if (element.type === 'Property' && element.shorthand && element.value.type === 'Identifier') { toIgnore.push(element.value); } }); }, JSXIdentifier: (node) => { jsxComponentsToIgnore.push(node.name); }, 'Program:exit': (node) => { checkScope(context.sourceCode.getScope(node), 'nothing'); toIgnore = []; jsxComponentsToIgnore = []; }, }; }, }; function getMessageAndData(name, isFunction) { if (isFunction) { return { messageId: 'unusedFunction', data: { symbol: name } }; } else { return { messageId: 'unusedVariable', data: { symbol: name } }; } } const preferOptionalChainRule = tsEslintRules['prefer-optional-chain']; const rule$z = { meta: { hasSuggestions: true, fixable: 'code', messages: { ...preferOptionalChainRule.meta.messages }, }, create(context) { const services = context.sourceCode.parserServices; if (!(services === null || services === void 0 ? void 0 : services.program) || !services.esTreeNodeToTSNodeMap || !services.tsNodeToESTreeNodeMap) { return {}; } return preferOptionalChainRule.create(context); }, }; const rule$y = { meta: { hasSuggestions: true, messages: { readOnlyProps: 'Mark the props of the component as read-only.', readOnlyPropsFix: 'Mark the props as read-only', }, }, create(context) { const services = context.sourceCode.parserServices; if (!isRequiredParserServices(services)) { return {}; } const functionInfo = []; return { ':function'() { functionInfo.push({ returns: [] }); }, ':function:exit'(node) { const info = functionInfo.pop(); if (!info || !isFunctionalComponent(node, info)) { return; } const [props] = node.params; if (!props) { return; } const { typeAnnotation } = props; if (!typeAnnotation) { return; } if (!isReadOnly(props, services)) { context.report({ node: props, messageId: 'readOnlyProps', suggest: [ { messageId: 'readOnlyPropsFix', fix(fixer) { const tpe = typeAnnotation.typeAnnotation; const oldText = context.sourceCode.getText(tpe); const newText = `Readonly<${oldText}>`; return fixer.replaceText(tpe, newText); }, }, ], }); } }, ReturnStatement(node) { last(functionInfo).returns.push(node); }, }; function isFunctionalComponent(node, info) { if (node.type !== 'FunctionDeclaration' || node.id === null) { return false; } const name = node.id.name; if (!(name && /^[A-Z]/.test(name))) { return false; } const paramCount = node.params.length; if (paramCount > 1) { return false; } const { returns } = info; for (const ret of returns) { if (!ret.argument) { continue; } const value = getUniqueWriteUsageOrNode(context, ret.argument); if (value.type.startsWith('JSX')) { return true; } } return false; } function isReadOnly(props, services) { const tpe = getTypeFromTreeNode$1(props, services); const { aliasSymbol } = tpe; if ((aliasSymbol === null || aliasSymbol === void 0 ? void 0 : aliasSymbol.escapedName) === 'Readonly') { return true; } const symbol = tpe.getSymbol(); if (!(symbol === null || symbol === void 0 ? void 0 : symbol.declarations)) { return true; } const declarations = symbol.declarations; for (const decl of declarations) { if (ts__namespace.isInterfaceDeclaration(decl)) { const node = services.tsNodeToESTreeNodeMap.get(decl); if ((node === null || node === void 0 ? void 0 : node.type) === 'TSInterfaceDeclaration') { const { body: { body: members }, } = node; if (members.every(m => m.type === 'TSPropertySignature' && m.readonly)) { return true; } } } if (ts__namespace.isTypeLiteralNode(decl)) { const node = services.tsNodeToESTreeNodeMap.get(decl); if ((node === null || node === void 0 ? void 0 : node.type) === 'TSTypeLiteral') { const { members } = node; if (members.every(m => m.type === 'TSPropertySignature' && m.readonly)) { return true; } } } } return false; } }, }; const rule$x = { meta: { hasSuggestions: true, messages: { useExec: 'Use the "RegExp.exec()" method instead.', suggestExec: 'Replace with "RegExp.exec()"', }, }, create(context) { const services = context.sourceCode.parserServices; if (!isRequiredParserServices(services)) { return {}; } return { "CallExpression[arguments.length=1] > MemberExpression.callee[property.name='match'][computed=false]": (memberExpr) => { var _a; const { object, property } = memberExpr; if (!isString$1(object, services)) { return; } const callExpr = memberExpr.parent; const regex = getParsedRegex(callExpr.arguments[0], context); if (regex === null || regex === void 0 ? void 0 : regex.flags.global) { return; } const variable = getLhsVariable(callExpr); for (const ref of (_a = variable === null || variable === void 0 ? void 0 : variable.references) !== null && _a !== void 0 ? _a : []) { const id = ref.identifier; const parent = getNodeParent(id); if (isMemberWithProperty$1(parent, 'length')) { return; } } context.report({ node: property, messageId: 'useExec', suggest: [ { messageId: 'suggestExec', fix(fixer) { const strText = context.sourceCode.getText(object); const regText = context.sourceCode.getText(callExpr.arguments[0]); const code = `RegExp(${regText}).exec(${strText})`; return fixer.replaceText(callExpr, code); }, }, ], }); }, }; function getLhsVariable(node) { const parent = getNodeParent(node); let ident; if (parent.type === 'VariableDeclarator' && parent.id.type === 'Identifier') { ident = parent.id; } else if (parent.type === 'AssignmentExpression' && parent.left.type === 'Identifier') { ident = parent.left; } if (ident) { return getVariableFromName(context, ident.name, node); } return null; } }, }; const dbModules = ['pg', 'mysql', 'mysql2', 'sequelize']; const rule$w = { meta: { messages: { safeQuery: `Make sure that executing SQL queries is safe here.`, }, }, create(context) { let isDbModuleImported = false; return { Program() { isDbModuleImported = false; }, ImportDeclaration(node) { const { source } = node; if (dbModules.includes(String(source.value))) { isDbModuleImported = true; } }, CallExpression(node) { const call = node; const { callee, arguments: args } = call; if (isRequireModule(call, ...dbModules)) { isDbModuleImported = true; return; } if (isDbModuleImported && isMemberWithProperty$1(callee, 'query') && isQuestionable(args[0])) { context.report({ messageId: 'safeQuery', node: callee, }); } }, }; }, }; function isQuestionable(sqlQuery) { if (!sqlQuery) { return false; } if (isTemplateWithVar(sqlQuery)) { return true; } if (isConcatenation(sqlQuery)) { return isVariableConcat(sqlQuery); } return (sqlQuery.type === 'CallExpression' && isMemberWithProperty$1(sqlQuery.callee, 'concat', 'replace')); } function isVariableConcat(node) { const { left, right } = node; if (!isHardcodedLiteral(right)) { return true; } if (isConcatenation(left)) { return isVariableConcat(left); } return !isHardcodedLiteral(left); } function isTemplateWithVar(node) { return node.type === 'TemplateLiteral' && node.expressions.length !== 0; } function isTemplateWithoutVar(node) { return node.type === 'TemplateLiteral' && node.expressions.length === 0; } function isConcatenation(node) { return node.type === 'BinaryExpression' && node.operator === '+'; } function isHardcodedLiteral(node) { return node.type === 'Literal' || isTemplateWithoutVar(node); } const rule$v = { meta: { messages: { stable: 'Make your tests stable so that they pass on the first try, or remove the flaky ones.', }, }, create(context) { const describes = []; const hasJest = hasJestDependency(context); return { CallExpression(node) { if (hasJestRetry(context, node, hasJest)) { report(context, node); return; } if (Mocha.isDescribeCase(node)) { describes.push(node); return; } if (describes.length > 0) { checkMochaRetries(context, node); } }, 'CallExpression:exit': (node) => { if (Mocha.isDescribeCase(node)) { describes.pop(); } }, 'Program:exit': () => { describes.length = 0; }, }; }, }; function hasJestRetry(context, node, hasJest) { const callExpressionName = getFullyQualifiedName(context, node); return (callExpressionName === 'jest.retryTimes' || (hasJest && isMethodInvocation(node, 'jest', 'retryTimes', 1))); } function hasJestDependency(context) { const dependencies = getDependencies(context.filename); return dependencies.has('jest'); } function checkMochaRetries(context, node) { const callee = node.callee; if (callee.type === 'MemberExpression' && callee.object.type === 'ThisExpression' && isIdentifier(callee.property, 'retries')) { report(context, node); } } function report(context, node) { context.report({ messageId: 'stable', node, }); } const rule$u = { meta: { messages: { safeStdin: `Make sure that reading the standard input is safe here.`, }, }, create(context) { return { MemberExpression(node) { if (isMemberExpression(node, 'process', 'stdin')) { context.report({ messageId: 'safeStdin', node, }); } }, }; }, }; const rule$t = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { const invocations = new Map(); const regexes = []; const resets = new Set(); return { 'Literal:exit': (node) => { extractRegex(node, regexes); }, 'CallExpression:exit': (node) => { const callExpr = node; extractRegex(node, regexes); extractRegexInvocation(callExpr, regexes, invocations, context); checkWhileConditionRegex(callExpr, context); }, 'MemberExpression:exit': (node) => { extractResetRegex(node, regexes, resets, context); }, 'NewExpression:exit': (node) => { extractRegex(node, regexes); }, 'Program:exit': () => { regexes.forEach(regex => checkGlobalStickyRegex(regex, context)); invocations.forEach((usages, regex) => checkMultipleInputsRegex(regex, usages, resets, context)); }, }; }, }; function extractRegex(node, acc) { var _a; if (isRegexLiteral(node)) { const { flags } = node.regex; acc.push({ node, flags }); } else if (isRegExpConstructor(node)) { const flags = (_a = getFlags(node)) !== null && _a !== void 0 ? _a : ''; acc.push({ node, flags }); } } function extractRegexInvocation(callExpr, regexes, invocations, context) { if (isCallingMethod(callExpr, 1, 'exec', 'test') && callExpr.callee.object.type === 'Identifier') { const { object } = callExpr.callee; const variable = getVariableFromName(context, object.name, callExpr); if (variable) { const value = getUniqueWriteUsage(context, variable.name, callExpr); const regex = regexes.find(r => r.node === value); if (regex === null || regex === void 0 ? void 0 : regex.flags.includes('g')) { const usages = invocations.get(variable); if (usages) { usages.push(callExpr); } else { invocations.set(variable, [callExpr]); } } } } } function extractResetRegex(node, regexes, resets, context) { if (isDotNotation(node) && node.object.type === 'Identifier' && node.property.name === 'lastIndex') { const parent = getParent(context, node); if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'AssignmentExpression' && parent.left === node) { const variable = getVariableFromName(context, node.object.name, node); if (variable) { const value = getUniqueWriteUsage(context, variable.name, node); const regex = regexes.find(r => r.node === value); if (regex) { resets.add(variable); } } } } } function checkWhileConditionRegex(callExpr, context) { if (isMethodCall(callExpr)) { const { object, property } = callExpr.callee; if ((isRegexLiteral(object) || isRegExpConstructor(object)) && property.name === 'exec') { const flags = object.type === 'Literal' ? object.regex.flags : getFlags(object); if ((flags === null || flags === void 0 ? void 0 : flags.includes('g')) && isWithinWhileCondition(callExpr, context)) { context.report({ message: toEncodedMessage$1('Extract this regular expression to avoid infinite loop.', []), node: object, }); } } } } function checkGlobalStickyRegex(regex, context) { if (regex.flags.includes('g') && regex.flags.includes('y')) { context.report({ message: toEncodedMessage$1(`Remove the 'g' flag from this regex as it is shadowed by the 'y' flag.`, []), node: regex.node, }); } } function checkMultipleInputsRegex(regex, usages, resets, context) { if (!resets.has(regex)) { const definition = regex.defs.find(def => def.type === 'Variable' && def.node.init); const uniqueInputs = new Set(usages.map(callExpr => context.sourceCode.getText(callExpr.arguments[0]))); const regexReset = uniqueInputs.has(`''`) || uniqueInputs.has(`""`); if (definition && uniqueInputs.size > 1 && !regexReset) { const pattern = definition.node.init; context.report({ message: toEncodedMessage$1(`Remove the 'g' flag from this regex as it is used on different inputs.`, usages, usages.map((_, idx) => `Usage ${idx + 1}`)), node: pattern, }); } } } function isWithinWhileCondition(node, context) { const ancestors = context.sourceCode.getAncestors(node); let parent; let child = node; while ((parent = ancestors.pop()) !== undefined) { if (functionLike$1.has(parent.type)) { break; } if (parent.type === 'WhileStatement' || parent.type === 'DoWhileStatement') { return parent.test === child; } child = parent; } return false; } const HSTS = 'hsts'; const HELMET$1 = 'helmet'; const MAX_AGE = 'maxAge'; const INCLUDE_SUB_DOMAINS = 'includeSubDomains'; const RECOMMENDED_MAX_AGE = 15552000; const rule$s = Express.SensitiveMiddlewarePropertyRule(findSensitiveTransportSecurityPolicyProperty, `Disabling Strict-Transport-Security policy is security-sensitive.`); function findSensitiveTransportSecurityPolicyProperty(context, node) { const sensitiveFinders = [findSensitiveHsts, findSensitiveMaxAge, findSensitiveIncludeSubDomains]; const sensitives = []; const { callee, arguments: args } = node; if (args.length === 1 && args[0].type === 'ObjectExpression') { const [options] = args; for (const finder of sensitiveFinders) { const maybeSensitive = finder(context, callee, options); if (maybeSensitive) { sensitives.push(maybeSensitive); } } } return sensitives; } function findSensitiveHsts(context, middleware, options) { if (getFullyQualifiedName(context, middleware) === HELMET$1) { return getPropertyWithValue(context, options, HSTS, false); } return undefined; } function findSensitiveMaxAge(context, middleware, options) { if (isHstsMiddlewareNode(context, middleware)) { const maybeMaxAgeProperty = getProperty$1(options, MAX_AGE, context); if (maybeMaxAgeProperty) { const maybeMaxAgeValue = getValueOfExpression(context, maybeMaxAgeProperty.value, 'Literal'); if (typeof (maybeMaxAgeValue === null || maybeMaxAgeValue === void 0 ? void 0 : maybeMaxAgeValue.value) === 'number' && maybeMaxAgeValue.value < RECOMMENDED_MAX_AGE) { return maybeMaxAgeProperty; } } } return undefined; } function findSensitiveIncludeSubDomains(context, middleware, options) { if (isHstsMiddlewareNode(context, middleware)) { return getPropertyWithValue(context, options, INCLUDE_SUB_DOMAINS, false); } return undefined; } function isHstsMiddlewareNode(context, node) { const fqn = getFullyQualifiedName(context, node); return fqn === `${HELMET$1}.${HSTS}` || fqn === HSTS; } const rule$r = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { const services = context.sourceCode.parserServices; if (!isRequiredParserServices(services)) { return {}; } return { BinaryExpression: (node) => { const { operator, left, right } = node; if (['<', '<=', '>', '>='].includes(operator) && isString$1(left, services) && isString$1(right, services) && !isLiteralException(left) && !isLiteralException(right) && !isWithinSortCallback(context, node)) { context.report({ message: toEncodedMessage$1(`Convert operands of this use of "${operator}" to number type.`, [left, right]), loc: context.sourceCode .getTokensBetween(left, right) .find(token => token.type === 'Punctuator' && token.value === operator).loc, }); } }, }; }, }; function isLiteralException(node) { return node.type === 'Literal' && node.raw.length === 3; } function isWithinSortCallback(context, node) { const ancestors = context.sourceCode.getAncestors(node).reverse(); const maybeCallback = ancestors.find(node => ['ArrowFunctionExpression', 'FunctionExpression'].includes(node.type)); if (maybeCallback) { const callback = maybeCallback; const parent = callback.parent; if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'CallExpression') { const { callee, arguments: args } = parent; let funcName; if (callee.type === 'Identifier') { funcName = callee.name; } else if (callee.type === 'MemberExpression' && callee.property.type === 'Identifier') { funcName = callee.property.name; } return (funcName === null || funcName === void 0 ? void 0 : funcName.match(/sort/i)) && args.some(arg => arg === callback); } } return false; } const constructorSuperRule = eslintRules['constructor-super']; const noThisBeforeSuperRule = eslintRules['no-this-before-super']; const rule$q = { meta: { messages: { ...constructorSuperRule.meta.messages, ...noThisBeforeSuperRule.meta.messages }, }, create(context) { const constructorSuperListener = constructorSuperRule.create(context); const notThisBeforeSuperListener = noThisBeforeSuperRule.create(context); return mergeRules(constructorSuperListener, notThisBeforeSuperListener); }, }; var _a, _b; const switchWithoutDefaultRule = { meta: { messages: { switchDefault: `Add a "default" clause to this "switch" statement.`, addDefault: 'Add a "default" branch.', }, }, create(context) { const services = context.sourceCode.parserServices; const hasTypeInformation = isRequiredParserServices(services); return { SwitchStatement(node) { const { discriminant, cases } = node; if (hasTypeInformation && isUnion$1(discriminant, services)) { return; } const defaultClause = cases.find(c => c.test === null); if (!defaultClause) { const switchKeyword = getSwitchKeyword(node, context); context.report({ messageId: 'switchDefault', loc: switchKeyword.loc, suggest: [ { messageId: 'addDefault', fix(fixer) { return fixSwitch(fixer, node, context.sourceCode); }, }, ], }); } }, }; }, }; const switchExhaustivenessRule = tsEslintRules['switch-exhaustiveness-check']; const decoratedSwitchExhaustivenessRule = interceptReport(switchExhaustivenessRule, function (context, descriptor) { const switchNode = descriptor.node.parent; const switchKeyword = getSwitchKeyword(switchNode, context); context.report({ ...descriptor, loc: switchKeyword.loc }); }); function getSwitchKeyword(node, context) { return context.sourceCode.getFirstToken(node, token => token.type === 'Keyword' && token.value === 'switch'); } function fixSwitch(fixer, node, sourceCode) { var _a, _b; const lastCase = node.cases.length > 0 ? node.cases[node.cases.length - 1] : null; const caseIndent = lastCase ? ' '.repeat((_a = lastCase.loc) === null || _a === void 0 ? void 0 : _a.start.column) : ' '.repeat((_b = node.loc) === null || _b === void 0 ? void 0 : _b.start.column); const code = "default: { throw new Error('Not implemented yet'); }"; const fixString = `${caseIndent}${code}`; if (lastCase) { return fixer.insertTextAfter(lastCase, `\n${fixString}`); } const openingBrace = sourceCode.getTokenAfter(node.discriminant, token => token.type === 'Punctuator' && token.value === '{'); const closingBrace = sourceCode.getTokenAfter(node.discriminant, token => token.type === 'Punctuator' && token.value === '}'); return fixer.replaceTextRange([openingBrace.range[0], closingBrace.range[1]], ['{', fixString, `${caseIndent}}`].join('\n')); } const rule$p = { meta: { hasSuggestions: true, messages: { ...(_a = switchWithoutDefaultRule.meta) === null || _a === void 0 ? void 0 : _a.messages, ...(_b = decoratedSwitchExhaustivenessRule.meta) === null || _b === void 0 ? void 0 : _b.messages, }, }, create(context) { return mergeRules(switchWithoutDefaultRule.create(context), decoratedSwitchExhaustivenessRule.create(context)); }, }; const HTML_TAG_NAMES = new Set([ 'a', 'abbr', 'acronym', 'address', 'applet', 'area', 'article', 'aside', 'audio', 'b', 'base', 'basefont', 'bdi', 'bdo', 'bgsound', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'command', 'content', 'data', 'datalist', 'dd', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'embed', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'frame', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'iframe', 'image', 'img', 'input', 'ins', 'isindex', 'kbd', 'keygen', 'label', 'legend', 'li', 'link', 'listing', 'main', 'map', 'mark', 'marquee', 'math', 'menu', 'menuitem', 'meta', 'meter', 'multicol', 'nav', 'nextid', 'nobr', 'noembed', 'noframes', 'noscript', 'object', 'ol', 'optgroup', 'option', 'output', 'p', 'param', 'picture', 'plaintext', 'pre', 'progress', 'q', 'rb', 'rbc', 'rp', 'rt', 'rtc', 'ruby', 's', 'samp', 'script', 'search', 'section', 'select', 'shadow', 'slot', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'svg', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'title', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr', 'xmp', ]); function isHtmlElement(node) { return (node.openingElement.name.type === 'JSXIdentifier' && HTML_TAG_NAMES.has(node.openingElement.name.name)); } const MAX_ROW_SPAN = 65534; const MAX_INVALID_COL_SPAN = 10000; const KNOWN_TABLE_STRUCTURE_ELEMENTS = ['thead', 'tbody', 'tfoot']; function computeSpan(tree, spanKey) { let span = 1; const spanAttr = jsxAstUtils.getProp(tree.openingElement.attributes, spanKey); if (spanAttr) { span = parseInt(String(jsxAstUtils.getLiteralPropValue(spanAttr))); } return span; } function rowSpan(tree) { let value = computeSpan(tree, 'rowspan'); if (value > MAX_ROW_SPAN) { value = MAX_ROW_SPAN; } return value; } function colSpan(tree) { let value = computeSpan(tree, 'colspan'); if (value > MAX_INVALID_COL_SPAN) { value = 1; } return value; } function getHeaders(tree) { const headers = jsxAstUtils.getProp(tree.openingElement.attributes, 'headers'); if (headers) { const headerVal = jsxAstUtils.getLiteralPropValue(headers); if (headerVal && String(headerVal).trim() !== '') { return String(headerVal).split(/\s+/); } } return undefined; } function getID(tree) { const id = jsxAstUtils.getProp(tree.openingElement.attributes, 'id'); if (id) { return String(jsxAstUtils.getLiteralPropValue(id)); } return undefined; } function createTableCell(internalCell) { const { rowSpan, ...tableCell } = internalCell; return tableCell; } function extractRows(context, tree) { const rows = []; let internalNodeCount = 0; let unknownTableStructure = false; const extractRow = (tree) => { const row = []; let unknownRowStructure = false; tree.children.forEach(child => { if ((child.type === 'JSXExpressionContainer' && child.expression.type === 'JSXEmptyExpression') || child.type === 'JSXText') { return; } const isTdOrTh = child.type === 'JSXElement' && child.openingElement.name.type === 'JSXIdentifier' && ['td', 'th'].includes(child.openingElement.name.name); if (!isTdOrTh) { unknownRowStructure = true; return; } const colSpanValue = colSpan(child); const rowSpanValue = rowSpan(child); const headers = getHeaders(child); const id = getID(child); for (let i = 0; i < colSpanValue; i++) { row.push({ rowSpan: rowSpanValue, isHeader: child.openingElement.name.type === 'JSXIdentifier' && child.openingElement.name.name === 'th', headers, id, node: child, internalNodeId: internalNodeCount, }); } internalNodeCount += 1; }); if (unknownRowStructure) { return null; } return row; }; const handleInternalStructure = (tree) => { const extractedRows = extractRows(context, tree); if (extractedRows === null) { unknownTableStructure = true; } else if (extractedRows.length > 0) { rows.push(...extractedRows); } }; tree.children.forEach(child => { if (child.type === 'JSXElement') { const childType = getElementType(context)(child.openingElement).toLowerCase(); if (childType === 'tr') { const extractedRow = extractRow(child); if (!extractedRow) { unknownTableStructure = true; } else { rows.push(extractedRow); } } else if (childType === 'table') ; else if (KNOWN_TABLE_STRUCTURE_ELEMENTS.includes(childType)) { handleInternalStructure(child); } else if (!isHtmlElement(child)) { unknownTableStructure = true; } } else if (child.type === 'JSXExpressionContainer' && child.expression.type !== 'JSXEmptyExpression') { unknownTableStructure = true; } else if (child.type === 'JSXFragment') { handleInternalStructure(child); } }); if (unknownTableStructure) { return null; } return rows; } function computeGrid(context, tree) { const rows = extractRows(context, tree); if (rows === null) { return null; } if (rows.length === 0) { return []; } const nbColumns = rows[0].length; const columns = Array.from({ length: nbColumns }); let row = 0; const result = []; while (row < rows.length) { const resultRow = []; let indexInRow = 0; let usedCurrentRow = false; let onlyMaxRowSpan = true; for (let column = 0; column < nbColumns; column++) { if (!columns[column]) { if (indexInRow === rows[row].length) { continue; } columns[column] = rows[row][indexInRow]; indexInRow++; usedCurrentRow = true; } const currentCell = columns[column]; if (!currentCell) { continue; } resultRow.push(createTableCell(currentCell)); if (currentCell.rowSpan > 0) { onlyMaxRowSpan = false; currentCell.rowSpan--; if (currentCell.rowSpan === 0) { columns[column] = undefined; } } } if (onlyMaxRowSpan) { break; } result.push(resultRow); if (usedCurrentRow) { row++; } } return result; } const rule$o = { meta: {}, create(context) { const checkValidTable = (tree) => { const grid = computeGrid(context, tree); if (grid === null) { return true; } if (grid.length === 0) { return false; } for (const row of grid) { if (row.every(({ isHeader }) => isHeader)) { return true; } } for (let col = 0; col < grid[0].length; col++) { if (grid.every(row => col >= row.length || row[col].isHeader)) { return true; } } return false; }; return { JSXElement(node) { const tree = node; const elementType = getElementType(context)(tree.openingElement); if (elementType === 'table') { if (isPresentationTable(context, tree.openingElement)) { return; } const ariaHidden = jsxAstUtils.getProp(tree.openingElement.attributes, 'aria-hidden'); if (ariaHidden && jsxAstUtils.getLiteralPropValue(ariaHidden) === true) { return; } if (!checkValidTable(tree)) { context.report({ node, message: 'Add a valid header row or column to this "".', }); } } }, }; }, }; const rule$n = { meta: {}, create(context) { const verifyHeaderReferences = (tree) => { const grid = computeGrid(context, tree); if (grid === null || grid.length === 0) { return; } const rowHeaders = Array.from({ length: grid.length }, (_, idx) => { const ids = grid[idx] .filter(({ isHeader, id }) => isHeader && id) .map(({ id }) => id); return new Set(ids); }); const colHeaders = Array.from({ length: grid[0].length }, (_, idx) => { const ids = grid .map(row => row[idx]) .filter(cell => cell) .filter(({ isHeader, id }) => isHeader && id) .map(({ id }) => id); return new Set(ids); }); const allHeaders = new Set([ ...rowHeaders.reduce((headers, acc) => new Set([...headers, ...acc]), new Set()), ...colHeaders.reduce((headers, acc) => new Set([...headers, ...acc]), new Set()), ]); const internalNodeToPositions = compileBlockInfo(grid); for (const { minRow, maxRow, minCol, maxCol, cell } of internalNodeToPositions.values()) { if (!cell.headers || cell.headers.length === 0) { continue; } const actualHeaders = [ ...colHeaders.slice(minCol, maxCol + 1), ...rowHeaders.slice(minRow, maxRow + 1), ].reduce((headers, acc) => new Set([...headers, ...acc]), new Set()); for (const header of cell.headers) { if (!actualHeaders.has(header)) { if (allHeaders.has(header)) { context.report({ node: cell.node, message: `id "${header}" in "headers" references the header of another column/row.`, }); } else { context.report({ node: cell.node, message: `id "${header}" in "headers" does not reference any
header.`, }); } } } } }; return { JSXElement(node) { const tree = node; const elementType = getElementType(context)(tree.openingElement); if (elementType === 'table') { verifyHeaderReferences(tree); } }, }; }, }; function compileBlockInfo(grid) { const internalNodeToPositions = new Map(); for (let row = 0; row < grid.length; row++) { for (let col = 0; col < grid[row].length; col++) { const cell = grid[row][col]; if (!cell.headers) { continue; } const oldValue = internalNodeToPositions.get(cell.internalNodeId); if (oldValue !== undefined) { internalNodeToPositions.set(cell.internalNodeId, { ...oldValue, maxRow: row, maxCol: col, }); } else { internalNodeToPositions.set(cell.internalNodeId, { minRow: row, maxRow: row, minCol: col, maxCol: col, cell, }); } } } return internalNodeToPositions; } const rule$m = { create(context) { let catchWithDone = false; function isInsideTest(node) { return context.sourceCode .getAncestors(node) .some(n => n.type === 'CallExpression' && Mocha.isTestConstruct(n)); } return { 'CatchClause CallExpression[callee.name="done"]': (_node) => { catchWithDone = true; }, 'CatchClause:exit': (node) => { if (!catchWithDone || !isInsideTest(node)) { return; } catchWithDone = false; const { param } = node; if (param && param.type === 'Identifier') { const exception = getVariableFromIdentifier(param, context.sourceCode.getScope(node)); if (exception && exception.references.length === 0) { context.report({ node: param, message: 'Either the exception should be passed to "done(e)", or the exception should be tested further.', }); } } }, CallExpression(node) { const callExpr = node; if (isInsideTest(node) && isThrowAssertWithoutNot(callExpr) && (callExpr.arguments.length === 0 || (callExpr.arguments.length === 1 && isIdentifier(callExpr.arguments[0], 'Error')))) { context.report({ node: callExpr.callee.property, message: 'Assert more concrete exception type or assert the message of exception.', }); } }, }; }, }; function isThrowAssertWithoutNot(node) { if (node.callee.type !== 'MemberExpression') { return false; } let { object, property } = node.callee; if (!isIdentifier(property, 'throw')) { return false; } while (object.type === 'MemberExpression') { if (isIdentifier(object.property, 'not')) { return false; } if (isIdentifier(object.property, 'should')) { return true; } object = object.object; } return object.type === 'CallExpression' && isIdentifier(object.callee, 'expect'); } const rule$l = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { let jumpTargets = []; function enterScope() { jumpTargets.push(new JumpTarget()); } function leaveScope() { jumpTargets.pop(); } function increateNumberOfJumpsInScopes(jump, label) { for (const jumpTarget of [...jumpTargets].reverse()) { jumpTarget.jumps.push(jump); if (label === jumpTarget.label) { break; } } } function leaveScopeAndCheckNumberOfJumps(node) { var _a; const jumps = (_a = jumpTargets.pop()) === null || _a === void 0 ? void 0 : _a.jumps; if (jumps && jumps.length > 1) { const sourceCode = context.sourceCode; const firstToken = sourceCode.getFirstToken(node); context.report({ loc: firstToken.loc, message: toEncodedMessage$1('Reduce the total number of "break" and "continue" statements in this loop to use one at most.', jumps, jumps.map(jmp => jmp.type === 'BreakStatement' ? '"break" statement.' : '"continue" statement.')), }); } } return { Program: () => { jumpTargets = []; }, BreakStatement: (node) => { var _a; const breakStatement = node; increateNumberOfJumpsInScopes(breakStatement, (_a = breakStatement.label) === null || _a === void 0 ? void 0 : _a.name); }, ContinueStatement: (node) => { var _a; const continueStatement = node; increateNumberOfJumpsInScopes(continueStatement, (_a = continueStatement.label) === null || _a === void 0 ? void 0 : _a.name); }, SwitchStatement: enterScope, 'SwitchStatement:exit': leaveScope, ForStatement: enterScope, 'ForStatement:exit': leaveScopeAndCheckNumberOfJumps, ForInStatement: enterScope, 'ForInStatement:exit': leaveScopeAndCheckNumberOfJumps, ForOfStatement: enterScope, 'ForOfStatement:exit': leaveScopeAndCheckNumberOfJumps, WhileStatement: enterScope, 'WhileStatement:exit': leaveScopeAndCheckNumberOfJumps, DoWhileStatement: enterScope, 'DoWhileStatement:exit': leaveScopeAndCheckNumberOfJumps, LabeledStatement: (node) => { const labeledStatement = node; jumpTargets.push(new JumpTarget(labeledStatement.label.name)); }, 'LabeledStatement:exit': leaveScope, }; }, }; class JumpTarget { constructor(label) { this.jumps = []; this.label = label; } } const rule$k = createRegExpRule(context => { const unicodeProperties = []; const unicodeCharacters = []; let rawPattern; let isUnicodeEnabled = false; return { onRegExpLiteralEnter: (node) => { rawPattern = node.raw; isUnicodeEnabled = node.flags.unicode; }, onQuantifierEnter: (quantifier) => { if (isUnicodeEnabled) { return; } const { raw, min: hex } = quantifier; if (raw.startsWith('\\u') && !raw.includes(',') && ['hhhh'.length, 'hhhhh'.length].includes(hex.toString().length)) { unicodeCharacters.push(quantifier); } }, onCharacterEnter: (character) => { if (isUnicodeEnabled) { return; } const c = character.raw; if (c !== '\\p' && c !== '\\P') { return; } let state = 'start'; let offset = character.start + c.length; let nextChar; do { nextChar = rawPattern[offset]; offset++; switch (state) { case 'start': if (nextChar === '{') { state = 'openingBracket'; } else { state = 'end'; } break; case 'openingBracket': if (/[a-zA-Z]/.test(nextChar)) { state = 'alpha'; } else { state = 'end'; } break; case 'alpha': if (/[a-zA-Z]/.test(nextChar)) { state = 'alpha'; } else if (nextChar === '=') { state = 'equal'; } else if (nextChar === '}') { state = 'closingBracket'; } else { state = 'end'; } break; case 'equal': if (/[a-zA-Z]/.test(nextChar)) { state = 'alpha1'; } else { state = 'end'; } break; case 'alpha1': if (/[a-zA-Z]/.test(nextChar)) { state = 'alpha1'; } else if (nextChar === '}') { state = 'closingBracket'; } else { state = 'end'; } break; case 'closingBracket': state = 'end'; unicodeProperties.push({ character, offset: offset - c.length - 1 }); break; } } while (state !== 'end'); }, onRegExpLiteralLeave: (regexp) => { if (!isUnicodeEnabled && (unicodeProperties.length > 0 || unicodeCharacters.length > 0)) { const secondaryLocations = []; const secondaryMessages = []; unicodeProperties.forEach(p => { const loc = getRegexpLocation(context.node, p.character, context, [0, p.offset]); if (loc) { secondaryLocations.push({ loc }); secondaryMessages.push('Unicode property'); } }); unicodeCharacters.forEach(c => { const loc = getRegexpLocation(context.node, c, context); if (loc) { secondaryLocations.push({ loc }); secondaryMessages.push('Unicode character'); } }); context.reportRegExpNode({ message: toEncodedMessage$1(`Enable the 'u' flag for this regex using Unicode constructs.`, secondaryLocations, secondaryMessages), node: context.node, regexpNode: regexp, }); } }, }; }, { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, }); const noUselessEscapeRule = eslintRules['no-useless-escape']; const noNonoctalDecimalEscapeRule = eslintRules['no-nonoctal-decimal-escape']; noNonoctalDecimalEscapeRule.meta.messages['nonOctalEscapeBacklash'] = noNonoctalDecimalEscapeRule.meta.messages['escapeBackslash']; delete noNonoctalDecimalEscapeRule.meta.messages['escapeBackslash']; const decoratedNoNonoctalDecimalEscapeRule = decorateNoNonoctalDecimalEscape(noNonoctalDecimalEscapeRule); function decorateNoNonoctalDecimalEscape(rule) { return interceptReport(rule, (context, descriptor) => { const { suggest, ...rest } = descriptor; suggest === null || suggest === void 0 ? void 0 : suggest.forEach(s => { const suggestion = s; if (suggestion.messageId === 'escapeBackslash') { suggestion.messageId = 'nonOctalEscapeBacklash'; } }); context.report({ suggest, ...rest }); }); } const rule$j = { meta: { hasSuggestions: true, messages: { ...noUselessEscapeRule.meta.messages, ...decoratedNoNonoctalDecimalEscapeRule.meta.messages, }, }, create(context) { const noUselessEscapeListener = noUselessEscapeRule.create(context); const decoratedNoNonoctalDecimalEscapeListener = decoratedNoNonoctalDecimalEscapeRule.create(context); return mergeRules(noUselessEscapeListener, decoratedNoNonoctalDecimalEscapeListener); }, }; const EXCLUDED_IMPORTS = ['React']; const JSDOC_TAGS = [ '@abstract', '@access', '@alias', '@arg', '@argument', '@async', '@augments', '@author', '@borrows', '@callback', '@class', '@classdesc', '@const', '@constant', '@constructor', '@constructs', '@copyright', '@default', '@defaultvalue', '@deprecated', '@desc', '@description', '@emits', '@enum', '@event', '@example', '@exception', '@exports', '@extends', '@external', '@file', '@fileoverview', '@fires', '@func', '@function', '@generator', '@global', '@hideconstructor', '@host', '@ignore', '@implements', '@inheritdoc', '@inner', '@instance', '@interface', '@kind', '@lends', '@license', '@link', '@linkcode', '@linkplain', '@listens', '@member', '@memberof', '@method', '@mixes', '@mixin', '@module', '@name', '@namespace', '@override', '@overview', '@package', '@param', '@private', '@prop', '@property', '@protected', '@public', '@readonly', '@requires', '@return', '@returns', '@see', '@since', '@static', '@summary', '@this', '@throws', '@todo', '@tutorial', '@type', '@typedef', '@var', '@variation', '@version', '@virtual', '@yield', '@yields', ]; const rule$i = { meta: { messages: { removeUnusedImport: `Remove this unused import of '{{symbol}}'.`, suggestRemoveWholeStatement: `Remove this import statement`, suggestRemoveOneVariable: `Remove this variable import`, }, hasSuggestions: true, }, create(context) { const isJsxPragmaSet = context.sourceCode.getAllComments().findIndex(comment => comment.value.includes('@jsx jsx')) > -1; const unusedImports = []; const tsTypeIdentifiers = new Set(); const vueIdentifiers = new Set(); const saveTypeIdentifier = (node) => tsTypeIdentifiers.add(node.name); function isExcluded(variable) { return EXCLUDED_IMPORTS.includes(variable.name); } function isUnused(variable) { return variable.references.length === 0; } function isImplicitJsx(variable) { return variable.name === 'jsx' && isJsxPragmaSet; } const ruleListener = { ImportDeclaration: (node) => { const variables = context.sourceCode.getDeclaredVariables(node); for (const variable of variables) { if (!isExcluded(variable) && !isImplicitJsx(variable) && isUnused(variable)) { unusedImports.push({ id: variable.identifiers[0], importDecl: node, }); } } }, 'TSTypeReference > Identifier, TSClassImplements > Identifier, TSInterfaceHeritage > Identifier': (node) => { saveTypeIdentifier(node); }, "TSQualifiedName[left.type = 'Identifier']": (node) => { saveTypeIdentifier(node.left); }, "TSInterfaceHeritage > MemberExpression[object.type = 'Identifier'], TSClassImplements > MemberExpression[object.type = 'Identifier']": (node) => { saveTypeIdentifier(node.object); }, 'Program:exit': () => { const jsxFactories = getJsxFactories(context); const jsxIdentifiers = getJsxIdentifiers(context); const jsDocComments = getJsDocComments(context); unusedImports .filter(({ id: unused }) => !jsxIdentifiers.includes(unused.name) && !tsTypeIdentifiers.has(unused.name) && !(vueIdentifiers.has(unused.name) && isInsideVueSetupScript(unused, context)) && !jsxFactories.has(unused.name) && !jsDocComments.some(comment => comment.value.includes(unused.name))) .forEach(unused => context.report({ messageId: 'removeUnusedImport', data: { symbol: unused.id.name, }, node: unused.id, suggest: [getSuggestion(context, unused)], })); }, }; if (context.sourceCode.parserServices.defineTemplateBodyVisitor) { return context.sourceCode.parserServices.defineTemplateBodyVisitor({ VElement: (node) => { const { rawName } = node; const name = rawName.split('.')[0]; vueIdentifiers.add(toCamelCase(name)); vueIdentifiers.add(toPascalCase(name)); }, VDirectiveKey: (node) => { const { name: { name }, } = node; vueIdentifiers.add(toCamelCase(name)); vueIdentifiers.add(toPascalCase(name)); }, Identifier: (node) => { vueIdentifiers.add(node.name); }, }, ruleListener, { templateBodyTriggerSelector: 'Program' }); } return ruleListener; }, }; function toCamelCase(str) { return str.replace(/-\w/g, s => s[1].toUpperCase()); } function toPascalCase(str) { const camelized = toCamelCase(str); return camelized[0].toUpperCase() + camelized.slice(1); } function getSuggestion(context, { id, importDecl }) { const variables = context.sourceCode.getDeclaredVariables(importDecl); if (variables.length === 1) { return { messageId: 'suggestRemoveWholeStatement', fix: fixer => { return removeNodeWithLeadingWhitespaces(context, importDecl, fixer); }, }; } const specifiers = importDecl.specifiers; const unusedSpecifier = specifiers.find(specifier => specifier.local === id); const code = context.sourceCode; let range; switch (unusedSpecifier.type) { case 'ImportDefaultSpecifier': { const tokenAfter = code.getTokenAfter(id); range = [id.range[0], code.getTokenAfter(tokenAfter).range[0]]; break; } case 'ImportNamespaceSpecifier': range = [code.getTokenBefore(unusedSpecifier).range[0], unusedSpecifier.range[1]]; break; case 'ImportSpecifier': { const simpleSpecifiers = specifiers.filter(specifier => specifier.type === 'ImportSpecifier'); const index = simpleSpecifiers.findIndex(specifier => specifier === unusedSpecifier); if (simpleSpecifiers.length === 1) { range = [specifiers[0].range[1], code.getTokenAfter(unusedSpecifier).range[1]]; } else if (index === 0) { range = [simpleSpecifiers[0].range[0], simpleSpecifiers[1].range[0]]; } else { range = [simpleSpecifiers[index - 1].range[1], simpleSpecifiers[index].range[1]]; } } } return { messageId: 'suggestRemoveOneVariable', fix: fixer => { return fixer.removeRange(range); }, }; } function getJsxFactories(context) { const factories = new Set(); const parserServices = context.sourceCode.parserServices; if (isRequiredParserServices(parserServices)) { const compilerOptions = parserServices.program.getCompilerOptions(); if (compilerOptions.jsxFactory) { factories.add(compilerOptions.jsxFactory); } if (compilerOptions.jsxFragmentFactory) { factories.add(compilerOptions.jsxFragmentFactory); } } return factories; } function getJsxIdentifiers(context) { return context.sourceCode.ast.tokens .filter(token => token.type === 'JSXIdentifier') .map(token => token.value); } function getJsDocComments(context) { return context.sourceCode .getAllComments() .filter(comment => comment.type === 'Block' && JSDOC_TAGS.some(tag => comment.value.includes(tag))); } const rule$h = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { const services = context.sourceCode.parserServices; if (!isRequiredParserServices(services)) { return {}; } const intellisense = new RegexIntelliSense(services, context); return { 'Literal[regex]:exit': (literal) => { intellisense.collectKnowledge(literal); }, 'NewExpression:exit': (newExpr) => { intellisense.collectKnowledge(newExpr); }, 'CallExpression:exit': (callExpr) => { intellisense.collectKnowledge(callExpr); intellisense.collectPatternMatcher(callExpr); checkStringReplaceGroupReferences(callExpr, intellisense); }, 'MemberExpression:exit': (memberExpr) => { if (memberExpr.computed) { checkIndexBasedGroupReference(memberExpr, intellisense); } else { checkNonExistingGroupReference(memberExpr, intellisense); } }, 'Program:exit': () => { checkUnusedGroups(intellisense); checkIndexedGroups(intellisense); }, }; }, }; function checkStringReplaceGroupReferences(callExpr, intellisense) { if (isStringReplaceCall(callExpr, intellisense.services)) { const [pattern, substr] = callExpr.arguments; const regex = intellisense.findRegex(pattern); if (regex) { const references = extractReferences(substr); const indexes = new Set(); const names = new Set(); references.forEach(ref => isNaN(Number(ref.value)) ? names.add(ref.value) : indexes.add(Number(ref.value))); regex.groups.forEach(group => { group.used || (group.used = names.has(group.name)); group.used || (group.used = indexes.has(group.index)); }); const indexedGroups = regex.groups.filter(group => indexes.has(group.index)); if (indexedGroups.length > 0) { const { locations, messages } = prepareSecondaries(regex, indexedGroups, intellisense, 'Group'); intellisense.context.report({ message: toEncodedMessage$1(`Directly use the group names instead of their numbers.`, locations, messages), node: substr, }); } } } } function checkIndexBasedGroupReference(memberExpr, intellisense) { const { object: matcher, property } = memberExpr; const regex = intellisense.resolve(matcher); if (regex) { const maybeIndex = getValueOfExpression(intellisense.context, property, 'Literal'); if (maybeIndex && typeof maybeIndex.value === 'number') { const index = maybeIndex.value; const group = regex.groups.find(grp => grp.index === index); if (group) { group.used = true; const { locations, messages } = prepareSecondaries(regex, [group], intellisense, 'Group'); intellisense.context.report({ message: toEncodedMessage$1(`Directly use '${group.name}' instead of its group number.`, locations, messages), node: property, }); } } } } function checkNonExistingGroupReference(memberExpr, intellisense) { const { object: matcher } = memberExpr; const regex = intellisense.resolve(matcher); if (regex) { const groupNodes = extractGroupNodes(memberExpr, intellisense); for (const groupNode of groupNodes) { const groupName = groupNode.type === 'Identifier' ? groupNode.name : groupNode.value; const group = regex.groups.find(grp => grp.name === groupName); if (group) { group.used = true; } else { const { locations, messages } = prepareSecondaries(regex, regex.groups, intellisense, 'Named group'); intellisense.context.report({ message: toEncodedMessage$1(`There is no group named '${groupName}' in the regular expression.`, locations, messages), node: groupNode, }); } } } } function extractGroupNodes(memberExpr, intellisense) { if (isDotNotation(memberExpr)) { const { property } = memberExpr; const ancestors = intellisense.context.sourceCode.getAncestors(memberExpr); let parent = ancestors.pop(); while (parent.type === 'TSNonNullExpression') { parent = ancestors.pop(); } if (parent) { switch (property.name) { case 'groups': return extractNamedOrDestructuredGroupNodes(parent); case 'indices': if (isDotNotation(parent) && parent.property.name === 'groups') { parent = ancestors.pop(); if (parent) { return extractNamedOrDestructuredGroupNodes(parent); } } } } } return []; } function extractNamedOrDestructuredGroupNodes(node) { if (isDotNotation(node) || isIndexNotation(node)) { return [node.property]; } else if (isObjectDestructuring(node)) { const destructuredGroups = []; const pattern = node.type === 'VariableDeclarator' ? node.id : node.left; for (const property of pattern.properties) { if (property.type === 'Property' && property.key.type === 'Identifier') { destructuredGroups.push(property.key); } } return destructuredGroups; } else { return []; } } function checkUnusedGroups(intellisense) { intellisense.getKnowledge().forEach(regex => { if (regex.matched) { const unusedGroups = regex.groups.filter(group => !group.used); if (unusedGroups.length) { const { locations, messages } = prepareSecondaries(regex, unusedGroups, intellisense, 'Named group'); intellisense.context.report({ message: toEncodedMessage$1('Use the named groups of this regex or remove the names.', locations, messages), node: regex.node, }); } } }); } function prepareSecondaries(regex, groups, intellisense, label) { const locations = []; const messages = []; for (const grp of groups) { const loc = getRegexpLocation(regex.node, grp.node, intellisense.context); if (loc) { locations.push({ loc }); messages.push(`${label} '${grp.name}'`); } } return { locations, messages }; } function checkIndexedGroups(intellisense) { intellisense.getKnowledge().forEach(regex => { regex.groups.forEach(group => { const { locations, messages } = prepareSecondaries(regex, [group], intellisense, 'Group'); group.node.references.forEach(reference => { const loc = getRegexpLocation(regex.node, reference, intellisense.context); if (loc && typeof reference.ref === 'number') { intellisense.context.report({ message: toEncodedMessage$1(`Directly use '${group.name}' instead of its group number.`, locations, messages), loc, }); } }); }); }); } function makeRegexKnowledge(node, regexp) { const capturingGroups = []; const backreferences = []; regexpp__namespace.visitRegExpAST(regexp, { onBackreferenceEnter: reference => reference.resolved.name && backreferences.push(reference), onCapturingGroupEnter: group => capturingGroups.push(group), }); const groups = []; capturingGroups.forEach((group, index) => group.name && groups.push(makeGroupKnowledge(group, backreferences, index + 1))); return { node, regexp, groups, matched: false }; } function makeGroupKnowledge(node, backreferences, index) { const name = node.name; const used = backreferences.some(backreference => backreference.resolved === node); return { node, name, used, index }; } class RegexIntelliSense { constructor(services, context) { this.services = services; this.context = context; this.knowledge = []; this.bindings = new Map(); } getKnowledge() { return this.knowledge; } collectKnowledge(node) { let regexNode = node; if (node.type === 'CallExpression' && isStringRegexMethodCall(node, this.services)) { regexNode = node.arguments[0]; } const regex = getParsedRegex(regexNode, this.context); if (regex !== null) { this.knowledge.push(makeRegexKnowledge(regexNode, regex)); } } collectPatternMatcher(callExpr) { const { callee, arguments: args } = callExpr; if (isMethodCall(callExpr) && args.length > 0) { const target = callee.object; const matcher = getLhsVariable(this.context, callExpr); if (matcher) { const method = callee.property; if (isString$1(target, this.services) && ['match', 'matchAll'].includes(method.name)) { const [pattern] = args; this.bind(pattern, matcher); } else if (method.name === 'exec' && isString$1(args[0], this.services)) { const pattern = target; this.bind(pattern, matcher); } } } } resolve(matcher) { var _a; const variable = this.findVariable(matcher); if (variable) { return (_a = this.bindings.get(variable)) !== null && _a !== void 0 ? _a : null; } else { return null; } } findRegex(node) { return this.findRegexRec(node, new Set()); } findRegexRec(node, visited) { if (!visited.has(node)) { visited.add(node); const variable = this.findVariable(node); if (variable) { const value = getUniqueWriteUsage(this.context, variable.name, node); if (value) { const regex = this.findRegexRec(value, visited); if (regex) { return regex; } } } } return this.knowledge.find(regex => regex.node === node); } bind(pattern, matcher) { const regex = this.findRegex(pattern); if (regex) { regex.matched = true; this.bindings.set(matcher, regex); } } findVariable(node) { if (node.type === 'Identifier') { return getVariableFromName(this.context, node.name, node); } return null; } } const rule$g = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { const MESSAGE = 'Enable server certificate validation on this SSL/TLS connection.'; const SECONDARY_MESSAGE = 'Set "rejectUnauthorized" to "true".'; function checkSensitiveArgument(callExpression, sensitiveArgumentIndex) { if (callExpression.arguments.length < sensitiveArgumentIndex + 1) { return; } const sensitiveArgument = callExpression.arguments[sensitiveArgumentIndex]; const secondaryLocations = []; const secondaryMessages = []; const argumentValue = getValueOfExpression(context, sensitiveArgument, 'ObjectExpression'); if (!argumentValue) { return; } if (sensitiveArgument !== argumentValue) { secondaryLocations.push(argumentValue); secondaryMessages.push(undefined); } const unsafeRejectUnauthorizedConfiguration = getPropertyWithValue(context, argumentValue, 'rejectUnauthorized', false); if (unsafeRejectUnauthorizedConfiguration) { secondaryLocations.push(unsafeRejectUnauthorizedConfiguration); secondaryMessages.push(SECONDARY_MESSAGE); context.report({ node: callExpression.callee, message: toEncodedMessage$1(MESSAGE, secondaryLocations, secondaryMessages), }); } } return { CallExpression: (node) => { const callExpression = node; const fqn = getFullyQualifiedName(context, callExpression); if (fqn === 'https.request') { checkSensitiveArgument(callExpression, 0); } if (fqn === 'request.get') { checkSensitiveArgument(callExpression, 0); } if (fqn === 'tls.connect') { checkSensitiveArgument(callExpression, 2); } }, }; }, }; const rule$f = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { const MESSAGE = 'Enable server hostname verification on this SSL/TLS connection.'; const SECONDARY_MESSAGE = 'Set "rejectUnauthorized" to "true".'; function checkSensitiveArgument(callExpression, sensitiveArgumentIndex) { if (callExpression.arguments.length < sensitiveArgumentIndex + 1) { return; } const sensitiveArgument = callExpression.arguments[sensitiveArgumentIndex]; const secondaryLocations = []; const secondaryMessages = []; let shouldReport = false; const argumentValue = getValueOfExpression(context, sensitiveArgument, 'ObjectExpression'); if (!argumentValue) { return; } if (sensitiveArgument !== argumentValue) { secondaryLocations.push(argumentValue); secondaryMessages.push(undefined); } const unsafeRejectUnauthorizedConfiguration = getPropertyWithValue(context, argumentValue, 'rejectUnauthorized', false); if (unsafeRejectUnauthorizedConfiguration) { secondaryLocations.push(unsafeRejectUnauthorizedConfiguration); secondaryMessages.push(SECONDARY_MESSAGE); shouldReport = true; } const checkServerIdentityProperty = getProperty$1(argumentValue, 'checkServerIdentity', context); if (checkServerIdentityProperty && shouldReportOnCheckServerIdentityCallBack(checkServerIdentityProperty)) { secondaryLocations.push(checkServerIdentityProperty); secondaryMessages.push(undefined); shouldReport = true; } if (shouldReport) { context.report({ node: callExpression.callee, message: toEncodedMessage$1(MESSAGE, secondaryLocations, secondaryMessages), }); } } function shouldReportOnCheckServerIdentityCallBack(checkServerIdentityProperty) { let baseFunction; baseFunction = getValueOfExpression(context, checkServerIdentityProperty.value, 'FunctionExpression'); if (!baseFunction) { baseFunction = getValueOfExpression(context, checkServerIdentityProperty.value, 'ArrowFunctionExpression'); } if ((baseFunction === null || baseFunction === void 0 ? void 0 : baseFunction.body.type) === 'BlockStatement') { const returnStatements = ReturnStatementsVisitor.getReturnStatements(baseFunction.body, context); if (returnStatements.length === 0 || returnStatements.every(r => { var _a; return (!r.argument || ((_a = getValueOfExpression(context, r.argument, 'Literal')) === null || _a === void 0 ? void 0 : _a.value) === true); })) { return true; } } return false; } return { CallExpression: (node) => { const callExpression = node; const fqn = getFullyQualifiedName(context, callExpression); if (fqn === 'https.request') { checkSensitiveArgument(callExpression, 0); } if (fqn === 'request.get') { checkSensitiveArgument(callExpression, 0); } if (fqn === 'tls.connect') { checkSensitiveArgument(callExpression, 2); } }, }; }, }; class ReturnStatementsVisitor { constructor() { this.returnStatements = []; } static getReturnStatements(node, context) { const visitor = new ReturnStatementsVisitor(); visitor.visit(node, context); return visitor.returnStatements; } visit(root, context) { const visitNode = (node) => { switch (node.type) { case 'ReturnStatement': this.returnStatements.push(node); break; case 'FunctionDeclaration': case 'FunctionExpression': case 'ArrowFunctionExpression': return; } childrenOf$1(node, context.sourceCode.visitorKeys).forEach(visitNode); }; visitNode(root); } } const rule$e = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { return { 'VariableDeclaration[kind="const"]': (node) => { context.sourceCode.getDeclaredVariables(node).forEach(variable => variable.references.filter(isModifyingReference).forEach(reference => context.report({ message: toEncodedMessage$1(`Correct this attempt to modify "${reference.identifier.name}" or use "let" in its declaration.`, [node], ['Const declaration']), node: reference.identifier, }))); }, }; }, }; function isModifyingReference(reference, index, references) { const identifier = reference.identifier; const modifyingDifferentIdentifier = index === 0 || references[index - 1].identifier !== identifier; return (identifier && reference.init === false && reference.isWrite() && modifyingDifferentIdentifier); } const rule$d = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { function checkLoop(updateNode, extractCounters, loopBody) { const counters = []; extractCounters(updateNode, counters); counters.forEach(counter => checkCounter(counter, loopBody)); } function checkCounter(counter, block) { const variable = getVariableFromName(context, counter.name, block); if (!variable) { return; } variable.references.forEach(ref => { if (ref.isWrite() && isUsedInsideBody(ref.identifier, block)) { context.report({ node: ref.identifier, message: toEncodedMessage$1(`Remove this assignment of "${counter.name}".`, [counter], ['Counter variable update']), }); } }); } return { 'ForStatement > BlockStatement': (node) => { const forLoop = getParent(context, node); if (forLoop.update) { checkLoop(forLoop.update, collectCountersFor, node); } }, 'ForInStatement > BlockStatement, ForOfStatement > BlockStatement': (node) => { const { left } = getParent(context, node); checkLoop(left, collectCountersForX, node); }, }; }, }; function collectCountersForX(updateExpression, counters) { if (updateExpression.type === 'VariableDeclaration') { updateExpression.declarations.forEach(decl => collectCountersForX(decl.id, counters)); } else { resolveIdentifiers(updateExpression, true).forEach(id => counters.push(id)); } } function collectCountersFor(updateExpression, counters) { let counter = undefined; if (updateExpression.type === 'AssignmentExpression') { counter = updateExpression.left; } else if (updateExpression.type === 'UpdateExpression') { counter = updateExpression.argument; } else if (updateExpression.type === 'SequenceExpression') { updateExpression.expressions.forEach(e => collectCountersFor(e, counters)); } if (counter && counter.type === 'Identifier') { counters.push(counter); } } function isUsedInsideBody(id, loopBody) { const bodyRange = loopBody.range; return id.range && bodyRange && id.range[0] > bodyRange[0] && id.range[1] < bodyRange[1]; } function decorate(rule) { rule.meta.hasSuggestions = true; return interceptReport(rule, (context, reportDescriptor) => { const suggest = []; const node = reportDescriptor.node; if (node.type === 'BinaryExpression') { const { left, operator, right } = node; let negate = null; switch (operator) { case '!=': case '!==': negate = true; break; case '==': case '===': negate = false; break; } if (negate !== null) { const arg = isNaNIdentifier(left) ? right : left; const argText = context.sourceCode.getText(arg); const prefix = negate ? '!' : ''; suggest.push({ desc: 'Use "isNaN()"', fix: fixer => fixer.replaceText(node, `${prefix}isNaN(${argText})`), }, { desc: 'Use "Number.isNaN()"', fix: fixer => fixer.replaceText(node, `${prefix}Number.isNaN(${argText})`), }); } } context.report({ ...reportDescriptor, suggest }); }); } function isNaNIdentifier(node) { return isIdentifier(node, 'NaN') || isMemberExpression(node, 'Number', 'NaN'); } const rule$c = decorate(eslintRules['use-isnan']); const TYPE_THRESHOLD = 2; const USAGE_THRESHOLD = 2; const rule$b = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { let usage; return { Program: () => (usage = new Map()), 'Program:exit': () => usage.forEach(nodes => { if (nodes.length > USAGE_THRESHOLD) { const [node, ...rest] = nodes; const kind = node.type === 'TSUnionType' ? 'union' : 'intersection'; const message = toEncodedMessage$1(`Replace this ${kind} type with a type alias.`, rest, Array(rest.length).fill('Following occurrence.')); context.report({ message, loc: node.loc }); } }), 'TSUnionType, TSIntersectionType': (node) => { const ancestors = context.sourceCode.getAncestors(node); const declaration = ancestors.find(ancestor => ancestor.type === 'TSTypeAliasDeclaration'); if (declaration) { return; } const composite = node; if (composite.types.length <= TYPE_THRESHOLD) { return; } if (isNullableType(composite)) { return; } const text = composite.types .map(typeNode => context.sourceCode.getText(typeNode)) .sort((a, b) => a.localeCompare(b)) .join('|'); let occurrences = usage.get(text); if (!occurrences) { occurrences = [composite]; usage.set(text, occurrences); } else { occurrences.push(composite); } }, }; function isNullableType(node) { return (node.type === 'TSUnionType' && node.types.filter(type => type.type !== 'TSNullKeyword' && type.type !== 'TSUndefinedKeyword').length === 1); } }, }; const rule$a = { meta: { messages: { uselessStringOp: '{{symbol}} is an immutable object; you must either store or return the result of the operation.', }, }, create(context) { const services = context.sourceCode.parserServices; if (!isRequiredParserServices(services)) { return {}; } function isString(node) { const type = getTypeFromTreeNode$1(node, services); return (type.flags & ts__namespace.TypeFlags.StringLike) !== 0; } function getVariable(node) { let variable = context.sourceCode.getText(node); if (variable.length > 30) { variable = 'String'; } return variable; } return { 'ExpressionStatement > CallExpression[callee.type="MemberExpression"]': (node) => { const { object, property } = node .callee; if (isString(object) && property.type === 'Identifier') { context.report({ messageId: 'uselessStringOp', data: { symbol: getVariable(object), }, node: property, }); } }, }; }, }; const comparisonOperators = new Set(['>', '<', '>=', '<=']); const rule$9 = { meta: { messages: { reEvaluateDataFlow: 'Re-evaluate the data flow; this operand of a numeric comparison could be of type {{type}}.', }, }, create(context) { const services = context.sourceCode.parserServices; if (!isRequiredParserServices(services)) { return {}; } return { BinaryExpression(node) { const { left, operator, right } = node; if (!comparisonOperators.has(operator)) { return; } if (left.type === 'MemberExpression' || right.type === 'MemberExpression') { return; } const checker = services.program.getTypeChecker(); const leftType = getTypeFromTreeNode$1(left, services); const rightType = getTypeFromTreeNode$1(right, services); if (isStringType$1(leftType) || isStringType$1(rightType)) { return; } const isLeftConvertibleToNumber = isConvertibleToNumber(leftType, checker); const isRightConvertibleToNumber = isConvertibleToNumber(rightType, checker); if (!isLeftConvertibleToNumber) { context.report({ messageId: 'reEvaluateDataFlow', data: { type: checker.typeToString(leftType), }, node: left, }); } if (!isRightConvertibleToNumber) { context.report({ messageId: 'reEvaluateDataFlow', data: { type: checker.typeToString(rightType), }, node: right, }); } }, }; }, }; function isConvertibleToNumber(typ, checker) { const flags = typ.getFlags(); if ((flags & ts__namespace.TypeFlags.BooleanLike) !== 0) { return true; } if ((flags & ts__namespace.TypeFlags.Undefined) !== 0) { return false; } const valueOfSignatures = getValueOfSignatures(typ, checker); return (valueOfSignatures.length === 0 || valueOfSignatures.some(signature => { const returnType = signature.getReturnType(); return isNumberType(returnType) || isBigIntType(returnType); })); } function getValueOfSignatures(typ, checker) { var _a; const valueOfSymbol = typ.getProperty('valueOf'); if (!valueOfSymbol) { return []; } const declarations = (_a = valueOfSymbol.getDeclarations()) !== null && _a !== void 0 ? _a : []; return declarations .map(declaration => checker.getTypeAtLocation(declaration).getCallSignatures()) .reduce((result, decl) => result.concat(decl), []); } const rule$8 = { meta: { messages: { renameSymbol: `Rename this {{symbolType}} "{{symbol}}" to match the regular expression {{format}}.`, }, schema: [ { type: 'object', properties: { format: { type: 'string', }, }, }, ], }, create(context) { return { VariableDeclaration: (node) => checkVariable(node, context), 'FunctionDeclaration, FunctionExpression, ArrowFunctionExpression, TSDeclareFunction, TSMethodSignature, TSConstructSignatureDeclaration, TSEmptyBodyFunctionExpression': (node) => checkFunction(node, context), PropertyDefinition: (node) => checkProperty(node, context), CatchClause: (node) => checkCatch(node, context), }; }, }; function checkVariable(decl, context) { if (decl.declare) { return; } decl.declarations.forEach(declaration => resolveIdentifiers(declaration.id).forEach(id => raiseOnInvalidIdentifier(id, 'local variable', context))); } function checkFunction(func, context) { if (func.declare) { return; } func.params.forEach(param => resolveIdentifiers(param).forEach(id => raiseOnInvalidIdentifier(id, 'parameter', context))); } function checkProperty(prop, context) { if (prop.key.type === 'Identifier') { raiseOnInvalidIdentifier(prop.key, 'property', context); } } function checkCatch(catchh, context) { if (catchh.param) { resolveIdentifiers(catchh.param).forEach(id => raiseOnInvalidIdentifier(id, 'parameter', context)); } } function raiseOnInvalidIdentifier(id, idType, context) { const [{ format }] = context.options; const { name } = id; if (!name.match(format)) { context.report({ messageId: 'renameSymbol', data: { symbol: name, symbolType: idType, format, }, node: id, }); } } const rule$7 = { meta: { messages: { removeVoid: 'Remove this use of the "void" operator.', }, }, create(context) { const services = context.sourceCode.parserServices; function checkNode(node) { const unaryExpression = node; if (isVoid0(unaryExpression) || isIIFE(unaryExpression) || isPromiseLike(unaryExpression)) { return; } const operatorToken = context.sourceCode.getTokenBefore(unaryExpression.argument); context.report({ loc: operatorToken.loc, messageId: 'removeVoid', }); } function isVoid0(expr) { return expr.argument.type === 'Literal' && 0 === expr.argument.value; } function isIIFE(expr) { return (expr.argument.type === 'CallExpression' && ['ArrowFunctionExpression', 'FunctionExpression'].includes(expr.argument.callee.type)); } function isPromiseLike(expr) { return isRequiredParserServices(services) && isThenable$1(expr.argument, services); } return { 'UnaryExpression[operator="void"]': checkNode, }; }, }; const SECURE_PROTOCOL_ALLOWED_VALUES = [ 'TLSv1_2_method', 'TLSv1_2_client_method', 'TLSv1_2_server_method', 'TLS_method', 'TLS_client_method', 'TLS_server_method', ]; const rule$6 = { meta: { messages: { useMinimumTLS: "Change '{{option}}' to use at least TLS v1.2.", useSecureTLS: "Change '{{option}}' to allow only secure TLS versions.", AWSApiGateway: 'Change this code to enforce TLS 1.2 or above.', AWSOpenElasticSearch: 'Omitting "tlsSecurityPolicy" enables a deprecated version of TLS. Set it to enforce TLS 1.2 or above.', }, }, create(context) { function getValueOfProperty(objectExpression, propertyName) { const unsafeProperty = objectExpression && getProperty$1(objectExpression, propertyName, context); if (unsafeProperty) { return getValueOfExpression(context, unsafeProperty.value, 'Literal'); } return undefined; } function checkMinMaxVersion(propertyName, property) { if (property && (property.value === 'TLSv1.1' || property.value === 'TLSv1')) { context.report({ node: property, messageId: 'useMinimumTLS', data: { option: propertyName, }, }); } } function checkSslOptions(optionsNode) { var _a, _b; const options = getValueOfExpression(context, optionsNode, 'ObjectExpression'); const minVersion = getValueOfProperty(options, 'minVersion'); const maxVersion = getValueOfProperty(options, 'maxVersion'); checkMinMaxVersion('minVersion', minVersion); checkMinMaxVersion('maxVersion', maxVersion); const secureProtocol = getValueOfProperty(options, 'secureProtocol'); const secureProtocolValue = (_b = (_a = secureProtocol === null || secureProtocol === void 0 ? void 0 : secureProtocol.value) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : ''; if (secureProtocol && !SECURE_PROTOCOL_ALLOWED_VALUES.includes(secureProtocolValue)) { context.report({ node: secureProtocol, messageId: 'useMinimumTLS', data: { option: 'secureProtocol', }, }); } const secureOptions = getProperty$1(options, 'secureOptions', context); if (secureOptions && !isValidSecureOptions(secureOptions.value)) { context.report({ node: secureOptions, messageId: 'useSecureTLS', data: { option: 'secureOptions', }, }); } } function isValidSecureOptions(options) { const flags = []; collectIdentifiersFromBinary(options, flags); return (flags[0] === null || (flags.includes('SSL_OP_NO_TLSv1') && flags.includes('SSL_OP_NO_TLSv1_1'))); } function collectIdentifiersFromBinary(node, acc) { if (node.type === 'BinaryExpression') { collectIdentifiersFromBinary(node.left, acc); collectIdentifiersFromBinary(node.right, acc); } else if (node.type === 'MemberExpression' && getFullyQualifiedName(context, node.object) === 'constants' && node.property.type === 'Identifier') { acc.push(node.property.name); } else { acc[0] = null; } } return { CallExpression: (node) => { const callExpression = node; const fqn = getFullyQualifiedName(context, callExpression); if (fqn === 'https.request') { checkSslOptions(callExpression.arguments[0]); checkSslOptions(callExpression.arguments[1]); } if (fqn === 'request.get') { checkSslOptions(callExpression.arguments[0]); } if (fqn === 'tls.connect') { checkSslOptions(callExpression.arguments[0]); checkSslOptions(callExpression.arguments[1]); checkSslOptions(callExpression.arguments[2]); } if (fqn === 'tls.createSecureContext') { checkSslOptions(callExpression.arguments[0]); } }, }; }, }; const rule$5 = AwsCdkTemplate({ 'aws_cdk_lib.aws_apigateway.CfnDomainName': AwsCdkCheckArguments('AWSApiGateway', true, 'securityPolicy', { primitives: { valid: ['TLS_1_2'] } }), 'aws_cdk_lib.aws_apigateway.DomainName': AwsCdkCheckArguments('AWSApiGateway', false, 'securityPolicy', { fqns: { valid: ['aws_cdk_lib.aws_apigateway.SecurityPolicy.TLS_1_2'] } }), 'aws_cdk_lib.aws_elasticsearch.CfnDomain': AwsCdkCheckArguments(['AWSOpenElasticSearch', 'enforceTLS12'], true, ['domainEndpointOptions', 'tlsSecurityPolicy'], { primitives: { valid: ['Policy-Min-TLS-1-2-2019-07'] }, }), 'aws_cdk_lib.aws_opensearchservice.Domain': AwsCdkCheckArguments(['AWSOpenElasticSearch', 'enforceTLS12'], true, 'tlsSecurityPolicy', { fqns: { valid: ['aws_cdk_lib.aws_opensearchservice.TLSSecurityPolicy.TLS_1_2'] }, }), 'aws_cdk_lib.aws_opensearchservice.CfnDomain': AwsCdkCheckArguments(['AWSOpenElasticSearch', 'enforceTLS12'], true, ['domainEndpointOptions', 'tlsSecurityPolicy'], { primitives: { valid: ['Policy-Min-TLS-1-2-2019-07'] }, }), 'aws_cdk_lib.aws_elasticsearch.Domain': AwsCdkCheckArguments(['AWSOpenElasticSearch', 'enforceTLS12'], true, 'tlsSecurityPolicy', { fqns: { valid: ['aws_cdk_lib.aws_elasticsearch.TLSSecurityPolicy.TLS_1_2'] }, }), }, { meta: { messages: { enforceTLS12: 'Change this code to enforce TLS 1.2 or above.', AWSApiGateway: 'Change this code to enforce TLS 1.2 or above.', AWSOpenElasticSearch: 'Omitting "tlsSecurityPolicy" enables a deprecated version of TLS. Set it to enforce TLS 1.2 or above.', }, }, }); const rule$4 = { meta: { messages: { ...rule$6.meta.messages, ...rule$5.meta.messages }, }, create(context) { return mergeRules(rule$6.create(context), rule$5.create(context)); }, }; const OPEN_DATABASE = 'openDatabase'; const rule$3 = { meta: { messages: { convertWebSQLUse: 'Convert this use of a Web SQL database to another technology.', }, }, create(context) { const services = context.sourceCode.parserServices; if (!isRequiredParserServices(services)) { return {}; } return { CallExpression: (node) => { const callExpression = node; const { callee } = callExpression; const symbol = getSymbolAtLocation(callee, services); if (!!symbol) { return; } if (isIdentifier(callee, OPEN_DATABASE)) { context.report({ node: callee, messageId: 'convertWebSQLUse' }); } if (callee.type !== 'MemberExpression' || !isIdentifier(callee.property, OPEN_DATABASE)) { return; } const typeName = getTypeAsString(callee.object, services); if (typeName.match(/window/i) || typeName.match(/globalThis/i)) { context.report({ node: callee, messageId: 'convertWebSQLUse' }); } }, }; }, }; const HELMET = 'helmet'; const HIDE_POWERED_BY = 'hide-powered-by'; const HEADER_X_POWERED_BY = 'X-Powered-By'.toLowerCase(); const PROTECTING_MIDDLEWARES = [HELMET, HIDE_POWERED_BY]; const APP_SET_NUM_ARGS = 2; const rule$2 = { meta: { messages: { headerSet: 'Make sure disclosing the fingerprinting of this web technology is safe here.', headerDefault: 'This framework implicitly discloses version information by default. Make sure it is safe here.', }, }, create(context) { let appInstantiation = null; let isSafe = false; let isExplicitelyUnsafe = false; return { Program() { appInstantiation = null; isSafe = false; isExplicitelyUnsafe = true; }, CallExpression: (node) => { if (!isSafe && appInstantiation) { const callExpr = node; isSafe = Express.isUsingMiddleware(context, callExpr, appInstantiation, isProtecting(context)) || isDisabledXPoweredBy(callExpr, appInstantiation) || isSetFalseXPoweredBy(callExpr, appInstantiation) || isAppEscaping(callExpr, appInstantiation); isExplicitelyUnsafe = isSetTrueXPoweredBy(callExpr, appInstantiation); } }, VariableDeclarator: (node) => { if (!isSafe && !appInstantiation) { const varDecl = node; const app = Express.attemptFindAppInstantiation(varDecl, context); if (app) { appInstantiation = app; } } }, ReturnStatement: (node) => { if (!isSafe && appInstantiation) { const ret = node; isSafe = isAppEscapingThroughReturn(ret, appInstantiation); } }, 'Program:exit'() { if (!isSafe && appInstantiation) { let messageId = 'headerDefault'; if (isExplicitelyUnsafe) { messageId = 'headerSet'; } context.report({ node: appInstantiation, messageId, }); } }, }; }, }; function isHidePoweredByFromHelmet(context, n) { if (n.type === 'CallExpression') { return getFullyQualifiedName(context, n) === `${HELMET}.hidePoweredBy`; } return false; } function isProtecting(context) { return (n) => Express.isMiddlewareInstance(context, PROTECTING_MIDDLEWARES, n) || isHidePoweredByFromHelmet(context, n); } function isDisabledXPoweredBy(callExpression, app) { if (isMethodInvocation(callExpression, app.name, 'disable', 1)) { const arg0 = callExpression.arguments[0]; return arg0.type === 'Literal' && String(arg0.value).toLowerCase() === HEADER_X_POWERED_BY; } return false; } function isSetFalseXPoweredBy(callExpression, app) { return getSetTrueXPoweredByValue(callExpression, app) === false; } function isSetTrueXPoweredBy(callExpression, app) { return getSetTrueXPoweredByValue(callExpression, app) === true; } function getSetTrueXPoweredByValue(callExpression, app) { if (isMethodInvocation(callExpression, app.name, 'set', APP_SET_NUM_ARGS)) { const [headerName, onOff] = callExpression.arguments; if (headerName.type === 'Literal' && String(headerName.value).toLowerCase() === HEADER_X_POWERED_BY && onOff.type === 'Literal') { return onOff.value; } } return undefined; } function isAppEscaping(callExpr, app) { return Boolean(callExpr.arguments.find(arg => arg.type === 'Identifier' && arg.name === app.name)); } function isAppEscapingThroughReturn(ret, app) { const arg = ret.argument; return Boolean(arg && arg.type === 'Identifier' && arg.name === app.name); } const XML_LIBRARY = 'libxmljs'; const XML_PARSERS = ['parseXml', 'parseXmlString']; const rule$1 = { meta: { schema: [ { enum: [SONAR_RUNTIME], }, ], }, create(context) { function isXmlParserCall(call) { const fqn = getFullyQualifiedName(context, call); return XML_PARSERS.some(parser => fqn === `${XML_LIBRARY}.${parser}`); } function isNoEntSet(property) { return property.value.type === 'Literal' && property.value.raw === 'true'; } return { CallExpression: (node) => { const call = node; if (isXmlParserCall(call)) { const noent = getProperty$1(call.arguments[1], 'noent', context); if (noent && isNoEntSet(noent)) { context.report({ message: toEncodedMessage$1('Disable access to external entities in XML parsing.', [ call.callee, ]), node: noent, }); } } }, }; }, }; const xpathModule = 'xpath'; const xpathEvalMethods = ['select', 'select1', 'evaluate']; const ieEvalMethods = ['selectNodes', 'SelectSingleNode']; const rule = { meta: { messages: { checkXPath: 'Make sure that executing this XPATH expression is safe.', }, }, create(context) { return { MemberExpression: (node) => { if (isMemberExpression(node, 'document', 'evaluate')) { context.report({ messageId: 'checkXPath', node }); } }, CallExpression: (node) => checkCallExpression(node, context), }; }, }; function checkCallExpression({ callee, arguments: args }, context) { if (args.length > 0 && isLiteral$2(args[0])) { return; } if (isMemberWithProperty$1(callee, ...ieEvalMethods) && args.length === 1) { context.report({ messageId: 'checkXPath', node: callee }); return; } if (isMemberWithProperty$1(callee, 'evaluate') && !isMemberExpression(callee, 'document', 'evaluate') && args.length >= 4) { const resultTypeArgument = args[3]; const argumentAsText = context.sourceCode.getText(resultTypeArgument); if (argumentAsText.includes('XPathResult')) { context.report({ messageId: 'checkXPath', node: callee }); return; } } const fqn = getFullyQualifiedName(context, callee); if (xpathEvalMethods.some(method => fqn === `${xpathModule}.${method}`)) { context.report({ messageId: 'checkXPath', node: callee }); } } const rules = {}; rules['accessor-pairs'] = rule$4D; rules['alt-text'] = rule$4C; rules['anchor-has-content'] = rule$4B; rules['anchor-is-valid'] = rule$4A; rules['anchor-precedence'] = rule$4z; rules['argument-type'] = rule$4y; rules['arguments-order'] = rule$4x; rules['arguments-usage'] = rule$4w; rules['array-callback-without-return'] = rule$4v; rules['array-constructor'] = rule$4u; rules['arrow-function-convention'] = rule$4t; rules['assertions-in-tests'] = rule$4s; rules['aws-apigateway-public-api'] = rule$4r; rules['aws-ec2-rds-dms-public'] = rule$4q; rules['aws-ec2-unencrypted-ebs-volume'] = rule$4p; rules['aws-efs-unencrypted'] = rule$4o; rules['aws-iam-all-privileges'] = rule$4n; rules['aws-iam-all-resources-accessible'] = rule$4m; rules['aws-iam-privilege-escalation'] = rule$4l; rules['aws-iam-public-access'] = rule$4k; rules['aws-opensearchservice-domain'] = rule$4j; rules['aws-rds-unencrypted-databases'] = rule$4i; rules['aws-restricted-ip-admin-access'] = rule$4h; rules['aws-s3-bucket-granted-access'] = rule$4g; rules['aws-s3-bucket-insecure-http'] = rule$4f; rules['aws-s3-bucket-public-access'] = rule$4e; rules['aws-s3-bucket-server-encryption'] = rule$4d; rules['aws-s3-bucket-versioning'] = rule$4c; rules['aws-sagemaker-unencrypted-notebook'] = rule$4b; rules['aws-sns-unencrypted-topics'] = rule$4a; rules['aws-sqs-unencrypted-queue'] = rule$49; rules['bitwise-operators'] = rule$48; rules['bool-param-default'] = rule$47; rules['brace-style'] = rule$46; rules['call-argument-line'] = rule$45; rules['certificate-transparency'] = rule$44; rules['chai-determinate-assertion'] = rule$43; rules['class-name'] = rule$42; rules['class-prototype'] = rule$41; rules['code-eval'] = rule$40; rules['comma-or-logical-or-case'] = rule$3$; rules['comment-regex'] = rule$3_; rules['concise-regex'] = rule$3Z; rules['conditional-indentation'] = rule$3Y; rules['confidential-information-logging'] = rule$3X; rules['constructor-for-side-effects'] = rule$3W; rules['content-length'] = rule$3U; rules['content-security-policy'] = rule$3T; rules['cookie-no-httponly'] = rule$3S; rules['cookies'] = rule$3R; rules['cors'] = rule$3Q; rules['csrf'] = rule$3P; rules['cyclomatic-complexity'] = rule$3O; rules['declarations-in-global-scope'] = rule$3N; rules['default-param-last'] = rule$3M; rules['deprecation'] = rule$3L; rules['destructuring-assignment-syntax'] = rule$3K; rules['different-types-comparison'] = rule$3J; rules['disabled-auto-escaping'] = rule$3I; rules['disabled-resource-integrity'] = rule$3H; rules['disabled-timeout'] = rule$3G; rules['dns-prefetching'] = rule$3F; rules['duplicates-in-character-class'] = rule$3E; rules['empty-string-repetition'] = rule$3D; rules['encryption'] = rule$3C; rules['encryption-secure-mode'] = rule$3B; rules['enforce-trailing-comma'] = rule$3A; rules['existing-groups'] = rule$3z; rules['expression-complexity'] = rule$3y; rules['file-header'] = rule$3x; rules['file-name-differ-from-class'] = rule$3w; rules['file-permissions'] = rule$3v; rules['file-uploads'] = rule$3V; rules['fixme-tag'] = rule$3t; rules['for-in'] = rule$3s; rules['for-loop-increment-sign'] = rule$3r; rules['frame-ancestors'] = rule$3q; rules['function-inside-loop'] = rule$3p; rules['function-name'] = rule$3o; rules['function-return-type'] = rule$3n; rules['future-reserved-words'] = rule$3m; rules['generator-without-yield'] = rule$3l; rules['hashing'] = rule$3k; rules['hidden-files'] = rule$3j; rules['hook-use-state'] = rule$3i; rules['html-has-lang'] = rule$3h; rules['in-operator-type-error'] = rule$3g; rules['inconsistent-function-call'] = rule$3f; rules['index-of-compare-to-positive-number'] = rule$3e; rules['insecure-cookie'] = rule$3d; rules['insecure-jwt-token'] = rule$3c; rules['inverted-assertion-arguments'] = rule$3b; rules['jsx-key'] = rule$3a; rules['jsx-no-constructed-context-values'] = rule$39; rules['jsx-no-useless-fragment'] = rule$38; rules['label-has-associated-control'] = rule$37; rules['label-position'] = rule$36; rules['link-with-target-blank'] = rule$35; rules['max-union-size'] = rule$34; rules['media-has-caption'] = rule$33; rules['misplaced-loop-counter'] = rule$32; rules['mouse-events-a11y'] = rule$31; rules['nested-control-flow'] = rule$30; rules['new-cap'] = rule$2$; rules['new-operator-misuse'] = rule$2_; rules['no-accessor-field-mismatch'] = rule$2Z; rules['no-alphabetical-sort'] = rule$2Y; rules['no-angular-bypass-sanitization'] = rule$2X; rules['no-array-delete'] = rule$2W; rules['no-array-index-key'] = rule$2V; rules['no-associative-arrays'] = rule$2U; rules['no-base-to-string'] = rule$2T; rules['no-built-in-override'] = rule$2S; rules['no-case-label-in-switch'] = rule$2R; rules['no-clear-text-protocols'] = rule$2O; rules['no-code-after-done'] = rule$2N; rules['no-commented-code'] = rule$2M; rules['no-dead-store'] = rule$2L; rules['no-delete-var'] = rule$2K; rules['no-deprecated-react'] = rule$2J; rules['no-duplicate-in-composite'] = rule$2I; rules['no-empty'] = rule$2H; rules['no-empty-after-reluctant'] = rule$2G; rules['no-empty-alternatives'] = rule$2F; rules['no-empty-function'] = rule$2E; rules['no-empty-group'] = rule$2D; rules['no-empty-interface'] = rule$2C; rules['no-empty-test-file'] = rule$2B; rules['no-equals-in-for-termination'] = rule$2A; rules['no-exclusive-tests'] = rule$2z; rules['no-extend-native'] = rule$2y; rules['no-extra-semi'] = rule$2x; rules['no-find-dom-node'] = rule$2w; rules['no-for-in-iterable'] = rule$2v; rules['no-function-declaration-in-block'] = rule$2u; rules['no-global-this'] = rule$2t; rules['no-globals-shadowing'] = rule$2s; rules['no-hardcoded-credentials'] = rule$2r; rules['no-hardcoded-ip'] = rule$2q; rules['no-hook-setter-in-body'] = rule$2p; rules['no-ignored-exceptions'] = rule$2o; rules['no-implicit-dependencies'] = rule$2n; rules['no-implicit-global'] = rule$2m; rules['no-in-misuse'] = rule$2l; rules['no-incomplete-assertions'] = rule$2k; rules['no-inconsistent-returns'] = rule$2j; rules['no-incorrect-string-concat'] = rule$2i; rules['no-infinite-loop'] = rule$2h; rules['no-intrusive-permissions'] = rule$2g; rules['no-invalid-await'] = rule$2f; rules['no-invariant-returns'] = rule$2e; rules['no-ip-forward'] = rule$2d; rules['no-labels'] = rule$2c; rules['no-literal-call'] = rule$2b; rules['no-lonely-if'] = rule$2a; rules['no-mime-sniff'] = rule$29; rules['no-misleading-array-reverse'] = rule$28; rules['no-misused-promises'] = rule$27; rules['no-mixed-content'] = rule$26; rules['no-nested-assignment'] = rule$25; rules['no-nested-conditional'] = rule$24; rules['no-nested-functions'] = rule$23; rules['no-nested-incdec'] = rule$22; rules['no-os-command-from-path'] = rule$21; rules['no-parameter-reassignment'] = rule$20; rules['no-primitive-wrappers'] = rule$1$; rules['no-redeclare'] = rule$1_; rules['no-redundant-assignments'] = rule$1Z; rules['no-redundant-optional'] = rule$1Y; rules['no-redundant-parentheses'] = rule$1X; rules['no-redundant-type-constituents'] = rule$1W; rules['no-reference-error'] = rule$1V; rules['no-referrer-policy'] = rule$1U; rules['no-require-or-define'] = rule$1T; rules['no-return-type-any'] = rule$1S; rules['no-same-argument-assert'] = rule$1R; rules['no-self-compare'] = rule$1Q; rules['no-tab'] = rule$1P; rules['no-table-as-layout'] = rule$1O; rules['no-this-alias'] = rule$1N; rules['no-throw-literal'] = rule$1M; rules['no-try-promise'] = rule$1L; rules['no-undefined-argument'] = rule$1K; rules['no-undefined-assignment'] = rule$1J; rules['no-unenclosed-multiline-block'] = rule$1I; rules['no-uniq-key'] = rule$1H; rules['no-unknown-property'] = rule$1G; rules['no-unreachable'] = rule$1F; rules['no-unsafe'] = rule$1E; rules['no-unsafe-unzip'] = rule$1D; rules['no-unstable-nested-components'] = rule$1C; rules['no-unthrown-error'] = rule$1B; rules['no-unused-expressions'] = rule$1A; rules['no-unused-function-argument'] = rule$1z; rules['no-unused-private-class-members'] = rule$1y; rules['no-useless-call'] = rule$1x; rules['no-useless-constructor'] = rule$1w; rules['no-useless-increment'] = rule$1v; rules['no-useless-intersection'] = rule$1u; rules['no-useless-react-setstate'] = rule$1t; rules['no-var'] = rule$1s; rules['no-variable-usage-before-declaration'] = rule$1r; rules['no-vue-bypass-sanitization'] = rule$1q; rules['no-weak-cipher'] = rule$1p; rules['no-weak-keys'] = rule$1o; rules['no-wildcard-import'] = rule$1n; rules['non-number-in-arithmetic-expression'] = rule$1m; rules['null-dereference'] = rule$1l; rules['object-alt-content'] = rule$1k; rules['object-shorthand'] = rule$1j; rules['operation-returning-nan'] = rule$1i; rules['os-command'] = rule$1h; rules['post-message'] = rule$1g; rules['prefer-default-last'] = rule$1f; rules['prefer-enum-initializers'] = rule$1e; rules['prefer-for-of'] = rule$1d; rules['prefer-function-type'] = rule$1c; rules['prefer-namespace-keyword'] = rule$1b; rules['prefer-nullish-coalescing'] = rule$1a; rules['prefer-object-spread'] = rule$19; rules['prefer-promise-shorthand'] = rule$18; rules['prefer-spread'] = rule$17; rules['prefer-string-starts-ends-with'] = rule$16; rules['prefer-template'] = rule$15; rules['prefer-type-guard'] = rule$14; rules['process-argv'] = rule$13; rules['production-debug'] = rule$12; rules['pseudo-random'] = rule$11; rules['public-static-readonly'] = rule$10; rules['publicly-writable-directories'] = rule$$; rules['reduce-initial-value'] = rule$_; rules['redundant-type-aliases'] = rule$Z; rules['regex-complexity'] = rule$Y; rules['regular-expr'] = rule$X; rules['rules-of-hooks'] = rule$W; rules['semi'] = rule$V; rules['session-regeneration'] = rule$U; rules['shorthand-property-grouping'] = rule$T; rules['single-char-in-character-classes'] = rule$S; rules['single-character-alternation'] = rule$R; rules['slow-regex'] = rule$Q; rules['sockets'] = rule$P; rules['sonar-block-scoped-var'] = rule$O; rules['sonar-jsx-no-leaked-render'] = rule$N; rules['sonar-max-lines'] = rule$L; rules['sonar-max-lines-per-function'] = rule$M; rules['sonar-max-params'] = rule$K; rules['sonar-no-control-regex'] = rule$J; rules['sonar-no-dupe-keys'] = rule$I; rules['sonar-no-empty-character-class'] = rule$H; rules['sonar-no-fallthrough'] = rule$G; rules['sonar-no-invalid-regexp'] = rule$F; rules['sonar-no-magic-numbers'] = rule$E; rules['sonar-no-misleading-character-class'] = rule$D; rules['sonar-no-regex-spaces'] = rule$C; rules['sonar-no-unused-class-component-methods'] = rule$B; rules['sonar-no-unused-vars'] = rule$A; rules['sonar-prefer-optional-chain'] = rule$z; rules['sonar-prefer-read-only-props'] = rule$y; rules['sonar-prefer-regexp-exec'] = rule$x; rules['sql-queries'] = rule$w; rules['stable-tests'] = rule$v; rules['standard-input'] = rule$u; rules['stateful-regex'] = rule$t; rules['strict-transport-security'] = rule$s; rules['strings-comparison'] = rule$r; rules['super-invocation'] = rule$q; rules['switch-without-default'] = rule$p; rules['table-header'] = rule$o; rules['table-header-reference'] = rule$n; rules['test-check-exception'] = rule$m; rules['todo-tag'] = rule$3u; rules['too-many-break-or-continue-in-loop'] = rule$l; rules['unicode-aware-regex'] = rule$k; rules['unnecessary-character-escapes'] = rule$j; rules['unused-import'] = rule$i; rules['unused-named-groups'] = rule$h; rules['unverified-certificate'] = rule$g; rules['unverified-hostname'] = rule$f; rules['updated-const-var'] = rule$e; rules['updated-loop-counter'] = rule$d; rules['use-isnan'] = rule$c; rules['use-type-alias'] = rule$b; rules['useless-string-operation'] = rule$a; rules['values-not-convertible-to-numbers'] = rule$9; rules['variable-name'] = rule$8; rules['void-use'] = rule$7; rules['weak-ssl'] = rule$4; rules['web-sql-database'] = rule$3; rules['x-powered-by'] = rule$2; rules['xml-parser-xxe'] = rule$1; rules['xpath'] = rule; const meta = { name, version, }; var sonar = /*#__PURE__*/Object.freeze({ __proto__: null, meta: meta, rules: rules }); const baseRules = { 'no-labels': 0, 'sonar/argument-type': 2, 'sonar/arguments-order': 2, 'sonar/array-callback-without-return': 2, 'sonar/bitwise-operators': 2, 'sonar/call-argument-line': 2, 'sonar/comma-or-logical-or-case': 2, 'sonar/code-eval': 2, 'sonar/deprecation': 1, 'sonar/different-types-comparison': 2, 'sonar/for-in': 2, 'sonar/for-loop-increment-sign': 2, 'sonar/function-inside-loop': 2, 'sonar/future-reserved-words': 1, 'sonar/generator-without-yield': 2, 'sonar/in-operator-type-error': 2, 'sonar/inconsistent-function-call': 2, 'sonar/label-position': 2, 'sonar/new-operator-misuse': [2, { considerJSDoc: false }], 'sonar/no-accessor-field-mismatch': 2, 'sonar/no-alphabetical-sort': 2, 'sonar/no-array-delete': 2, 'sonar/no-associative-arrays': 2, 'sonar/no-case-label-in-switch': 2, 'sonar/no-dead-store': 2, 'sonar/no-delete-var': 2, 'sonar/no-duplicate-in-composite': 2, 'sonar/no-equals-in-for-termination': 1, 'sonar/no-function-declaration-in-block': 1, 'sonar/no-global-this': 1, 'sonar/no-globals-shadowing': 1, 'sonar/no-implicit-global': 2, 'sonar/no-in-misuse': 2, 'sonar/no-infinite-loop': 2, 'sonar/no-invalid-await': 2, 'sonar/no-labels': 1, 'sonar/no-parameter-reassignment': 1, 'sonar/no-primitive-wrappers': 1, 'sonar/no-redundant-assignments': 1, 'sonar/no-redundant-optional': 1, 'sonar/no-try-promise': 2, 'sonar/no-undefined-argument': 1, 'sonar/no-unthrown-error': 2, 'sonar/no-useless-increment': 2, 'sonar/operation-returning-nan': 2, 'sonar/post-message': 1, 'sonar/sonar-block-scoped-var': 1, 'sonar/sonar-no-fallthrough': 1, 'sonar/sonar-no-unused-vars': 2, 'sonar/strings-comparison': 2, 'sonar/super-invocation': 2, 'sonar/unused-import': 2, 'sonar/updated-loop-counter': 1, 'sonar/useless-string-operation': 2, 'sonar/values-not-convertible-to-numbers': 1, }; const baseTsRules = { 'sonar/argument-type': 0, 'sonar/arguments-order': 0, 'sonar/array-callback-without-return': 0, 'sonar/call-argument-line': 0, 'sonar/different-types-comparison': 0, 'sonar/inconsistent-function-call': 0, 'sonar/new-operator-misuse': 0, 'sonar/no-associative-arrays': 0, 'sonar/no-gratuitous-expressions': 0, 'sonar/no-implicit-global': 0, 'sonar/no-invalid-await': 0, 'sonar/no-primitive-wrappers': 0, 'sonar/operation-returning-nan': 0, 'sonar/sonar-block-scoped-var': 0, 'sonar/sonar-no-fallthrough': 0, 'sonar/sonar-no-unused-vars': 0, 'sonar/strings-comparison': 0, 'sonar/super-invocation': 0, 'sonar/unused-import': 0, 'sonar/values-not-convertible-to-numbers': 0, }; const recommendedRules = { ...baseRules, 'sonar/array-constructor': 2, 'sonar/class-prototype': 2, 'sonar/destructuring-assignment-syntax': 2, 'sonar/function-name': [2, { format: '^_?[a-zA-Z][a-zA-Z0-9]*\\$?$' }], 'sonar/future-reserved-words': 2, 'sonar/max-union-size': [ 1, { threshold: 5, }, ], 'sonar/misplaced-loop-counter': 2, 'sonar/no-equals-in-for-termination': 2, 'sonar/no-for-in-iterable': 2, 'sonar/no-labels': 2, 'sonar/no-parameter-reassignment': 2, 'sonar/no-primitive-wrappers': 2, 'sonar/no-redundant-assignments': 2, 'sonar/no-redundant-optional': 2, 'sonar/no-return-type-any': 1, 'sonar/no-undefined-argument': 2, 'sonar/no-unused-function-argument': 1, 'sonar/no-useless-intersection': 2, 'sonar/no-variable-usage-before-declaration': 2, 'sonar/non-number-in-arithmetic-expression': 1, 'sonar/null-dereference': 2, 'sonar/prefer-default-last': 1, 'sonar/prefer-promise-shorthand': 2, 'sonar/sonar-block-scoped-var': 2, 'sonar/sonar-no-fallthrough': 2, 'sonar/updated-loop-counter': 2, 'sonar/values-not-convertible-to-numbers': 2, }; const recommendedTsRules = { ...baseTsRules, 'sonar/array-constructor': 0, 'sonar/no-unused-function-argument': 0, 'sonar/class-prototype': 0, 'sonar/no-for-in-iterable': 0, 'sonar/no-variable-usage-before-declaration': 0, 'sonar/non-number-in-arithmetic-expression': 0, 'sonar/null-dereference': 0, 'sonar/sonar-block-scoped-var': 0, }; const tsPatterns = ['**/*.{cts,mts,ts,tsx}']; const base = { plugins: ['sonar'], rules: baseRules, overrides: [ { files: tsPatterns, rules: baseTsRules, }, ], }; const recommended = { ...base, rules: recommendedRules, overrides: [ ...base.overrides, { files: tsPatterns, rules: recommendedTsRules, }, ], }; const flatBase = [ { plugins: { sonar, }, rules: baseRules, }, { files: tsPatterns, plugins: { sonar, }, rules: baseTsRules, }, ]; const flatRecommended = [ { plugins: { sonar, }, rules: recommendedRules, }, { files: tsPatterns, plugins: { sonar, }, rules: recommendedTsRules, }, ]; var configs = /*#__PURE__*/Object.freeze({ __proto__: null, base: base, flatBase: flatBase, flatRecommended: flatRecommended, recommended: recommended }); exports.baseRules = baseRules; exports.baseTsRules = baseTsRules; exports.configs = configs; exports.meta = meta; exports.recommendedRules = recommendedRules; exports.recommendedTsRules = recommendedTsRules; exports.rules = rules; //# sourceMappingURL=index.cjs.map