"use strict";
/**
 * Layer 2: AI Package Hallucination Detection
 * Detects AI-hallucinated and potentially fake package names in imports
 *
 * Background: USENIX research shows ~20% of AI-generated code references
 * packages that don't exist, creating supply chain attack vectors. Attackers
 * can register these fake package names and inject malicious code.
 *
 * Detection Strategy:
 * 1. Known hallucinations database (verified fake packages)
 * 2. Heuristic patterns (suspicious naming conventions)
 * 3. Generic unscoped names that are too vague to be real
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.detectAIPackageHallucination = detectAIPackageHallucination;
const context_helpers_1 = require("../utils/context-helpers");
// ============================================================================
// Known Hallucinated Package Database
// ============================================================================
/**
 * Verified fake package names from research and real-world observations
 * These are packages that LLMs frequently suggest but don't exist (or are typosquats)
 */
const KNOWN_HALLUCINATED_PACKAGES = new Set([
    // JavaScript/TypeScript - from USENIX research and observation
    'react-charts', // Real: recharts, react-chartjs-2
    'mongo-client', // Real: mongodb
    'postgres-client', // Real: pg, postgres
    'fast-json', // Real: fast-json-stringify
    'node-helpers', // Doesn't exist
    'node-utils', // Doesn't exist
    'easy-utils', // Doesn't exist
    'simple-tools', // Doesn't exist
    'csv-parser-pro', // Real: csv-parser, papaparse
    'express-jwt-auth', // Real: express-jwt, passport-jwt
    'mongoose-connect', // Real: mongoose
    'redis-connect', // Real: redis, ioredis
    'graphql-tools-schema', // Real: @graphql-tools/schema
    'aws-s3-client', // Real: @aws-sdk/client-s3
    'google-cloud-storage', // Real: @google-cloud/storage (scoped)
    'firebase-auth-client', // Real: firebase, firebase-admin
    'stripe-payments', // Real: stripe
    'twilio-sms', // Real: twilio
    'sendgrid-email', // Real: @sendgrid/mail
    'mailchimp-api', // Real: @mailchimp/mailchimp_marketing
    'slack-bot', // Real: @slack/bolt, @slack/web-api
    'discord-bot', // Real: discord.js
    'telegram-bot', // Real: telegraf, node-telegram-bot-api
    'jwt-decode-verify', // Real: jsonwebtoken, jose
    'bcrypt-hash', // Real: bcrypt, bcryptjs
    'uuid-generate', // Real: uuid
    'date-formatter', // Real: date-fns, dayjs, moment
    'image-resize', // Real: sharp, jimp
    'pdf-generator', // Real: pdfkit, pdf-lib
    'excel-parser', // Real: xlsx, exceljs
    'xml-parser-pro', // Real: fast-xml-parser, xml2js
    'yaml-parser', // Real: js-yaml, yaml
    // Python hallucinated packages
    'easy-flask', // Real: flask
    'simple-api', // Real: fastapi, flask
    'fast-db', // Real: sqlalchemy, databases
    'python-helpers', // Doesn't exist
    'django-helpers', // Doesn't exist
    'flask-helpers', // Doesn't exist
    'numpy-utils', // Doesn't exist
    'pandas-helpers', // Doesn't exist
    'data-parser', // Real: pandas
    'ml-utils', // Doesn't exist
    'ai-tools', // Doesn't exist
]);
/**
 * Well-known legitimate packages to avoid false positives
 */
