"use strict";
/**
 * Math.random() Detection
 *
 * Context-aware detection of Math.random() usage with intelligent severity
 * classification based on usage context, variable names, and function intent.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.isJitterOrBackoffContext = isJitterOrBackoffContext;
exports.isReactKeyPattern = isReactKeyPattern;
exports.isCosmeticMathRandom = isCosmeticMathRandom;
exports.classifyFunctionIntent = classifyFunctionIntent;
exports.analyzeToStringPattern = analyzeToStringPattern;
exports.extractMathRandomVariableName = extractMathRandomVariableName;
exports.classifyVariableNameRisk = classifyVariableNameRisk;
exports.analyzeMathRandomContext = analyzeMathRandomContext;
exports.isAnimationFile = isAnimationFile;
exports.isAnimationCoordinateUsage = isAnimationCoordinateUsage;
exports.isTemplatePlaceholderGenerator = isTemplatePlaceholderGenerator;
exports.shouldSkipMathRandom = shouldSkipMathRandom;
const context_helpers_1 = require("../../utils/context-helpers");
const control_flow_1 = require("./utils/control-flow");
/**
 * Check if Math.random() is used in a jitter/backoff/retry context
 * These are legitimate uses of Math.random() for network resilience,
 * not security-sensitive randomness.
 *
 * Examples:
 *   const delay = baseDelay + Math.random() * jitter
 *   setTimeout(retry, delay * Math.random())
 *   await sleep(backoff * (1 + Math.random() * 0.1))
 *
 * @param content - Full file content
 * @param lineNumber - The 0-indexed line number where Math.random() was found
 */
function isJitterOrBackoffContext(content, lineNumber, lines) {
    const _lines = lines ?? content.split('\n');
    const start = Math.max(0, lineNumber - 10);
    const end = Math.min(_lines.length, lineNumber + 5);
    const context = _lines.slice(start, end).join('\n');
    // Patterns indicating jitter/backoff/retry context
    const jitterPatterns = [
        // Direct keyword matches
        /\b(jitter|backoff|retry|retries|exponential)\b/i,
        // Delay/timeout with random
        /setTimeout.*Math\.random/i,
        /setInterval.*Math\.random/i,
        /sleep.*Math\.random/i,
        /await.*delay.*Math\.random/i,
        // Common backoff patterns
        /\* Math\.random\(\).*delay/i,
        /delay\s*\*\s*Math\.random/i,
        /Math\.random\(\)\s*\*\s*\d+.*delay/i,
        // Retry-related function names
        /function\s+(retry|withRetry|backoff|withBackoff|exponentialBackoff)/i,
        // Common retry library patterns
        /retryPolicy|retryConfig|retryOptions|maxRetries|retryCount/i,
        // Network resilience patterns
        /\b(throttle|debounce|rateLimit)\b.*Math\.random/i,
        // Sampling/probability for non-security uses
        /sampleRate|samplingRate|probability\s*[<>]=?\s*Math\.random/i,
    ];
    return jitterPatterns.some(p => p.test(context));
}
/**
 * Check if Math.random() is used in a React key prop context
 * This is a common pattern to force re-renders, not a security issue.
 *
 * Examples:
 *   key={Math.random()}
 *   key={`prefix-${Math.random()}`}
 *   key={Math.random().toString()}
 *
 * @param lineContent - The line of code to check
 * @param filePath - The file path (only check JSX/TSX files)
 */
function isReactKeyPattern(lineContent, filePath) {
    // Only check in JSX/TSX files
    if (!/\.[jt]sx$/.test(filePath)) {
        return false;
    }
    // Pattern: key={...Math.random()...}
    // Matches:
    //   key={Math.random()}
    //   key={`foo-${Math.random()}`}
    //   key={Math.random().toString()}
    //   key={`${Math.random()}-bar`}
    //   key={something + Math.random()}
    const keyPattern = /key\s*=\s*\{[^}]*Math\.random\(\)/;
    return keyPattern.test(lineContent);
}
/**
 * Check if Math.random() is used for cosmetic/UI purposes (not security)
 * Cosmetic uses: CSS values, animations, UI variations, demo data
 * Security uses: tokens, IDs, cryptographic operations, session management
 */
