/** * Universal Schema Analyzer — Spec 17 R2 * * R2.1: SQL-context-only extraction (AST-based, not regex scan-all-strings). * R2.2: File gate — only analyze files with DB usage indicators. * R2.3: Template expressions resolve to wildcards for known-table matching. * R2.4: Unknown-table findings include SQL kind, line, and Levenshtein suggestions. * R2.5: Legacy scan-all-strings path DELETED. * R7: schema/unknown-table severity is "suggestion". */ import { UniversalAnalyzer } from '../../languages/UniversalAnalyzer.js'; import type { Violation } from '../../types.js'; import type { AST, LanguageAdapter } from '../../languages/types.js'; /** * Configuration for Schema analyzer */ export interface SchemaAnalyzerConfig { enableTableUsageTracking?: boolean; checkMissingReferences?: boolean; checkNamingConventions?: boolean; detectUnusedTables?: boolean; validateQueryPatterns?: boolean; maxQueriesPerFunction?: number; requiredSchemas?: string[]; schemas?: Array<{ name: string; tables: Array<{ name: string; columns: Array<{ name: string; type: string; }>; }>; }>; validateJsonSchemas?: boolean; jsonSchemaVersion?: 'draft-04' | 'draft-06' | 'draft-07' | '2019-09' | '2020-12'; allowedJsonTypes?: string[]; schemaFilePatterns?: string[]; dataFilePatterns?: string[]; schemaDataPairs?: Array<{ schema: string; data: string | string[]; }>; strictMode?: boolean; allowAdditionalProperties?: boolean; sqlTagNames?: string[]; dbReceiverNames?: string[]; dbCallMethods?: string[]; dbBindingNames?: string[]; fileGateGlobs?: string[]; } export declare const DEFAULT_SCHEMA_CONFIG: SchemaAnalyzerConfig; import type { AnalyzerResult } from '../../types.js'; export declare class UniversalSchemaAnalyzer extends UniversalAnalyzer { readonly name = "schema"; readonly description = "Analyzes code against database schemas and validates JSON schemas"; readonly category = "database"; private tableReferences; private columnReferences; analyze(files: string[], config: any): Promise; /** * Spec 22 Item 2 — Auto-discover known tables from migration/SQL files. * * When config.schemas is empty, scans files matching fileGateGlobs for * CREATE TABLE statements and returns the set of discovered table names. * These are injected as a synthetic schema so the unknown-table detector * has a reference set to check against. * * Only extracts `create`-type references (CREATE TABLE ...), since those * define tables — SELECT/INSERT/UPDATE references to an unknown table are * the violations we're trying to avoid flagging. */ private discoverTablesFromMigrations; /** * Spec 24 Item 4 — Auto-discover known tables from ORM schema definitions. * * Uses import provenance to identify schema files (files importing Drizzle * table constructors from drizzle-orm) and Prisma's canonical schema.prisma * filename. Extracts table/model names and feeds them into allTables so the * unknown-table detector works without explicit user config. * * Drizzle: scans .ts/.tsx/.js/.jsx files that import from drizzle-orm for * pgTable/mysqlTable/sqliteTable('tableName', ...) calls. * Prisma: scans schema.prisma files for model Name { ... } blocks. */ private discoverTablesFromOrmSchemas; protected analyzeAST(ast: AST, adapter: LanguageAdapter, config: SchemaAnalyzerConfig, sourceCode: string): Promise; /** * Pre-filter: only analyze files that show DB usage. * Checks: .sql/migration glob, D1/SQL imports, env-binding patterns, DB calls. */ private passesFileGate; /** * Extract table references exclusively from SQL contexts in the AST. * R2.1: Only tagged template SQL and DB-call patterns produce candidates. * R2.3: Template expressions (${var}) resolved to wildcards. */ private findTableReferences; /** * Spec 15 R1 — Record extracted table references to schema_usage for * cross-domain lifecycle analysis (written-never-read, read-never-written, * transaction-boundary risk). * * Idempotent per-file: stale entries are cleared before fresh references * are inserted. For .sql/migration files, uses "schema-file" as the * function name since there's no AST function context. */ private recordTableUsage; /** * Parse SQL table names from a SQL text string. * R2.3: Template expressions (${...}) resolve portions to wildcards. */ private parseSqlTables; /** * Spec 22 R4.3: Extract alias identifiers from SQL text. * * Detects both explicit (`FROM x AS t`) and bare (`FROM x t`) aliases * so they can be filtered from table-references in parseSqlTables(). * Without this, "JOIN t.posts" captures t via the JOIN regex when t is * an alias for the real table x. */ private extractAliasIdentifiers; /** * R2.3: Resolve template expressions in SQL text. * * Uses the sentinel `__TMPL__` instead of an empty string. An empty * replacement produces whitespace artifacts (e.g. `FROM t WHERE` * when `${tableName}` is stripped), which causes the bare-alias regex * in extractAliasIdentifiers() to misalign: `t` lands in the table-name * capture group instead of the alias group, and is never denylisted. * * `__TMPL__` keeps the token boundaries intact so alias extraction * correctly identifies `t` as the alias. `__TMPL__` table references * are filtered in parseSqlTables(). */ private resolveTemplateExpressions; /** * Return known table names within edit distance ≤ maxDist. */ private getNearestTableSuggestions; private levenshteinDistance; private findColumnReferences; private checkNamingConventions; private checkQueryPatterns; private checkSQLInjection; /** * Extract the callee text from a call_expression node. */ private getCallee; /** * Check if call_expression has a template string argument. */ private hasTemplateArgument; /** * Get the text of the first template string argument. */ private getTemplateText; /** * Get the first string/template argument from a call expression. */ private getFirstStringArgument; /** * Check if a callee is a DB member call like db.exec, database.query, etc. */ private isDbMemberCall; /** * Get the line/column location of the call expression. */ private getCallLocation; /** * Convert a character offset to a line/column location. */ private offsetToLocation; private isSystemTable; /** * Common SQL keywords and identifiers that are not real table names. */ private isSqlKeyword; private getQueryType; private countQueries; private findNodeByLocation; /** * Find the nearest AST node at a source location — walks the tree looking * for the deepest node that contains the given line/column. */ private findClosestNodeAt; /** * Walk up the AST from a node to find the enclosing function or method name. * Matches the same scheme as UniversalDataAccessAnalyzer.findEnclosingFunctionName. */ private findEnclosingFunctionName; /** * Extract a human-readable name from an AST node. * Matches the same scheme as UniversalDataAccessAnalyzer.getNodeName. */ private getNodeName; private analyzeJsonSchemas; private validateJsonSchema; private validateSchemaTypes; private identifySchemaFiles; private identifyDataFiles; private loadSchema; private findMatchingSchema; private validateDataAgainstSchema; private validateAgainstSchema; } //# sourceMappingURL=UniversalSchemaAnalyzer.d.ts.map