const KNOWN_LEGITIMATE_PACKAGES = new Set([
    // Core/popular JS packages
    'react', 'vue', 'angular', 'svelte', 'solid-js',
    'express', 'fastify', 'hono', 'koa', 'nest',
    'next', 'nuxt', 'remix', 'astro', 'gatsby',
    'axios', 'fetch', 'got', 'ky', 'superagent',
    'lodash', 'underscore', 'radash', 'ramda',
    'zod', 'joi', 'yup', 'ajv', 'valibot',
    'dayjs', 'date-fns', 'moment', 'luxon',
    'mongodb', 'mongoose', 'pg', 'mysql2', 'better-sqlite3',
    'prisma', 'drizzle-orm', 'typeorm', 'sequelize', 'knex',
    'redis', 'ioredis',
    'bcrypt', 'bcryptjs', 'argon2',
    'jsonwebtoken', 'jose', 'passport',
    'uuid', 'nanoid', 'cuid', 'ulid',
    'sharp', 'jimp', 'canvas',
    'pdfkit', 'pdf-lib',
    'xlsx', 'exceljs',
    'cheerio', 'puppeteer', 'playwright',
    'winston', 'pino', 'bunyan',
    'dotenv', 'config', 'convict',
    'chalk', 'picocolors', 'kleur',
    'commander', 'yargs', 'meow', 'cac',
    'inquirer', 'prompts',
    'glob', 'fast-glob', 'globby',
    'chokidar', 'nodemon',
    'esbuild', 'vite', 'webpack', 'rollup', 'parcel',
    'jest', 'vitest', 'mocha', 'ava', 'tape',
    'eslint', 'prettier', 'biome',
    'typescript', 'ts-node', 'tsx',
    'openai', 'anthropic',
    'stripe', 'paypal',
    'twilio', 'nodemailer',
    'aws-sdk',
    'firebase', 'firebase-admin',
    'supabase',
    'graphql', 'apollo-server', 'urql',
    'socket.io', 'ws',
    'bullmq', 'bee-queue',
    'csv-parser', 'papaparse',
    'fast-xml-parser', 'xml2js',
    'js-yaml', 'yaml',
    // Real 'simple-' packages
    'simple-git', 'simpl-schema',
    // Real 'fast-' packages
    'fast-json-stringify', 'fastify', 'fast-glob', 'fast-deep-equal', 'fast-xml-parser',
    // Python packages
    'flask', 'django', 'fastapi', 'starlette', 'tornado',
    'requests', 'httpx', 'aiohttp',
    'numpy', 'pandas', 'scipy', 'matplotlib',
    'scikit-learn', 'tensorflow', 'pytorch', 'keras',
    'sqlalchemy', 'alembic', 'psycopg2', 'asyncpg',
    'celery', 'redis', 'dramatiq',
    'pydantic', 'marshmallow',
    'pytest', 'unittest', 'nose',
    'black', 'flake8', 'mypy', 'ruff',
    'boto3', 'botocore',
    'pillow', 'opencv-python',
    'beautifulsoup4', 'lxml', 'scrapy',
]);
/**
 * Packages that should NEVER be flagged as typosquats despite similarity to popular packages.
 * These are commonly used legitimate packages that happen to be lexically similar to others.
 *
 * Examples of FPs this prevents:
 * - 'test' flagged as typosquat of 'nest' (59 FPs in cal-com)
 * - 'geist' (Vercel's font) flagged as typosquat of 'nest'
 * - 'botid' flagged as typosquat of 'solid'
 * - 'cypress' flagged as typosquat (major testing framework)
 */