function isCosmeticMathRandom(lineContent, content, lineNumber, lines) {
    const _lines = lines ?? content.split('\n');
    // Check the line itself for cosmetic indicators
    const cosmeticLinePatterns = [
        // CSS/style values
        /['"`]\s*\$\{.*Math\.random.*\}\s*%['"`]/, // `${Math.random() * 40 + 50}%`
        /Math\.random.*\s*\+\s*['"`]%['"`]/, // Math.random() * 40 + '%'
        /Math\.random.*\)\s*\*\s*\d+\s*\+\s*\d+\s*\}\s*%/, // }) * 40 + 50}%
        /return\s+`.*Math\.random.*%`/, // return `${...}%`
        /width:\s*['"`].*Math\.random/i, // width: `${Math.random()...}%`
        /height:\s*['"`].*Math\.random/i, // height: `${Math.random()...}%`
        /opacity:\s*['"`]?.*Math\.random/i, // opacity: Math.random()
        /transform:\s*['"`]?.*Math\.random/i, // transform: translate(...)
        /rotate\(.*Math\.random/i, // rotate(Math.random() * 360)
        /translate\(.*Math\.random/i, // translate(Math.random() * 100)
        /scale\(.*Math\.random/i, // scale(Math.random() * 2)
        // Color/animation values
        /rgba?\(.*Math\.random/i, // rgb(Math.random() * 255, ...)
        /hsl\(.*Math\.random/i, // hsl(Math.random() * 360, ...)
        /Math\.random.*\*\s*360/, // Math.random() * 360 (degrees/hue)
        /Math\.random.*\*\s*255/, // Math.random() * 255 (RGB values)
        // Array/list randomization for UI
        /Math\.floor\(Math\.random.*\.length\)/, // Math.floor(Math.random() * array.length)
        /\[Math\.floor\(Math\.random/, // array[Math.floor(Math.random()...)]
        // Demo/placeholder data
        /Math\.random.*\*\s*\d+\s*\+\s*\d+.*\bpx\b/i, // Math.random() * 100 + 50 + 'px'
        /Math\.random.*\*\s*\d+\s*\+\s*\d+.*\bms\b/i, // Math.random() * 1000 + 500 + 'ms'
        /Math\.random.*\*\s*\d+\s*\+\s*\d+.*\bs\b/i, // Math.random() * 5 + 2 + 's'
        // NOTE: toString patterns removed - now handled by analyzeToStringPattern()
        // which provides more granular severity classification (info/low/medium/high)
        // based on truncation length and context
    ];
    if (cosmeticLinePatterns.some(p => p.test(lineContent))) {
        return true;
    }
    // Check surrounding context (5 lines before and after)
    const contextStart = Math.max(0, lineNumber - 5);
    const contextEnd = Math.min(_lines.length, lineNumber + 5);
    const context = _lines.slice(contextStart, contextEnd).join('\n');
    // Context indicators of cosmetic use
    const cosmeticContextPatterns = [
        // UI component files - REMOVED, let severity classification handle these
        // Style-related variables/functions
        /\b(style|styles|css|className|animation|transition)/i,
        /\b(width|height|opacity|color|transform|rotate|scale|translate)/i,
        // Demo/example data
        /\b(demo|example|placeholder|mock|fake|sample|test)Data/i,
        /\b(random|shuffle|pick|choose).*\b(color|item|element|option)/i,
        // Animation/timing
        /setTimeout.*Math\.random/i,
        /setInterval.*Math\.random/i,
        /delay.*Math\.random/i,
        /duration.*Math\.random/i,
        // UI state variations
        /\b(variant|theme|layout|position).*Math\.random/i,
        // NOTE: Removed UI identifier patterns (key, id, tempId, etc.) - these should be
        // classified with info/low severity by the severity classification logic, not skipped entirely
    ];
    if (cosmeticContextPatterns.some(p => p.test(context))) {
        return true;
    }
    // Security-sensitive patterns that override cosmetic detection
    const securityPatterns = [
        /\b(token|secret|key|password|credential|signature)/i,
        /\b(auth|crypto|encrypt|decrypt|hash)/i,
        /\b(session|nonce|salt)\b/i,
        /Math\.random.*\*\s*1e\d+/, // Math.random() * 1e16 (large numbers for IDs)
    ];
    if (securityPatterns.some(p => p.test(lineContent) || p.test(context))) {
        return false; // Not cosmetic - this is security-sensitive
    }
    // Check for .toString(36) WITHOUT substring/slice/substr (security token pattern)
    // If it has substring/slice/substr, it's already caught by cosmeticLinePatterns above
    const hasToString36WithoutTruncation = /Math\.random\(\)\.toString\(36\)/.test(lineContent) &&
        !/\.(substring|substr|slice)\(/.test(lineContent);
    const hasToString16WithoutTruncation = /Math\.random\(\)\.toString\(16\)/.test(lineContent) &&
        !/\.(substring|substr|slice)\(/.test(lineContent);
    if (hasToString36WithoutTruncation || hasToString16WithoutTruncation) {
        return false; // Full-length toString() without truncation - likely security token
    }
    return false; // Default to flagging if unclear
}
/**
 * Classify function intent based on function name
 * Used to determine if Math.random() usage is legitimate
 */
function classifyFunctionIntent(functionName) {
    if (!functionName)
        return 'unknown';
    const lower = functionName.toLowerCase();
    // UUID/ID generation (UI correlation, not security)
    // Check for specific UUID patterns and generic ID generation functions
    const uuidPatterns = ['uuid', 'guid', 'uniqueid', 'correlationid', 'tempid', 'temp_id'];
    // Match patterns like generateId, generateTempId, createId, etc.
    const idGenerationPatterns = /^(generate|create|make|build)(\w*)?(id|identifier)$/i;
    if (uuidPatterns.some(p => lower.includes(p)) ||
        idGenerationPatterns.test(lower)) {
        return 'uuid';
    }
    // CAPTCHA/puzzle generation (legitimate non-security)
    const captchaPatterns = ['captcha', 'puzzle', 'mathproblem'];
    // Also check for 'challenge' but only if not in security context
    if (captchaPatterns.some(p => lower.includes(p)))
        return 'captcha';
    if (lower.includes('challenge') && !lower.includes('auth'))
        return 'captcha';
    // Demo/seed/fixture data
    const demoPatterns = ['seed', 'fixture', 'demo', 'mock', 'fake'];
    if (demoPatterns.some(p => lower.includes(p)))
        return 'demo';
    // Security-sensitive (check this after id generation to avoid false positives)
    const securityPatterns = [
        'token',
        'secret',
        'key',
        'password',
        'credential',
        'signature',
    ];
    // Also match generate/create + security term combinations
    const securityFunctionPattern = /^(generate|create|make)(token|secret|key|session|password|credential)/i;
    if (securityPatterns.some(p => lower.includes(p)) ||
        securityFunctionPattern.test(lower)) {
        return 'security';
    }
    return 'unknown';
}
/**
 * Analyze toString() pattern in Math.random() usage
 * Determines intent based on base and truncation length
 */
function analyzeToStringPattern(lineContent) {
    const toString36Match = lineContent.match(/Math\.random\(\)\.toString\(36\)/);
    const toString16Match = lineContent.match(/Math\.random\(\)\.toString\(16\)/);
    if (!toString36Match && !toString16Match) {
        return {
            hasToString: false,
            base: null,
            isTruncated: false,
            truncationLength: null,
            intent: 'unknown',
        };
    }
    const base = toString36Match ? 36 : 16;
    // Check for truncation methods
    const substringMatch = lineContent.match(/\.substring\((\d+)(?:,\s*(\d+))?\)/);
    const sliceMatch = lineContent.match(/\.slice\((\d+)(?:,\s*(\d+))?\)/);
    const substrMatch = lineContent.match(/\.substr\((\d+)(?:,\s*(\d+))?\)/);
    const truncMatch = substringMatch || sliceMatch || substrMatch;
    if (!truncMatch) {
        return {
            hasToString: true,
            base,
            isTruncated: false,
            truncationLength: null,
            intent: 'full-token',
        };
    }
    // Calculate truncation length
    const start = parseInt(truncMatch[1]);
    const end = truncMatch[2] ? parseInt(truncMatch[2]) : null;
    // If no end specified (e.g., .substring(7)), the result is from start to end of string
    // Math.random().toString(36) produces ~11 chars like "0.abc123def"
    // .substring(2) gives ~9 chars, .substring(7) gives ~4 chars
    // Estimate remaining length: ~11 - start
    const estimatedFullLength = 11;
    const length = end ? end - start : (start >= 2 ? estimatedFullLength - start : null);
    // Classify intent by length
    // Short (2-9 chars): UI correlation IDs, React keys
    // Medium (10-15 chars): Business IDs, order numbers
    if (length && length <= 9) {
        return {
            hasToString: true,
            base,
            isTruncated: true,
            truncationLength: length,
            intent: 'short-ui-id',
        };
    }
    else if (length && length <= 15) {
        return {
            hasToString: true,
            base,
            isTruncated: true,
            truncationLength: length,
            intent: 'business-id',
        };
    }
    else {
        return {
            hasToString: true,
            base,
            isTruncated: true,
            truncationLength: length,
            intent: 'business-id',
        };
    }
}
/**
 * Extract variable name from Math.random() assignment
 * Examples:
 *   const token = Math.random() -> "token"
 *   const businessId = Math.random().toString(36) -> "businessId"
 *   return Math.random() -> null (no variable)
 */
function extractMathRandomVariableName(lineContent) {
    // const/let/var variableName = Math.random...
    const assignmentMatch = lineContent.match(/(?:const|let|var)\s+(\w+)\s*=.*Math\.random/);
    if (assignmentMatch)
        return assignmentMatch[1];
    // object.property = Math.random...
    const propertyMatch = lineContent.match(/(\w+)\s*[:=]\s*Math\.random/);
    if (propertyMatch)
        return propertyMatch[1];
    // function parameter default: functionName(param = Math.random())
    const paramMatch = lineContent.match(/(\w+)\s*=\s*Math\.random/);
    if (paramMatch)
        return paramMatch[1];
    return null; // No variable name found
}
/**
 * Classify variable name security risk based on naming patterns
 *
 * High risk: Security-sensitive names (token, secret, key, etc.)
 * Medium risk: Unclear context
 * Low risk: Non-security names (id, businessId, orderId, etc.)
 */
function classifyVariableNameRisk(varName) {
    if (!varName)
        return 'medium'; // Unknown usage, moderate risk
    const lower = varName.toLowerCase();
    // High risk: security-sensitive variable names
    // Note: 'key' alone is NOT included - it often means React key, not crypto key
    // Instead, we match specific security key patterns
    const highRiskPatterns = [
        'token',
        'secret',
        'password',
        'credential',
        'signature',
        'salt',
        'nonce',
        'session',
        'csrf',
        'auth',
        'apikey',
        'secretkey',
        'privatekey',
        'encryptionkey',
        'accesstoken',
        'refreshtoken',
        'jwt',
        'bearer',
        'oauth',
        'sessionid',
    ];
    if (highRiskPatterns.some(p => lower.includes(p))) {
        return 'high';
    }
    // Low risk: clearly non-security contexts
    const lowRiskPatterns = [
        // Business identifiers
        'id',
        'uid',
        'guid',
        'business',
        'order',
        'invoice',
        'customer',
        'user',
        'product',
        'item',
        'transaction',
        'request',
        'reference',
        'tracking',
        'confirmation',
        // Test/demo data
        'test',
        'mock',
        'demo',
        'sample',
        'example',
        'fixture',
        'random',
        'temp',
        'temporary',
        'generated',
        'dummy',
        // UI identifiers (checked after high-risk, so 'apikey' etc. already caught)
        'key',
        'toast',
        'notification',
        'element',
        'component',
        'widget',
        'modal',
        'dialog',
        'popup',
        'unique',
        'react',
        // Non-security randomness usage (backoff/sampling/experiments)
        'jitter',
        'retry',
        'backoff',
        'delay',
        'timeout',
        'latency',
        'sample',
        'sampling',
        'probability',
        'chance',
        'rollout',
        'experiment',
        'abtest',
        'cohort',
        'bucket',
        'variant',
    ];
    if (lowRiskPatterns.some(p => lower.includes(p))) {
        return 'low';
    }
    return 'medium'; // Unclear context, moderate risk
}
/**
 * Analyze surrounding code context for security signals
 * Returns context type and description for severity classification
 */
function analyzeMathRandomContext(content, filePath, lineNumber, lines) {
    const _lines = lines ?? content.split('\n');
    const start = Math.max(0, lineNumber - 10);
    const end = Math.min(_lines.length, lineNumber + 5);
    const context = _lines.slice(start, end).join('\n');
    // Security context indicators (functions, imports, comments)
    const securityPatterns = [
        /\b(generate|create)(Token|Secret|Key|Password|Nonce|Salt|Session|Signature)/i,
        /\b(auth|crypto|encrypt|decrypt|hash|sign)\b/i,
        /function\s+.*(?:token|secret|key|auth|crypto)/i,
        /\bimport.*(?:crypto|jsonwebtoken|bcrypt|argon2|jose)/i,
        /\/\*.*(?:security|authentication|cryptograph|authorization)/i,
        /\/\/.*(?:security|auth|crypto|token|secret)/i,
    ];
    const inSecurityContext = securityPatterns.some(p => p.test(context));
    // Test context
    const testFilePatterns = /\.(test|spec)\.(ts|tsx|js|jsx)$/i;
    const testContextPatterns = [
        /\b(describe|it|test|expect|mock|jest|vitest|mocha|chai)\b/i,
        /\b(beforeEach|afterEach|beforeAll|afterAll)\b/i,
        /\b(fixture|stub|spy)\b/i,
    ];
    const inTestContext = testFilePatterns.test(filePath) ||
        testContextPatterns.some(p => p.test(context));
    // UI/cosmetic context (reuse existing logic)
    const lineContent = _lines[lineNumber];
    const inUIContext = isCosmeticMathRandom(lineContent, content, lineNumber, _lines);
    // Business logic context (non-security ID generation)
    // Note: UUID/CAPTCHA patterns excluded - handled by functionIntent classification
    const businessLogicPatterns = [
        /\b(business|order|invoice|customer|product|transaction)Id\b/i,
        /\b(reference|tracking|confirmation)Number\b/i,
        /\b(backoff|retry|jitter|delay|timeout|latency)\b/i,
        /\b(sample|sampling|probability|chance|rollout|experiment|abtest|cohort|bucket|variant)\b/i,
        // Load balancing and selection patterns
        /mode\s*===?\s*['"]random['"]/i, // mode === 'random'
        /\.\w*index\s*%/i, // round-robin patterns
        /keys?\[.*Math\.random/i, // keys[Math.floor(Math.random() * keys.length)]
        /\[\s*Math\.floor\s*\(\s*Math\.random/i, // array[Math.floor(Math.random()...)]
        /shuffle/i, // shuffle functions
        /pickRandom/i, // pickRandom helpers
        /randomElement/i, // randomElement helpers
    ];
    const inBusinessLogicContext = businessLogicPatterns.some(p => p.test(context)) && !inSecurityContext;
    // Determine context description
    let contextDescription = 'unknown context';
    if (inSecurityContext) {
        contextDescription = 'security-sensitive function';
    }
    else if (inTestContext) {
        contextDescription = 'test/mock data generation';
    }
    else if (inUIContext) {
        contextDescription = 'UI/cosmetic usage';
    }
    else if (inBusinessLogicContext) {
        contextDescription = 'non-security usage';
    }
    return {
        inSecurityContext,
        inTestContext,
        inUIContext,
        inBusinessLogicContext,
        contextDescription,
    };
}
/**
 * Check if file is an animation/motion component based on file name
 * Files with animation-related names typically use Math.random for visual effects
 */
function isAnimationFile(filePath) {
    const animationPatterns = [
        /animated[-_]/i, // animated-document-scanner.tsx
        /[-_]animation/i, // document-animation.tsx
        /motion[-_]/i, // motion-component.tsx
        /[-_]motion/i, // scroll-motion.tsx
        /particles?[-_]/i, // particles-background.tsx
        /confetti/i, // confetti.tsx
        /[-_]effect/i, // hover-effect.tsx
        /transition[-_]/i, // transition-wrapper.tsx
        /visual[-_]/i, // visual-effects.tsx
        /canvas[-_]/i, // canvas-animation.tsx
    ];
    return animationPatterns.some(p => p.test(filePath));
}
/**
 * Check if Math.random() is used for animation/motion coordinates
 * Common in animation libraries like framer-motion, react-spring, Three.js, etc.
 */
function isAnimationCoordinateUsage(lineContent, context) {
    // Object property assignments for coordinates
    const coordinatePatterns = [
        /\bx:\s*Math\.random/i, // x: Math.random()
        /\by:\s*Math\.random/i, // y: Math.random()
        /\bz:\s*Math\.random/i, // z: Math.random()
        /\bleft:\s*.*Math\.random/i, // left: Math.random()
        /\btop:\s*.*Math\.random/i, // top: Math.random()
        /\bright:\s*.*Math\.random/i, // right: Math.random()
        /\bbottom:\s*.*Math\.random/i, // bottom: Math.random()
        /\brotation:\s*.*Math\.random/i, // rotation: Math.random()
        /\brotateX:\s*.*Math\.random/i, // rotateX: Math.random()
        /\brotateY:\s*.*Math\.random/i, // rotateY: Math.random()
        /\brotateZ:\s*.*Math\.random/i, // rotateZ: Math.random()
        /\bscaleX?:\s*.*Math\.random/i, // scale/scaleX: Math.random()
        /\bscaleY:\s*.*Math\.random/i, // scaleY: Math.random()
        /\bopacity:\s*.*Math\.random/i, // opacity: Math.random()
        /\bduration:\s*.*Math\.random/i, // duration: Math.random()
        /\bdelay:\s*.*Math\.random/i, // delay: Math.random()
        // 3D/Three.js specific patterns
        /\boffset\s*=.*Math\.random/i, // offset = Math.random()
        /useMemo\s*\(\s*\(\s*\)\s*=>\s*Math\.random/i, // useMemo(() => Math.random(), [])
        /\bphase\s*[:=].*Math\.random/i, // phase: Math.random() or phase = Math.random()
        /\bspeed\s*[:=].*Math\.random/i, // speed: Math.random()
        /\bangle\s*[:=].*Math\.random/i, // angle: Math.random()
    ];
    if (coordinatePatterns.some(p => p.test(lineContent))) {
        return true;
    }
    // Motion/animation library context patterns
    const motionLibraryPatterns = [
        /framer-motion/i,
        /react-spring/i,
        /react-motion/i,
        /gsap/i,
        /animejs/i,
        /popmotion/i,
        /motion\.div/i,
        /useSpring/i,
        /useAnimation/i,
        /animate\s*\(/i,
        /keyframes/i,
        // Three.js and React Three Fiber patterns
        /three/i,
        /useFrame/i,
        /@react-three/i,
        /Canvas/i, // React Three Fiber Canvas
        /mesh/i, // Three.js mesh
        /geometry/i, // Three.js geometry
        /material/i, // Three.js material
    ];
    return motionLibraryPatterns.some(p => p.test(context));
}
/**
 * Check if Math.random() is used in a template placeholder generator context
 * Template systems often use random generators for placeholder values
 *
 * Examples:
 *   const templates = { random: () => Math.random().toString() }
 *   random_hex: () => Math.random().toString(16)
 *   {{random}} placeholder generation
 */
function isTemplatePlaceholderGenerator(line, content, lineNumber, lines) {
    const _lines = lines ?? content.split('\n');
    const contextStart = Math.max(0, lineNumber - 10);
    const contextEnd = Math.min(_lines.length, lineNumber + 5);
    const context = _lines.slice(contextStart, contextEnd).join('\n');
    const templatePatterns = [
        /\{\{random\w*\}\}/i, // {{random}}, {{random_hex}}, etc.
        /random:\s*\(\s*\)\s*=>\s*Math\.random/i, // random: () => Math.random()
        /random_\w+:\s*\(\s*\)\s*=>/i, // random_int: () => ...
        /placeholder.*random/i, // placeholder context
        /templates?\s*[=:]\s*\{/i, // templates = { or template: {
        /generatePlaceholder/i, // generatePlaceholder function
        /placeholder\s*[:=]/i, // placeholder: or placeholder =
    ];
    return templatePatterns.some(p => p.test(context) || p.test(line));
}
/**
 * Check if Math.random() should be skipped entirely
 * Returns true for seed files, test fixtures, captcha/puzzle, uuid, React keys, jitter/backoff, and pure cosmetic uses
 */
function shouldSkipMathRandom(content, filePath, lineNumber, options) {
    // Seed/data generation files - skip entirely
    if ((0, context_helpers_1.isSeedOrDataGenFile)(filePath)) {
        return true;
    }
    // Animation/motion component files - skip entirely
    // These use Math.random for visual effects, not security
    if (isAnimationFile(filePath)) {
        return true;
    }
    // Educational/intentional vulnerability files - skip entirely
    // These include OWASP Juice Shop, intentionally-vulnerable examples, etc.
    if ((0, context_helpers_1.isEducationalVulnerabilityFile)(filePath)) {
        return true;
    }
    // Check for React key pattern - this is a common pattern to force re-renders
    // It's not a security issue, just a way to reset component state
    const lines = options?.parsed?.lines ?? content.split('\n');
    const lineContent = lines[lineNumber] || '';
    if (isReactKeyPattern(lineContent, filePath)) {
        return true;
    }
    // Template placeholder generators - skip entirely
    // These generate placeholder values for templates, not security tokens
    if (isTemplatePlaceholderGenerator(lineContent, content, lineNumber, lines)) {
        return true;
    }
    // Jitter/backoff/retry patterns - legitimate non-security use of randomness
    // Used for network resilience, rate limiting, exponential backoff, etc.
    if (isJitterOrBackoffContext(content, lineNumber, lines)) {
        return true;
    }
    // Test files with test fixture patterns
    if ((0, context_helpers_1.isTestOrMockFile)(filePath)) {
        const line = lines[lineNumber];
        // If in a test file and generating test data, skip
        if (/\b(mock|fake|fixture|test)Data/i.test(line) ||
            /\b(it|test|describe)\s*\(/.test(line)) {
            return true;
        }
    }
    // Pure cosmetic usage (CSS values, animations)
    if (isCosmeticMathRandom(lineContent, content, lineNumber, lines)) {
        // Additional check: if this is for animation/style, truly skip
        const pureStylePatterns = [
            /\.style\./,
            /animation/i,
            /transform/i,
            /opacity/i,
            /\brgb/i,
            /\bhsl/i,
        ];
        if (pureStylePatterns.some(p => p.test(lineContent))) {
            return true;
        }
    }
    // Animation coordinate usage (x, y, rotation, etc.)
    // Get surrounding context for animation library detection
    const contextStart = Math.max(0, lineNumber - 15);
    const contextEnd = Math.min(lines.length, lineNumber + 5);
    const animContext = lines.slice(contextStart, contextEnd).join('\n');
    if (isAnimationCoordinateUsage(lineContent, animContext)) {
        return true;
    }
    // Check function context for demo/seed/captcha/uuid functions
    const functionName = (0, control_flow_1.extractFunctionContext)(content, lineNumber);
    const functionIntent = classifyFunctionIntent(functionName);
    // Skip demo, captcha, and uuid functions entirely - these are legitimate uses
    if (functionIntent === 'demo' || functionIntent === 'captcha' || functionIntent === 'uuid') {
        return true;
    }
    // Check for fallback pattern: crypto.randomUUID?.() ?? Math.random()
    // When a secure primary method is used with Math.random as fallback,
    // the code is safe (Math.random only runs in environments without crypto API)
    const prevLines = lines.slice(Math.max(0, lineNumber - 2), lineNumber + 1).join(' ');
    const multiLineFallbackPatterns = [
        /crypto\??\.?\s*randomUUID\??\.?\s*\(\s*\)\s*\?\?/i, // crypto.randomUUID() ??
        /globalThis\.crypto\??\.?\s*randomUUID\??\.?\s*\(/i, // globalThis.crypto?.randomUUID?.()
        /window\.crypto\??\.?\s*randomUUID\??\.?\s*\(/i, // window.crypto?.randomUUID?.()
        /\?\.\s*randomUUID\??\.?\s*\(\s*\)\s*\?\?/i, // ?.randomUUID?.() ??
        /crypto\??\.?\s*getRandomValues\s*\(/i, // crypto.getRandomValues()
        /randomUUID\??\.?\s*\(\s*\)\s*\?\?/i, // randomUUID?.() ?? (generic)
    ];
    if (multiLineFallbackPatterns.some(p => p.test(prevLines))) {
        return true; // Skip - Math.random is only a fallback for missing crypto API
    }
    return false;
}
//# sourceMappingURL=math-random.js.map