{"version":3,"file":"test-origin.cjs","names":[],"sources":["../../src/sql/test-origin.ts"],"sourcesContent":["import type { SQLCommenterTag } from \"./analyzer.js\";\n\n/**\n * Whether a query originated from a test file, decided from its SQLCommenter\n * `file` tag.\n *\n * The CI gate should never flag a query that no production route runs — e.g. a\n * read-back assertion in `tests/pg/postgres.test.ts` — yet before this such\n * queries had to be ignored one hash at a time (#3199). SQLCommenter already\n * carries the caller's file (surfaced in query detail per #2585); this reads it\n * so both the analyzer's gate and the server's alert engine can bucket\n * test-origin queries out with a single shared rule instead of drifting apart.\n *\n * Conservative by construction: the decision keys only off the `file` tag's\n * origin path. A query with no `file` tag is never test-origin, so untagged\n * codebases behave exactly as before.\n */\nexport function isTestOriginQuery(\n  tags: readonly SQLCommenterTag[] | undefined | null,\n): boolean {\n  if (!tags) return false;\n  for (const tag of tags) {\n    if (tag.key !== \"file\") continue;\n    // SQLCommenter can pack a caller stack into one `file` value, `;`-separated\n    // and most-specific-first (the frontend renders `files[0]` as the origin).\n    // The first entry is the query's own call site, so it decides origin — a\n    // production query that merely threads through a test helper deeper in the\n    // stack stays gated. Each entry carries a `:line[:col]` suffix\n    // (`foo.spec.ts:509:10`); it must come off before matching, or the\n    // `$`-anchored filename patterns in isTestFilePath never fire.\n    const originFile = tag.value\n      .split(\";\")[0]\n      ?.trim()\n      .replace(/:\\d+(?::\\d+)?$/, \"\");\n    if (originFile && isTestFilePath(originFile)) return true;\n  }\n  return false;\n}\n\n/**\n * Whether a source path looks like a test file. Query Doctor analyzes clients in\n * any language, so this spans the common cross-language conventions rather than\n * assuming JS/TS — directory-scoped (`tests/`, `__tests__/`, `spec/`, `e2e/`,\n * Maven's `src/test/`) and filename-scoped (`*.test.*` / `*.spec.*`, Python\n * `test_*.py` / `*_test.py`, Go `*_test.go`, Ruby `*_test.rb` / `*_spec.rb`,\n * Java `*Test.java`). Anchored on path separators so `testimonials/user.ts` or\n * `latest/report.py` don't get mistaken for tests.\n */\nexport function isTestFilePath(path: string): boolean {\n  return TEST_PATH_PATTERNS.some((pattern) => pattern.test(path));\n}\n\nconst TEST_PATH_PATTERNS: readonly RegExp[] = [\n  // A directory segment dedicated to tests, anywhere in the path.\n  /(?:^|\\/)(?:tests?|__tests__|specs?|e2e)\\//i,\n  // Maven/Gradle layout: src/test/java/...\n  /(?:^|\\/)src\\/test\\//i,\n  // JS/TS: foo.test.ts, foo.spec.tsx, foo.e2e.mts\n  /\\.(?:test|spec|e2e)\\.[cm]?[jt]sx?$/i,\n  // Python: test_foo.py, foo_test.py, conftest.py\n  /(?:^|\\/)(?:test_[^/]+|[^/]+_test|conftest)\\.py$/i,\n  // Go: foo_test.go\n  /_test\\.go$/i,\n  // Ruby: foo_test.rb, foo_spec.rb\n  /_(?:test|spec)\\.rb$/i,\n  // Java/Kotlin: FooTest.java, FooTests.kt\n  /Tests?\\.(?:java|kt)$/,\n];\n"],"mappings":";;;;;;;;;;;;;;;;;AAiBA,SAAgB,kBACd,MACS;AACT,KAAI,CAAC,KAAM,QAAO;AAClB,MAAK,MAAM,OAAO,MAAM;AACtB,MAAI,IAAI,QAAQ,OAAQ;EAQxB,MAAM,aAAa,IAAI,MACpB,MAAM,IAAI,CAAC,IACV,MAAM,CACP,QAAQ,kBAAkB,GAAG;AAChC,MAAI,cAAc,eAAe,WAAW,CAAE,QAAO;;AAEvD,QAAO;;;;;;;;;;;AAYT,SAAgB,eAAe,MAAuB;AACpD,QAAO,mBAAmB,MAAM,YAAY,QAAQ,KAAK,KAAK,CAAC;;AAGjE,MAAM,qBAAwC;CAE5C;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CACD"}