const TYPOSQUAT_WHITELIST = new Set([
    // Common test/build packages (easily confused with 'nest', etc.)
    'test', 'jest', 'mocha', 'chai', 'karma', 'ava', 'tape',
    'nest', 'next', 'best', 'rest', 'fest', 'west', // Short common words
    // Major testing frameworks - NEVER flag these
    'cypress', 'playwright', 'vitest', 'jasmine', 'puppeteer',
    // Vercel ecosystem
    'geist', 'turbo', 'swr', 'next', 'vercel', 'ai',
    // Common frameworks that might match other frameworks
    'solid', 'react', 'vue', 'svelte', 'angular', 'ember',
    'hono', 'koa', 'oak', 'hapi', 'fastify', 'express',
    // Short legitimate package names that could false-positive
    'botid', 'zod', 'yup', 'joi', 'got', 'ora', 'ink', 'arg',
    'fs', 'os', 'vm', 'ws', 'ip', 'ms', 'qs', 'p-',
    'co', 'on', 'yn', 'is', 'it', 'to', 'at', 'no', 'of',
    // Font packages
    'geist', 'inter', 'roboto', 'lato', 'poppins',
    // Common utility packages with similar names
    'uuid', 'ulid', 'cuid', 'nanoid',
    'date', 'data', 'deta', 'meta',
    'path', 'glob', 'node', 'deno',
    'form', 'from', 'fork', 'core',
    'fast', 'last', 'past', 'cast', 'vast',
    'hash', 'cash', 'dash', 'bash', 'rash',
    'find', 'bind', 'mind', 'kind', 'wind',
    'send', 'lend', 'tend', 'mend', 'bend',
    'read', 'lead', 'head', 'dead', 'bead',
    'sort', 'port', 'fort', 'tort', 'mort',
    // Database/ORM related
    'pg', 'mysql', 'mssql', 'sqlite', 'redis', 'mongo',
    'knex', 'drizzle', 'prisma', 'typeorm',
    // Build tools
    'vite', 'esbuild', 'rollup', 'parcel', 'turbo',
    // Linting/formatting
    'eslint', 'biome', 'oxlint', 'rome',
    // Popular packages that sound like typosquats but aren't
    'lodash', 'axios', 'chalk', 'dotenv', 'bcrypt', 'bcryptjs',
    'dayjs', 'luxon', 'sharp', 'jimp', 'pino', 'bunyan', 'winston',
    // Math/rendering libraries (katex is NOT a typosquat of knex)
    'katex', 'latex', 'mathjax',
    // Unified ecosystem (unist is NOT a typosquat of nest - 5M+ weekly downloads)
    'unist', 'mdast', 'hast', 'xast', 'nlcst', 'esast',
    'unified', 'remark', 'rehype', 'retext', 'redot',
    'micromark', 'mdx', 'mdxjs',
]);
/**
 * Scoped package prefixes that are always legitimate
 * Packages starting with these scopes should never be flagged
 */
const LEGITIMATE_SCOPED_PREFIXES = [
    '@vercel/',
    '@types/',
    '@testing-library/',
    '@babel/',
    '@eslint/',
    '@typescript-eslint/',
    '@aws-sdk/',
    '@azure/',
    '@google-cloud/',
    '@octokit/',
    '@prisma/',
    '@trpc/',
    '@tanstack/',
    '@radix-ui/',
    '@headlessui/',
    '@heroicons/',
    '@tailwindcss/',
    '@fontsource/',
    '@next/',
    '@supabase/',
    '@clerk/',
    '@auth/',
    '@sentry/',
    '@opentelemetry/',
    '@anthropic-ai/',
    '@langchain/',
];
// ============================================================================
// Typosquatting Detection
// ============================================================================
/**
 * Popular packages to check for typosquatting
 */
const POPULAR_PACKAGES_FOR_TYPOSQUAT = [
    // JavaScript/TypeScript core
    'react', 'vue', 'angular', 'svelte', 'solid',
    'express', 'fastify', 'koa', 'hono', 'nest',
    'next', 'nuxt', 'remix', 'gatsby', 'astro',
    'lodash', 'axios', 'moment', 'dayjs', 'zod',
    'mongoose', 'sequelize', 'prisma', 'typeorm', 'knex',
    'webpack', 'rollup', 'vite', 'esbuild', 'parcel',
    'jest', 'vitest', 'mocha', 'chai', 'cypress',
    'typescript', 'eslint', 'prettier', 'babel',
    'redux', 'mobx', 'zustand', 'jotai', 'recoil',
    'tailwindcss', 'bootstrap', 'antd', 'material-ui',
    'socket', 'graphql', 'apollo', 'trpc',
    // Python core
    'requests', 'flask', 'django', 'fastapi', 'tornado',
    'numpy', 'pandas', 'scipy', 'matplotlib', 'seaborn',
    'tensorflow', 'pytorch', 'keras', 'scikit-learn',
    'sqlalchemy', 'celery', 'redis', 'boto3',
    'pydantic', 'pytest', 'black', 'ruff',
];
/**
 * Common character substitutions used in typosquatting
 */
const TYPOSQUAT_SUBSTITUTIONS = [
    ['0', 'o'], ['o', '0'],
    ['1', 'l'], ['l', '1'], ['1', 'i'], ['i', '1'],
    ['5', 's'], ['s', '5'],
    ['a', '@'], ['@', 'a'],
    ['e', '3'], ['3', 'e'],
    ['rn', 'm'], ['m', 'rn'],
    ['vv', 'w'], ['w', 'vv'],
    ['cl', 'd'], ['d', 'cl'],
    ['ii', 'u'], ['u', 'ii'],
];
/**
 * Calculate Levenshtein distance between two strings
 */
function levenshteinDistance(a, b) {
    const matrix = [];
    for (let i = 0; i <= b.length; i++) {
        matrix[i] = [i];
    }
    for (let j = 0; j <= a.length; j++) {
        matrix[0][j] = j;
    }
    for (let i = 1; i <= b.length; i++) {
        for (let j = 1; j <= a.length; j++) {
            if (b.charAt(i - 1) === a.charAt(j - 1)) {
                matrix[i][j] = matrix[i - 1][j - 1];
            }
            else {
                matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j] + 1);
            }
        }
    }
    return matrix[b.length][a.length];
}
/**
 * Check if package name has character substitutions matching a popular package
 */
function hasCharacterSubstitution(packageName, popularPackage) {
    // Apply each substitution to the popular package and check for match
    for (const [from, to] of TYPOSQUAT_SUBSTITUTIONS) {
        const substituted = popularPackage.replace(new RegExp(from, 'g'), to);
        if (substituted.toLowerCase() === packageName.toLowerCase() && substituted !== popularPackage) {
            return true;
        }
    }
    return false;
}
/**
 * Check if package is a potential typosquat of a popular package
 * Returns the popular package it resembles and the reason
 */
function checkTyposquatting(packageName) {
    const name = packageName.toLowerCase();
    // Skip packages in the typosquat whitelist - these are known legitimate packages
    if (TYPOSQUAT_WHITELIST.has(name)) {
        return { isTyposquat: false };
    }
    // Skip scoped packages with legitimate prefixes
    if (packageName.startsWith('@')) {
        for (const prefix of LEGITIMATE_SCOPED_PREFIXES) {
            if (packageName.startsWith(prefix)) {
                return { isTyposquat: false };
            }
        }
    }
    for (const popular of POPULAR_PACKAGES_FOR_TYPOSQUAT) {
        const popularLower = popular.toLowerCase();
        // Skip exact match
        if (name === popularLower)
            continue;
        // Check Levenshtein distance (1-2 chars difference)
        const distance = levenshteinDistance(name, popularLower);
        if (distance === 1) {
            return {
                isTyposquat: true,
                similarTo: popular,
                reason: `differs by only 1 character from "${popular}"`,
            };
        }
        if (distance === 2 && name.length >= 5 && Math.abs(name.length - popularLower.length) <= 1) {
            return {
                isTyposquat: true,
                similarTo: popular,
                reason: `very similar to "${popular}" (2 char difference)`,
            };
        }
        // Check character substitution
        if (hasCharacterSubstitution(name, popularLower)) {
            return {
                isTyposquat: true,
                similarTo: popular,
                reason: `uses character substitution similar to "${popular}" (e.g., 0↔o, 1↔l)`,
            };
        }
        // Check for doubled characters (lodaash vs lodash)
        const doubledPattern = new RegExp(`^${popularLower.split('').join('+')}+$`);
        if (doubledPattern.test(name) && name !== popularLower) {
            return {
                isTyposquat: true,
                similarTo: popular,
                reason: `contains doubled characters similar to "${popular}"`,
            };
        }
        // Check for missing vowels (rqsts vs requests)
        const noVowels = popularLower.replace(/[aeiou]/g, '');
        const nameNoVowels = name.replace(/[aeiou]/g, '');
        if (noVowels === nameNoVowels && noVowels.length >= 4 && name !== popularLower) {
            return {
                isTyposquat: true,
                similarTo: popular,
                reason: `missing vowels similar to "${popular}"`,
            };
        }
        // Check for common prefixes/suffixes that create confusion
        if (name === `${popularLower}-js` || name === `${popularLower}js` ||
            name === `node-${popularLower}` || name === `${popularLower}-node`) {
            return {
                isTyposquat: true,
                similarTo: popular,
                reason: `adds common suffix/prefix that could be confused with "${popular}"`,
            };
        }
    }
    return { isTyposquat: false };
}
// ============================================================================
// Suspicious Pattern Definitions
// ============================================================================
/**
 * Unscoped generic names that are too vague to be real packages
 * Real packages have specific names, not generic utility words
 */
const GENERIC_UNSCOPED_NAMES = new Set([
    'utils',
    'helpers',
    'common',
    'tools',
    'shared',
    'lib',
    'core',
    'base',
    'main',
    'app',
    'api',
    'data',
    'models',
    'services',
    'modules',
    'components',
]);
/**
 * Prefixes that are frequently hallucinated when combined with generic suffixes
 */
const SUSPICIOUS_PREFIXES = [
    'easy-',
    'simple-',
    'fast-', // Note: some real packages use this, checked against allowlist
    'quick-',
    'basic-',
    'super-',
    'mega-',
    'ultra-',
    'awesome-',
    'better-',
    'node-', // Note: some real packages use this, but often hallucinated for non-core modules
    'react-', // Note: many real packages, but also many hallucinated
    'vue-', // Note: many real packages, but also many hallucinated
    'express-', // Note: many real packages, but also many hallucinated
    'python-',
    'django-', // Note: some real, but often hallucinated
    'flask-', // Note: some real, but often hallucinated
];
/**
 * Suffixes that indicate potential hallucination when combined with suspicious prefixes
 */
const SUSPICIOUS_SUFFIXES = [
    '-utils',
    '-helpers',
    '-tools',
    '-lib',
    '-client', // Often hallucinated for already-named services
    '-sdk', // Often hallucinated
    '-api',
    '-wrapper',
    '-connector',
    '-adapter',
    '-handler',
    '-manager',
    '-service',
    '-pro',
    '-plus',
    '-enhanced',
];
// ============================================================================
// Context Detection
// ============================================================================
/**
 * Check if package name is scoped (@org/package)
 * Scoped packages are less likely to be hallucinated (requires npm org)
 */
function isScopedPackage(packageName) {
    return packageName.startsWith('@');
}
/**
 * Check if this is a relative import (./path or ../path)
 */
function isRelativeImport(importPath) {
    return importPath.startsWith('./') || importPath.startsWith('../') || importPath.startsWith('/');
}
/**
 * Check if this is an alias import (@/, ~/, #) or TypeScript path alias
 * These are local imports configured in tsconfig.json, NOT npm packages
 *
 * Common patterns:
 * - @/lib/auth (Next.js/Vite common pattern)
 * - ~/components (Nuxt.js pattern)
 * - #/utils (private imports)
 * - @components/Button (custom tsconfig paths)
 */
function isAliasImport(importPath) {
    // Standard alias patterns
    if (/^[@~#]\//.test(importPath)) {
        return true;
    }
    // Scoped packages are NOT aliases (they have @org/package format)
    // But @/path and @alias/path ARE aliases when:
    // 1. They start with @ followed by / (e.g., @/lib/auth)
    // 2. They have a short "scope" that looks like an alias (e.g., @components/Button)
    if (importPath.startsWith('@')) {
        // Check if it looks like a scoped npm package (@org/package-name)
        // vs a path alias (@/path or @alias/path)
        const match = importPath.match(/^@([^/]+)\//);
        if (match) {
            const scope = match[1];
            // Empty scope means @/ which is always an alias
            if (!scope)
                return true;
            // Single char scopes are aliases (@a/foo, @x/bar)
            if (scope.length === 1)
                return true;
            // Common alias names
            const commonAliases = ['app', 'src', 'lib', 'utils', 'components', 'hooks', 'services', 'config', 'types', 'styles', 'assets', 'public', 'pages', 'layouts', 'features', 'modules', 'core', 'shared'];
            if (commonAliases.includes(scope.toLowerCase()))
                return true;
        }
    }
    return false;
}
/**
 * Check if this is a Node.js built-in module
 */
function isNodeBuiltin(packageName) {
    const builtins = new Set([
        'fs', 'path', 'http', 'https', 'crypto', 'os', 'url', 'util', 'stream',
        'events', 'buffer', 'querystring', 'child_process', 'cluster', 'dgram',
        'dns', 'net', 'readline', 'repl', 'tls', 'tty', 'v8', 'vm', 'zlib',
        'assert', 'async_hooks', 'console', 'constants', 'domain', 'inspector',
        'module', 'perf_hooks', 'process', 'punycode', 'string_decoder',
        'timers', 'trace_events', 'worker_threads',
        // Node: prefixed
        'node:fs', 'node:path', 'node:http', 'node:https', 'node:crypto',
        'node:os', 'node:url', 'node:util', 'node:stream', 'node:events',
        'node:buffer', 'node:querystring', 'node:child_process', 'node:test',
    ]);
    return builtins.has(packageName) || packageName.startsWith('node:');
}
/**
 * Check if file is a package manifest
 */
function isPackageManifest(filePath) {
    const manifestFiles = [
        'package.json',
        'requirements.txt',
        'Pipfile',
        'pyproject.toml',
        'setup.py',
        'Gemfile',
        'go.mod',
        'Cargo.toml',
        'composer.json',
    ];
    return manifestFiles.some(f => filePath.endsWith(f));
}
/**
 * Check if package name matches suspicious patterns
 */
function isSuspiciousPattern(packageName) {
    // Check known hallucinated packages first
    if (KNOWN_HALLUCINATED_PACKAGES.has(packageName)) {
        return { suspicious: true, reason: 'Known hallucinated package from research' };
    }
    // Skip known legitimate packages
    if (KNOWN_LEGITIMATE_PACKAGES.has(packageName)) {
        return { suspicious: false, reason: '' };
    }
    // Check unscoped generic names
    if (GENERIC_UNSCOPED_NAMES.has(packageName)) {
        return { suspicious: true, reason: 'Generic unscoped name - real packages have specific names' };
    }
    // Check suspicious prefix + suffix combinations
    for (const prefix of SUSPICIOUS_PREFIXES) {
        if (packageName.startsWith(prefix)) {
            // Check if it has a suspicious suffix too
            for (const suffix of SUSPICIOUS_SUFFIXES) {
                if (packageName.endsWith(suffix)) {
                    // Double suspicious - prefix AND suffix
                    return {
                        suspicious: true,
                        reason: `Suspicious pattern: "${prefix}" prefix with "${suffix}" suffix`,
                    };
                }
            }
            // Just prefix is lower confidence
            const baseName = packageName.slice(prefix.length);
            if (GENERIC_UNSCOPED_NAMES.has(baseName) || baseName.length < 3) {
                return {
                    suspicious: true,
                    reason: `Suspicious pattern: "${prefix}" prefix with generic name`,
                };
            }
        }
    }
    // Check if it's just prefix + generic suffix
    for (const suffix of SUSPICIOUS_SUFFIXES) {
        if (packageName.endsWith(suffix)) {
            const baseName = packageName.slice(0, -suffix.length);
            // If the base is very short or generic, flag it
            if (baseName.length <= 2 || GENERIC_UNSCOPED_NAMES.has(baseName)) {
                return {
                    suspicious: true,
                    reason: `Suspicious pattern: generic name with "${suffix}" suffix`,
                };
            }
        }
    }
    return { suspicious: false, reason: '' };
}
/**
 * Extract package name from import/require path
 */
function extractPackageName(importPath) {
    // Skip relative and alias imports
    if (isRelativeImport(importPath) || isAliasImport(importPath)) {
        return null;
    }
    // Handle scoped packages (@org/package)
    if (importPath.startsWith('@')) {
        const parts = importPath.split('/');
        if (parts.length >= 2) {
            return `${parts[0]}/${parts[1]}`;
        }
        return null;
    }
    // Regular package - get the first part before any /
    const parts = importPath.split('/');
    return parts[0];
}
/**
 * Extract imports from JavaScript/TypeScript code
 */
function extractJSImports(content) {
    const imports = [];
    const lines = content.split('\n');
    // ES6 import patterns
    const es6ImportRegex = /import\s+(?:(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)\s+from\s+)?['"]([^'"]+)['"]/g;
    // require() patterns
    const requireRegex = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
    // Dynamic import
    const dynamicImportRegex = /import\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
    let match;
    while ((match = es6ImportRegex.exec(content)) !== null) {
        const lineNumber = content.substring(0, match.index).split('\n').length;
        const packageName = extractPackageName(match[1]);
        if (packageName && !isNodeBuiltin(packageName)) {
            imports.push({
                packageName,
                lineNumber,
                lineContent: lines[lineNumber - 1]?.trim() || '',
            });
        }
    }
    while ((match = requireRegex.exec(content)) !== null) {
        const lineNumber = content.substring(0, match.index).split('\n').length;
        const packageName = extractPackageName(match[1]);
        if (packageName && !isNodeBuiltin(packageName)) {
            imports.push({
                packageName,
                lineNumber,
                lineContent: lines[lineNumber - 1]?.trim() || '',
            });
        }
    }
    while ((match = dynamicImportRegex.exec(content)) !== null) {
        const lineNumber = content.substring(0, match.index).split('\n').length;
        const packageName = extractPackageName(match[1]);
        if (packageName && !isNodeBuiltin(packageName)) {
            imports.push({
                packageName,
                lineNumber,
                lineContent: lines[lineNumber - 1]?.trim() || '',
            });
        }
    }
    return imports;
}
/**
 * Extract dependencies from package.json
 */
function extractPackageJsonDeps(content, lines) {
    const imports = [];
    try {
        const pkg = JSON.parse(content);
        const allDeps = {
            ...pkg.dependencies,
            ...pkg.devDependencies,
            ...pkg.peerDependencies,
            ...pkg.optionalDependencies,
        };
        for (const packageName of Object.keys(allDeps)) {
            // Find the line number where this package appears
            const lineIndex = lines.findIndex(line => line.includes(`"${packageName}"`));
            if (lineIndex !== -1) {
                imports.push({
                    packageName,
                    lineNumber: lineIndex + 1,
                    lineContent: lines[lineIndex].trim(),
                });
            }
        }
    }
    catch {
        // Invalid JSON, skip
    }
    return imports;
}
/**
 * Extract dependencies from requirements.txt
 */
function extractRequirementsDeps(_content, lines) {
    const imports = [];
    for (let i = 0; i < lines.length; i++) {
        const line = lines[i].trim();
        // Skip comments and empty lines
        if (!line || line.startsWith('#') || line.startsWith('-'))
            continue;
        // Extract package name (before ==, >=, <=, ~=, etc.)
        const match = line.match(/^([a-zA-Z0-9_-]+)/);
        if (match) {
            imports.push({
                packageName: match[1].toLowerCase().replace(/_/g, '-'),
                lineNumber: i + 1,
                lineContent: line,
            });
        }
    }
    return imports;
}
// ============================================================================
// Main Detection Function
// ============================================================================
/**
 * Main detection function for AI package hallucination
 */
function detectAIPackageHallucination(content, filePath, options) {
    const vulnerabilities = [];
    // Skip non-applicable files
    if ((0, context_helpers_1.isScannerOrFixtureFile)(filePath))
        return vulnerabilities;
    if ((0, context_helpers_1.isDocumentationFile)(filePath))
        return vulnerabilities;
    const lines = options?.parsed?.lines ?? content.split('\n');
    const isTestFile = (0, context_helpers_1.isTestOrMockFile)(filePath);
    const isExample = (0, context_helpers_1.isExampleDirectory)(filePath);
    const isManifest = isPackageManifest(filePath);
    // Extract imports based on file type
    let imports = [];
    if (filePath.endsWith('package.json')) {
        imports = extractPackageJsonDeps(content, lines);
    }
    else if (filePath.endsWith('requirements.txt')) {
        imports = extractRequirementsDeps(content, lines);
    }
    else if (/\.(js|jsx|ts|tsx|mjs|cjs)$/.test(filePath)) {
        imports = extractJSImports(content);
    }
    else {
        // Not a file we can analyze for imports
        return vulnerabilities;
    }
    // Track already-flagged packages to avoid duplicates
    const flaggedPackages = new Set();
    for (const imp of imports) {
        // Skip if we've already flagged this package
        if (flaggedPackages.has(imp.packageName))
            continue;
        // Skip scoped packages (less likely to be hallucinated)
        if (isScopedPackage(imp.packageName))
            continue;
        // Skip comments
        if ((0, context_helpers_1.isComment)(imp.lineContent))
            continue;
        // Skip known legitimate packages for typosquat check
        if (KNOWN_LEGITIMATE_PACKAGES.has(imp.packageName))
            continue;
        // Check for typosquatting first (higher priority - supply chain attack)
        const typosquatResult = checkTyposquatting(imp.packageName);
        if (typosquatResult.isTyposquat) {
            flaggedPackages.add(imp.packageName);
            let severity = 'high'; // Typosquats are always high priority
            // Package manifests in production are critical
            if (isManifest) {
                severity = 'critical';
            }
            // Test files and examples get downgraded
            if (isTestFile || isExample) {
                severity = 'low';
            }
            const description = `Package "${imp.packageName}" ${typosquatResult.reason}. This could be a typosquatting attack where attackers register similar package names to steal credentials or inject malicious code.`;
            const suggestedFix = `Verify you meant to use "${typosquatResult.similarTo}". Run "npm view ${imp.packageName}" to check if this package exists. If it doesn't, update to "${typosquatResult.similarTo}".`;
            vulnerabilities.push({
                id: `ai-pkg-typosquat-${filePath}-${imp.lineNumber}-${imp.packageName}`,
                filePath,
                lineNumber: imp.lineNumber,
                lineContent: imp.lineContent,
                severity,
                category: 'ai_package_typosquat',
                title: `Potential typosquat: ${imp.packageName} (similar to ${typosquatResult.similarTo})`,
                description,
                suggestedFix,
                confidence: 'high',
                layer: 2,
                requiresAIValidation: false, // Typosquats don't need AI validation - pattern is clear
            });
            continue; // Don't also flag as hallucination
        }
        // Check if package is suspicious (hallucination patterns)
        const { suspicious, reason } = isSuspiciousPattern(imp.packageName);
        if (suspicious) {
            flaggedPackages.add(imp.packageName);
            // Determine severity based on context
            let severity = 'medium';
            // Known hallucinations are higher severity
            if (KNOWN_HALLUCINATED_PACKAGES.has(imp.packageName)) {
                severity = 'high';
            }
            // Package manifests are higher severity (direct dependency)
            if (isManifest && severity === 'medium') {
                severity = 'high';
            }
            // Test files and examples get downgraded
            if (isTestFile || isExample) {
                severity = 'info';
            }
            const description = KNOWN_HALLUCINATED_PACKAGES.has(imp.packageName)
                ? `Package "${imp.packageName}" is a known AI-hallucinated package that doesn't exist. This creates a supply chain attack vector where attackers register the fake package name.`
                : `Package "${imp.packageName}" matches suspicious hallucination patterns: ${reason}. Verify this package exists on npm/PyPI before using.`;
            const suggestedFix = KNOWN_HALLUCINATED_PACKAGES.has(imp.packageName)
                ? `Remove "${imp.packageName}" and use the correct package. Search npm/PyPI for the real package that provides this functionality.`
                : `Verify "${imp.packageName}" exists: run "npm view ${imp.packageName}" or check https://www.npmjs.com/package/${imp.packageName}. If it doesn't exist, find the correct package name.`;
            vulnerabilities.push({
                id: `ai-pkg-hallucination-${filePath}-${imp.lineNumber}-${imp.packageName}`,
                filePath,
                lineNumber: imp.lineNumber,
                lineContent: imp.lineContent,
                severity,
                category: 'ai_package_hallucination',
                title: `Potentially hallucinated package: ${imp.packageName}`,
                description,
                suggestedFix,
                confidence: KNOWN_HALLUCINATED_PACKAGES.has(imp.packageName) ? 'high' : 'medium',
                layer: 2,
                requiresAIValidation: severity !== 'info' && !KNOWN_HALLUCINATED_PACKAGES.has(imp.packageName),
            });
        }
    }
    return vulnerabilities;
}
//# sourceMappingURL=ai-package-hallucination.js.map