@happyvertical/smrt-core 0.37.0 → 0.37.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/consumer-plugin/index.js.map +1 -1
- package/dist/manifest/discover-smrt-packages.d.ts +10 -0
- package/dist/manifest/discover-smrt-packages.d.ts.map +1 -1
- package/dist/manifest/discover-smrt-packages.js.map +1 -1
- package/dist/manifest/generator.d.ts.map +1 -1
- package/dist/manifest/generator.js +34 -37
- package/dist/manifest/generator.js.map +1 -1
- package/dist/manifest/index.js +2 -2
- package/dist/manifest/index.js.map +1 -1
- package/dist/manifest/manifest-loader.d.ts +10 -0
- package/dist/manifest/manifest-loader.d.ts.map +1 -1
- package/dist/manifest/manifest-loader.js.map +1 -1
- package/dist/manifest/static-manifest.js +2 -2
- package/dist/manifest/static-manifest.js.map +1 -1
- package/dist/manifest/store.js +2 -2
- package/dist/manifest/test-manifest-stub.js +2 -2
- package/dist/manifest/test-manifest-stub.js.map +1 -1
- package/dist/manifest.json +2 -2
- package/dist/migrations/differ.d.ts +104 -13
- package/dist/migrations/differ.d.ts.map +1 -1
- package/dist/migrations/differ.js +199 -26
- package/dist/migrations/differ.js.map +1 -1
- package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/assert-valid-pattern.js.map +1 -1
- package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/ast.js +1 -7
- package/dist/node_modules/.pnpm/minimatch@10.2.5/node_modules/minimatch/dist/esm/ast.js.map +1 -0
- package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/brace-expressions.js.map +1 -1
- package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/escape.js.map +1 -1
- package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/index.js +17 -14
- package/dist/node_modules/.pnpm/minimatch@10.2.5/node_modules/minimatch/dist/esm/index.js.map +1 -0
- package/dist/node_modules/.pnpm/minimatch@10.2.5/node_modules/minimatch/dist/esm/unescape.js +10 -0
- package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/unescape.js.map +1 -1
- package/dist/object.d.ts.map +1 -1
- package/dist/object.js.map +1 -1
- package/dist/scanner/manifest-generator.d.ts.map +1 -1
- package/dist/scanner/manifest-generator.js +22 -20
- package/dist/scanner/manifest-generator.js.map +1 -1
- package/dist/smrt-knowledge.json +7 -7
- package/dist/vite-plugin/index.js +1 -1
- package/package.json +7 -7
- package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/ast.js.map +0 -1
- package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/index.js.map +0 -1
- package/dist/node_modules/.pnpm/minimatch@10.2.3/node_modules/minimatch/dist/esm/unescape.js +0 -10
- /package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/assert-valid-pattern.js +0 -0
- /package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/brace-expressions.js +0 -0
- /package/dist/node_modules/.pnpm/{minimatch@10.2.3 → minimatch@10.2.5}/node_modules/minimatch/dist/esm/escape.js +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"differ.js","sources":["../../src/migrations/differ.ts"],"sourcesContent":["/**\n * Schema Differ\n *\n * Compares manifest schemas to database schemas and generates\n * a SchemaDiff with the differences.\n */\n\nimport { createLogger } from '@happyvertical/logger';\nimport { detectEngine, getDDLStrategy } from '../schema/ddl/index.js';\nimport type { DatabaseEngine } from '../schema/ddl/types.js';\nimport type {\n ColumnDefinition,\n IndexDefinition,\n SchemaChange,\n SchemaDefinition,\n SchemaDiff,\n SQLDataType,\n} from '../schema/types.js';\nimport { isJsonPathIndex, renderIndexTarget } from '../schema/utils.js';\nimport type { DatabaseInterface, SqlTableSchemaInfo } from './types.js';\n\nconst logger = createLogger({ level: 'info' });\n\n/**\n * Valid SQLDataType values for validation\n */\nconst VALID_SQL_DATA_TYPES: Set<SQLDataType> = new Set([\n 'TEXT',\n 'INTEGER',\n 'REAL',\n 'BLOB',\n 'BOOLEAN',\n 'JSON',\n 'TIMESTAMP',\n 'UUID',\n]);\n\ninterface GeneratedTypeUpgradeSQL {\n sql: string;\n statements?: string[];\n}\n\n/**\n * Check if a string is a valid SQLDataType\n */\nfunction isValidSQLDataType(type: string): type is SQLDataType {\n return VALID_SQL_DATA_TYPES.has(type as SQLDataType);\n}\n\n/**\n * Options for schema comparison\n */\nexport interface DiffOptions {\n /** Include dropped tables in diff (default: false for safety) */\n includeDroppedTables?: boolean;\n /** Include dropped columns in diff (default: false for safety) */\n includeDroppedColumns?: boolean;\n /**\n * Drop indexes that exist in the database but are absent from the manifest\n * AND are not functionally equivalent to anything in the manifest. Default:\n * false. The differ always skips primary-key indexes (`*_pkey`) and the\n * implicit indexes that PostgreSQL creates from inline UNIQUE constraints\n * (`*_key`) — those are owned by table-level constraints, not by the\n * index list, and dropping them here would break the constraint.\n */\n includeDroppedIndexes?: boolean;\n /** Ignore type mismatches (just log warnings) */\n ignoreTypeMismatches?: boolean;\n /**\n * Explicit engine hint forwarded to `detectEngine` when picking the DDL\n * strategy used for *existing-table* SQL (ALTER/CREATE INDEX/etc.). Use\n * this when `db.url` is empty or ambiguous (e.g. JSON adapter, in-memory\n * wrappers where the URL lives on `db.config?.url`). Without it the\n * comparer falls back to URL-only detection, which can produce SQLite-\n * flavored SQL on a connection whose caller meant Postgres or DuckDB.\n */\n engineHint?: string;\n}\n\n/**\n * Suffix patterns for indexes that the differ refuses to drop.\n * - `_pkey`: PostgreSQL primary key implicit index.\n * - `_key`: PostgreSQL implicit index for inline `UNIQUE (...)` table\n * constraints. Dropping these by name does not drop the underlying\n * constraint, and dropping the constraint requires a separate DDL path\n * (`ALTER TABLE ... DROP CONSTRAINT`) the differ does not emit today.\n */\nconst PROTECTED_INDEX_SUFFIXES = ['_pkey', '_key'];\n\nfunction isProtectedDbIndexName(name: string): boolean {\n return PROTECTED_INDEX_SUFFIXES.some((suffix) => name.endsWith(suffix));\n}\n\nfunction resolveDatabaseUrl(db: DatabaseInterface): string {\n const dbWithConfig = db as DatabaseInterface & {\n config?: { url?: string };\n };\n return db.url || dbWithConfig.config?.url || '';\n}\n\n/**\n * SchemaComparer class for comparing manifest schemas to database\n */\nexport class SchemaComparer {\n private db: DatabaseInterface;\n private options: DiffOptions;\n private engine: DatabaseEngine;\n private ddlStrategy: ReturnType<typeof getDDLStrategy>;\n\n constructor(db: DatabaseInterface, options: DiffOptions = {}) {\n this.db = db;\n this.options = {\n includeDroppedTables: false,\n includeDroppedColumns: false,\n includeDroppedIndexes: false,\n ignoreTypeMismatches: false,\n ...options,\n };\n // Use the shared detectEngine utility for consistent detection.\n // Handles :memory:, .json, and other edge cases. The JSON adapter is\n // detected structurally (it exposes `exportTable`) because its url can be\n // empty; otherwise fall back to URL-based detection, where `engineHint`\n // lets callers override when `db.url` is empty or points at an adapter\n // whose engine isn't obvious from the URL alone (some in-memory wrappers).\n this.engine =\n typeof (this.db as { exportTable?: unknown }).exportTable === 'function'\n ? 'json'\n : detectEngine(resolveDatabaseUrl(this.db), this.options.engineHint);\n this.ddlStrategy = getDDLStrategy(this.engine);\n }\n\n /**\n * Compare manifest schemas to database and return differences\n */\n async compare(\n manifestSchemas: Record<string, SchemaDefinition>,\n ): Promise<SchemaDiff> {\n const diff: SchemaDiff = {\n added_tables: [],\n dropped_tables: [],\n changes: [],\n has_changes: false,\n };\n\n // Get list of existing tables\n const existingTables = await this.getExistingTables();\n\n // Check each manifest schema against database\n for (const [tableName, schema] of Object.entries(manifestSchemas)) {\n if (!existingTables.has(tableName)) {\n // Table doesn't exist - add to added_tables\n diff.added_tables.push(schema);\n diff.has_changes = true;\n } else {\n // Table exists - compare columns and indexes\n const tableChanges = await this.compareTable(tableName, schema);\n if (tableChanges.length > 0) {\n diff.changes.push(...tableChanges);\n diff.has_changes = true;\n }\n }\n }\n\n // Check for dropped tables (if enabled)\n if (this.options.includeDroppedTables) {\n for (const tableName of existingTables) {\n // Skip system tables\n if (tableName.startsWith('_smrt_') || tableName.startsWith('sqlite_')) {\n continue;\n }\n if (!manifestSchemas[tableName]) {\n diff.dropped_tables.push(tableName);\n diff.has_changes = true;\n }\n }\n }\n\n return diff;\n }\n\n /**\n * Compare a single table's schema to manifest\n */\n async compareTable(\n tableName: string,\n manifest: SchemaDefinition,\n ): Promise<SchemaChange[]> {\n const changes: SchemaChange[] = [];\n\n // Get current table schema from database\n const dbSchema = await this.db.getTableSchema?.(tableName);\n if (!dbSchema) {\n // Table doesn't exist - this is an add_table case\n return changes;\n }\n\n // Compare columns\n const columnChanges = this.compareColumns(tableName, manifest, dbSchema);\n changes.push(...columnChanges);\n\n // Compare indexes\n const indexChanges = this.compareIndexes(tableName, manifest, dbSchema);\n changes.push(...indexChanges);\n\n return changes;\n }\n\n /**\n * Compare columns between manifest and database\n */\n private compareColumns(\n tableName: string,\n manifest: SchemaDefinition,\n dbSchema: SqlTableSchemaInfo,\n ): SchemaChange[] {\n const changes: SchemaChange[] = [];\n const dbColumnNames = new Set(Object.keys(dbSchema.columns));\n\n // Check for new and modified columns\n for (const [colName, colDef] of Object.entries(manifest.columns)) {\n if (!dbColumnNames.has(colName)) {\n // Column doesn't exist - add it\n changes.push({\n type: 'add_column',\n table: tableName,\n name: colName,\n column: colDef,\n sql: this.generateAddColumnSQL(tableName, colName, colDef),\n });\n } else {\n // Column exists - check for type mismatch\n const dbCol = dbSchema.columns[colName];\n\n // Map manifest's abstract type to engine-specific type\n // e.g., JSON → TEXT for SQLite, JSON → JSONB for PostgreSQL\n // Validate the manifest type before mapping\n const manifestType = colDef.type;\n if (!isValidSQLDataType(manifestType)) {\n // Invalid manifest type - treat as TEXT (safest fallback)\n logger.warn(\n `[SchemaComparer] Invalid manifest type \"${manifestType}\" for ${tableName}.${colName}, treating as TEXT`,\n );\n }\n const validatedType: SQLDataType = isValidSQLDataType(manifestType)\n ? manifestType\n : 'TEXT';\n const expectedEngineType = this.ddlStrategy.mapType(validatedType);\n const normalizedExpected = this.normalizeType(expectedEngineType);\n const normalizedActual = this.normalizeType(dbCol.type);\n\n // R11: native `uuid` and `text` are interchangeable for SMRT-owned\n // identifiers/references, but not for arbitrary provenance text. Keep\n // the tolerance directional:\n // - manifest UUID + DB text is tolerated for structural ID/ref\n // columns so old deployments are not forced into native UUID.\n // - manifest TEXT + DB uuid is tolerated only for structural ID/ref\n // columns that are intentionally UUID-compatible.\n // Plain TEXT columns with DB uuid now surface as repairable drift.\n const isUuidTextEquivalent = this.isUuidTextEquivalentColumn(\n colName,\n colDef,\n normalizedExpected,\n normalizedActual,\n );\n\n // #1335: native `json`/`jsonb` (DB) and `text` (manifest) are\n // interchangeable for SMRT — the convention is to serialize JSON values\n // into TEXT columns, and a native-json column already holds exactly that\n // data. So the differ must NOT flag a json<->text difference in EITHER\n // direction:\n // - manifest TEXT vs DB json (native-json column, text-convention manifest)\n // - manifest JSON vs DB text (the canary case: an enum/plain field\n // mis-inferred as JSON by a downstream scanner, sitting on a real\n // `text` column holding bare values like 'active')\n // Generating an ALTER here is pure churn at best and data-destroying at\n // worst: `status::jsonb` on a column holding 'active' raises\n // \"invalid input syntax for type json\" and aborts the whole atomic\n // migration. Like the uuid/text tolerance, this lives at the equality\n // gate only (not in `normalizeType`) so `isCompatibleTypeUpgrade` still\n // treats JSON and TEXT as distinct buckets for OTHER upgrade paths.\n const isJsonTextEquivalent =\n (normalizedExpected === 'JSON' && normalizedActual === 'TEXT') ||\n (normalizedExpected === 'TEXT' && normalizedActual === 'JSON');\n\n if (\n normalizedExpected !== normalizedActual &&\n !isUuidTextEquivalent &&\n !isJsonTextEquivalent\n ) {\n // Check if this is a safe type upgrade that SMRT can handle\n // Since SMRT owns the data lifecycle, we know the intent from the manifest\n if (this.isCompatibleTypeUpgrade(colDef.type, dbCol.type)) {\n // Generate type upgrade SQL\n const generatedSQL = this.generateTypeUpgradeSQL(\n tableName,\n colName,\n colDef,\n dbCol.type,\n );\n changes.push({\n type: 'type_upgrade',\n table: tableName,\n name: colName,\n column: colDef,\n mismatch: {\n expected: colDef.type,\n actual: dbCol.type,\n },\n sql: generatedSQL.sql,\n ...(generatedSQL.statements\n ? { sqlStatements: generatedSQL.statements }\n : {}),\n });\n } else if (!this.options.ignoreTypeMismatches) {\n changes.push({\n type: 'type_mismatch',\n table: tableName,\n name: colName,\n mismatch: {\n expected: colDef.type,\n actual: dbCol.type,\n },\n });\n }\n }\n }\n }\n\n // Check for dropped columns (if enabled)\n if (this.options.includeDroppedColumns) {\n const manifestColumnNames = new Set(Object.keys(manifest.columns));\n for (const colName of dbColumnNames) {\n if (!manifestColumnNames.has(colName)) {\n changes.push({\n type: 'drop_column',\n table: tableName,\n name: colName,\n sql: this.generateDropColumnSQL(tableName, colName),\n });\n }\n }\n }\n\n return changes;\n }\n\n private isUuidTextEquivalentColumn(\n columnName: string,\n colDef: ColumnDefinition,\n normalizedExpected: string,\n normalizedActual: string,\n ): boolean {\n const expectedUuidActualText =\n normalizedExpected === 'UUID' && normalizedActual === 'TEXT';\n const expectedTextActualUuid =\n normalizedExpected === 'TEXT' && normalizedActual === 'UUID';\n\n if (!expectedUuidActualText && !expectedTextActualUuid) {\n return false;\n }\n\n return this.isStructuralUuidCompatibleColumn(columnName, colDef);\n }\n\n private isStructuralUuidCompatibleColumn(\n columnName: string,\n colDef: ColumnDefinition,\n ): boolean {\n return (\n colDef.primaryKey === true ||\n Boolean(colDef.foreignKey) ||\n colDef.referenceKind === 'id' ||\n colDef.referenceKind === 'foreignKey' ||\n colDef.referenceKind === 'crossPackageRef' ||\n colDef.referenceKind === 'tenantId' ||\n (columnName === 'id' && colDef.type === 'TEXT')\n );\n }\n\n /**\n * Compare indexes between manifest and database\n *\n * Three classes of drift the differ now detects:\n *\n * 1. **Missing index** — manifest has an index neither the DB has by name\n * nor any equivalent-by-signature. Emit `add_index`. (Issue #741: the\n * signature check protects against creating duplicates when STI child\n * classes register indexes with different name prefixes.)\n *\n * 2. **Same-name shape drift** — DB has an index with the manifest's name,\n * but its columns or uniqueness flag differ. This is the failure mode\n * in issue #1165: `tenants_slug_context_meta_type_idx` exists but is\n * non-unique, while the manifest declares it unique. Emit\n * `drop_index` + `add_index` so the next migrate cycle recreates it\n * with the correct shape.\n *\n * 3. **Orphan in DB** — DB has an index with no manifest counterpart by\n * name and no signature equivalent. Emit `drop_index` *only* when the\n * caller opts in via `includeDroppedIndexes`, and even then never for\n * PostgreSQL implicit indexes (`*_pkey`, `*_key`) — those are owned by\n * table-level constraints and need a separate `DROP CONSTRAINT` path\n * that the differ does not emit yet.\n */\n private compareIndexes(\n tableName: string,\n manifest: SchemaDefinition,\n dbSchema: SqlTableSchemaInfo,\n ): SchemaChange[] {\n const changes: SchemaChange[] = [];\n\n // Index DB indexes by name and by signature for fast lookup.\n // dbIndexSignatures groups *all* DB index names sharing a signature so\n // duplicates under different names all get claimed by a single matching\n // manifest entry — otherwise the orphan sweep would drop the un-claimed\n // siblings even though they are functionally equivalent to the manifest.\n const dbIndexesByName = new Map<\n string,\n { columns: string[]; unique: boolean }\n >();\n const dbIndexSignatures = new Map<string, Set<string>>();\n for (const idx of dbSchema.indexes) {\n const unique = idx.unique ?? false;\n dbIndexesByName.set(idx.name, { columns: idx.columns, unique });\n const signature = this.getIndexSignature(idx.columns, unique);\n let bucket = dbIndexSignatures.get(signature);\n if (!bucket) {\n bucket = new Set();\n dbIndexSignatures.set(signature, bucket);\n }\n bucket.add(idx.name);\n }\n\n // Manifest signatures — used during the orphan sweep to skip DB indexes\n // that match a manifest entry's signature even if no specific manifest\n // entry \"claimed\" them by name.\n const manifestSignatureSet = new Set<string>();\n for (const idx of manifest.indexes) {\n manifestSignatureSet.add(this.getIndexSignature(idx));\n }\n\n // Track which DB indexes a manifest entry has claimed, so the orphan\n // pass below doesn't re-flag indexes that match by signature alone.\n const claimedDbIndexes = new Set<string>();\n\n for (const idx of manifest.indexes) {\n const manifestSignature = this.getIndexSignature(idx);\n\n // (a) Same name in DB — verify shape matches.\n const dbByName = dbIndexesByName.get(idx.name);\n if (dbByName) {\n claimedDbIndexes.add(idx.name);\n\n // JSON-path indexes (`@meta({ indexed: true })`) cannot be reliably\n // compared by DB introspection — SQLite expression indexes surface\n // as `[null]` columns, so the signature would always mismatch and\n // every diff run would emit drop+recreate. Trust the name match\n // here; if the json path itself changes, the index name changes\n // too (we encode the field name into it), so a name match is a\n // stronger guarantee than the column list for this index family.\n if (isJsonPathIndex(idx)) {\n continue;\n }\n\n const dbSignature = this.getIndexSignature(\n dbByName.columns,\n dbByName.unique,\n );\n if (dbSignature === manifestSignature) {\n continue; // Same name, same shape — nothing to do.\n }\n\n // Same name, drifted shape. Most often this is a uniqueness flip\n // (issue #1165: 3-column index materialized non-unique). Recreate.\n //\n // Rollback caveat: the auto-generated DOWN script for the\n // `add_index` half drops the (newly correct) index, and the\n // `drop_index` half has no DOWN. Rolling back a recreate leaves\n // the table without the index entirely instead of restoring the\n // wrong-shape original. Capturing the original shape would\n // require richer DB introspection than the differ currently has,\n // so this asymmetry is accepted — the failure mode after an\n // un-rolled-back recreate is \"missing index\" rather than\n // \"permanently broken UPSERT,\" which is recoverable.\n changes.push({\n type: 'drop_index',\n table: tableName,\n name: idx.name,\n sql: this.generateDropIndexSQL(idx.name),\n });\n changes.push({\n type: 'add_index',\n table: tableName,\n name: idx.name,\n index: idx,\n sql: this.generateAddIndexSQL(tableName, idx),\n });\n continue;\n }\n\n // (b) Different name in DB but functionally equivalent — keep as-is.\n // Claim *every* DB name sharing this signature so duplicate-shape\n // indexes (e.g., a stale `<name>_idx` plus the implicit `<name>_key`\n // from the same constraint) all survive the orphan sweep.\n const equivalentIndexNames = dbIndexSignatures.get(manifestSignature);\n if (equivalentIndexNames && equivalentIndexNames.size > 0) {\n for (const name of equivalentIndexNames) {\n claimedDbIndexes.add(name);\n }\n continue;\n }\n\n // (c) Genuinely missing — add it.\n changes.push({\n type: 'add_index',\n table: tableName,\n name: idx.name,\n index: idx,\n sql: this.generateAddIndexSQL(tableName, idx),\n });\n }\n\n // Orphan-index sweep (opt-in via includeDroppedIndexes).\n if (this.options.includeDroppedIndexes) {\n for (const idx of dbSchema.indexes) {\n if (claimedDbIndexes.has(idx.name)) continue;\n if (isProtectedDbIndexName(idx.name)) continue;\n\n // Belt-and-suspenders: even if a DB index wasn't formally claimed\n // by a manifest entry (e.g., shape-drift recreate consumed the\n // claim slot), don't drop it if its signature still matches\n // something the manifest declares. That would contradict the\n // option doc (\"not functionally equivalent to anything in the\n // manifest\") and risk dropping a still-needed index.\n const idxSignature = this.getIndexSignature(\n idx.columns,\n idx.unique ?? false,\n );\n if (manifestSignatureSet.has(idxSignature)) continue;\n\n changes.push({\n type: 'drop_index',\n table: tableName,\n name: idx.name,\n sql: this.generateDropIndexSQL(idx.name),\n });\n }\n }\n\n return changes;\n }\n\n /**\n * Generate a signature for an index based on its columns and uniqueness.\n * Used for functional equivalence checking (Issue #741).\n *\n * Note: Column order is preserved because it is semantically significant for\n * composite indexes. An index on (a, b) is NOT equivalent to (b, a) - they\n * have different query performance characteristics.\n *\n * Limitation: Partial indexes (with WHERE clauses) are not fully supported.\n * The database introspection layer doesn't provide WHERE clause information,\n * so two partial indexes with the same columns but different WHERE clauses\n * cannot be distinguished and may be incorrectly treated as equivalent.\n *\n * For JSON-path indexes (`@meta({ indexed: true })`) the signature is\n * derived from the JSON path instead of an empty column list, so the\n * differ can distinguish two jsonPath indexes against different paths.\n *\n * @param idxOrColumns - Either an IndexDefinition or a column array (legacy)\n * @param uniqueArg - Unique flag (used when first arg is a column array)\n * @returns Signature string\n */\n private getIndexSignature(\n idxOrColumns: IndexDefinition | string[],\n uniqueArg?: boolean,\n ): string {\n if (Array.isArray(idxOrColumns)) {\n return `${idxOrColumns.join(',')}:${Boolean(uniqueArg)}`;\n }\n const idx = idxOrColumns;\n if (isJsonPathIndex(idx) && idx.jsonPath) {\n return `json:${idx.jsonPath.column}.${idx.jsonPath.path}:${Boolean(idx.unique)}`;\n }\n return `${(idx.columns ?? []).join(',')}:${Boolean(idx.unique)}`;\n }\n\n /**\n * Get list of existing tables from database\n */\n private async getExistingTables(): Promise<Set<string>> {\n let query: string;\n if (this.engine === 'postgres') {\n query = `SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'`;\n } else {\n // SQLite and DuckDB\n query = `SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'`;\n }\n\n const result = await this.db.query(query);\n const rows = result.rows as { name?: string; table_name?: string }[];\n return new Set(\n rows.map((r) => r.name || r.table_name || '').filter(Boolean),\n );\n }\n\n /**\n * Normalize SQL types for comparison\n */\n private normalizeType(type: string): string {\n const upper = type.toUpperCase().trim();\n\n // Integer types\n if (/^(INTEGER|INT|BIGINT|SMALLINT|TINYINT)$/i.test(upper)) {\n return 'INTEGER';\n }\n\n // Text types\n if (/^(TEXT|CLOB|STRING|VARCHAR|CHAR)/i.test(upper)) {\n return 'TEXT';\n }\n\n // UUID normalizes to its own bucket — deliberately NOT folded into TEXT.\n // The text<->uuid drift tolerance (R11) is applied at the equality gate\n // in `compare()` only, so that `isCompatibleTypeUpgrade` (which also\n // calls normalizeType) still treats `uuid` as distinct from text and\n // won't mis-classify e.g. `uuid`->`timestamp` as a compatible\n // \"TEXT->TIMESTAMP\" upgrade.\n if (/^UUID$/i.test(upper)) {\n return 'UUID';\n }\n\n // Decimal types\n if (/^(REAL|FLOAT|DOUBLE|DECIMAL|NUMERIC|NUMBER)/i.test(upper)) {\n return 'REAL';\n }\n\n // Boolean types\n if (/^(BOOLEAN|BOOL)/i.test(upper)) {\n return 'BOOLEAN';\n }\n\n // Date/time types\n if (/^(DATETIME|TIMESTAMP|DATE|TIME)/i.test(upper)) {\n return 'TIMESTAMP';\n }\n\n // Blob types\n if (/^(BLOB|BINARY|BYTEA)/i.test(upper)) {\n return 'BLOB';\n }\n\n // JSON types\n if (/^(JSON|JSONB)/i.test(upper)) {\n return 'JSON';\n }\n\n return upper;\n }\n\n /**\n * Check if a type change is a safe upgrade that can be auto-migrated.\n *\n * SMRT controls the data lifecycle for these columns, so we know:\n * - TEXT→JSON: The column stores JSON data serialized as text (arrays, objects)\n * - TEXT/JSON→TIMESTAMP: Legacy system columns stored timestamp strings\n * before newer manifests normalized the column type.\n * - INTEGER→REAL: Safe widening of integer to floating point\n * - TEXT/REAL→INTEGER on PostgreSQL: explicit data-checked repairs for\n * legacy integer columns that were previously stored as text/real.\n *\n * @param manifestType - The abstract type from the manifest (e.g., 'JSON')\n * @param dbType - The actual type in the database (e.g., 'TEXT')\n * @returns true if the change from dbType to manifestType is a safe upgrade\n */\n private isCompatibleTypeUpgrade(\n manifestType: string,\n dbType: string,\n ): boolean {\n const manifest = this.normalizeType(manifestType);\n const db = this.normalizeType(dbType);\n\n // TEXT → JSON is safe: SMRT serializes arrays/objects as JSON text\n // When the manifest says JSON, the data is already valid JSON in TEXT column\n if (manifest === 'JSON' && db === 'TEXT') {\n return true;\n }\n\n // JSON → TEXT is also safe (downgrade, but data is preserved as-is)\n if (manifest === 'TEXT' && db === 'JSON') {\n return true;\n }\n\n // UUID → TEXT is safe for plain text/provenance fields that were\n // mistakenly materialized as native uuid: the stored UUID value can be\n // rendered losslessly as text.\n if (manifest === 'TEXT' && db === 'UUID') {\n return true;\n }\n\n // INTEGER → REAL is safe (widening)\n if (manifest === 'REAL' && db === 'INTEGER') {\n return true;\n }\n\n // PostgreSQL can safely repair legacy integer columns when the generated\n // migration validates that every existing value is already an integer.\n if (\n this.engine === 'postgres' &&\n manifest === 'INTEGER' &&\n (db === 'TEXT' || db === 'REAL')\n ) {\n return true;\n }\n\n // TEXT/JSON → TIMESTAMP is a legacy-drift repair. Invalid values fail\n // explicitly during migration rather than being silently coerced.\n if (manifest === 'TIMESTAMP' && (db === 'TEXT' || db === 'JSON')) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Generate SQL for a type upgrade migration.\n *\n * Engine-specific SQL:\n * - SQLite: TEXT and JSON are equivalent, no-op or comment\n * - DuckDB: ALTER COLUMN TYPE (native type conversion)\n * - PostgreSQL: ALTER COLUMN TYPE with USING clause\n */\n private generateTypeUpgradeSQL(\n tableName: string,\n colName: string,\n colDef: ColumnDefinition,\n dbType: string,\n ): GeneratedTypeUpgradeSQL {\n const quotedTable = this.quoteIdentifier(tableName);\n const quotedCol = this.quoteIdentifier(colName);\n const manifestType = colDef.type;\n\n // Validate manifestType before mapping\n const validatedType: SQLDataType = isValidSQLDataType(manifestType)\n ? manifestType\n : 'TEXT';\n const targetType = this.ddlStrategy.mapType(validatedType);\n\n switch (this.engine) {\n case 'sqlite':\n // SQLite has dynamic typing - TEXT and JSON are functionally equivalent\n // For SQLite, we just return a comment since no actual change is needed\n if (\n this.normalizeType(manifestType) === 'JSON' &&\n this.normalizeType(dbType) === 'TEXT'\n ) {\n return {\n sql: `-- SQLite: ${quotedCol} already stores JSON as TEXT (no change needed)`,\n };\n }\n // For other type upgrades, SQLite requires recreating the table\n return {\n sql: `-- SQLite: Type upgrade for ${quotedCol} requires table recreation`,\n };\n\n case 'postgres': {\n // PostgreSQL defaults must be dropped/reset around some type changes\n // so drift repairs can succeed even when an existing default cannot\n // be cast automatically to the target type.\n const manifestNormalized = this.normalizeType(manifestType);\n const dbNormalized = this.normalizeType(dbType);\n const preflightSQL =\n manifestNormalized === 'INTEGER' &&\n (dbNormalized === 'TEXT' || dbNormalized === 'REAL')\n ? this.generatePostgresIntegerPreflightSQL(\n quotedTable,\n quotedCol,\n tableName,\n colName,\n dbNormalized,\n )\n : null;\n const clauses: string[] = [];\n\n if (colDef.defaultValue !== undefined) {\n clauses.push(`ALTER COLUMN ${quotedCol} DROP DEFAULT`);\n }\n\n let typeClause = `ALTER COLUMN ${quotedCol} TYPE ${targetType}`;\n if (manifestNormalized === 'JSON' && dbNormalized === 'TEXT') {\n // #1335: a bare `${col}::jsonb` cast raises \"invalid input syntax for\n // type json\" on any row whose text is not already valid JSON (e.g. a\n // legacy enum column holding 'active'). `to_jsonb(col)` instead wraps\n // ANY text value as a JSON string and never errors, so a genuine\n // TEXT->JSON widening survives non-JSON legacy data. (Note: with the\n // json<->text equality tolerance added in this fix, the normal\n // compare path no longer reaches here; this keeps the SQL safe for\n // callers that construct a type_upgrade directly.)\n typeClause += ` USING to_jsonb(${quotedCol})`;\n } else if (manifestNormalized === 'TEXT' && dbNormalized === 'JSON') {\n // #1335: a native-json column cast back to text is value-preserving\n // (`::text` renders the stored JSON as its text form), so this arm is\n // safe. (Note: like the TEXT->JSON arm above, the json<->text equality\n // tolerance means the normal compare path no longer reaches here; this\n // keeps the SQL safe for callers that construct a type_upgrade\n // directly.)\n typeClause += ` USING ${quotedCol}::text`;\n } else if (manifestNormalized === 'TEXT' && dbNormalized === 'UUID') {\n typeClause += ` USING ${quotedCol}::text`;\n } else if (\n manifestNormalized === 'INTEGER' &&\n dbNormalized === 'TEXT'\n ) {\n typeClause += ` USING trim(${quotedCol}::text)::integer`;\n } else if (\n manifestNormalized === 'INTEGER' &&\n dbNormalized === 'REAL'\n ) {\n typeClause += ` USING ${quotedCol}::integer`;\n } else if (\n manifestNormalized === 'TIMESTAMP' &&\n (dbNormalized === 'TEXT' || dbNormalized === 'JSON')\n ) {\n typeClause += ` USING NULLIF(NULLIF(trim(both '\"' from ${quotedCol}::text), ''), 'null')::timestamp`;\n }\n\n clauses.push(typeClause);\n\n if (colDef.defaultValue !== undefined) {\n const formattedDefault = this.ddlStrategy.formatDefaultValue(\n colDef.defaultValue,\n validatedType,\n );\n const defaultSql =\n manifestNormalized === 'JSON'\n ? `${formattedDefault}::${targetType.toLowerCase()}`\n : formattedDefault;\n clauses.push(`ALTER COLUMN ${quotedCol} SET DEFAULT ${defaultSql}`);\n }\n\n const alterSql = `ALTER TABLE ${quotedTable} ${clauses.join(', ')}`;\n\n return preflightSQL\n ? { sql: alterSql, statements: [preflightSQL, alterSql] }\n : { sql: alterSql };\n }\n\n case 'duckdb':\n // DuckDB supports ALTER COLUMN TYPE for type conversions\n return {\n sql: `ALTER TABLE ${quotedTable} ALTER COLUMN ${quotedCol} TYPE ${targetType}`,\n };\n\n default: {\n // Escape special characters in type names for safe comment generation\n const safeDbType = dbType.replace(/[^\\w]/g, '_');\n const safeManifestType = manifestType.replace(/[^\\w]/g, '_');\n return {\n sql: `-- Type upgrade for ${quotedCol}: ${safeDbType} → ${safeManifestType}`,\n };\n }\n }\n }\n\n /**\n * Quote a SQL identifier\n */\n private quoteIdentifier(name: string): string {\n return `\"${name.replace(/\"/g, '\"\"')}\"`;\n }\n\n /**\n * Generate a PostgreSQL preflight guard for narrowing legacy columns to\n * INTEGER. PostgreSQL's REAL→INTEGER cast rounds fractional values, so the\n * generated migration must fail before the ALTER can silently change data.\n */\n private generatePostgresIntegerPreflightSQL(\n quotedTable: string,\n quotedCol: string,\n tableName: string,\n colName: string,\n dbNormalized: string,\n ): string {\n const invalidCondition =\n dbNormalized === 'REAL'\n ? `${quotedCol} IS NOT NULL AND ${quotedCol} <> trunc(${quotedCol})`\n : `${quotedCol} IS NOT NULL AND trim(${quotedCol}::text) !~ '^[+-]?[0-9]+$'`;\n const message = `Cannot convert ${tableName}.${colName} to INTEGER: found non-integer values`;\n\n return `DO $$ BEGIN IF EXISTS (SELECT 1 FROM ${quotedTable} WHERE ${invalidCondition}) THEN RAISE EXCEPTION ${this.quoteLiteral(message)}; END IF; END $$`;\n }\n\n private quoteLiteral(value: string): string {\n return `'${value.replace(/'/g, \"''\")}'`;\n }\n\n /**\n * Generate SQL for adding a column\n */\n private generateAddColumnSQL(\n tableName: string,\n colName: string,\n colDef: ColumnDefinition,\n ): string {\n // Build the ADD COLUMN definition inline (main) rather than delegating to\n // the DDL strategy's generateColumnDefinition: that builder is for CREATE\n // TABLE and would emit `PRIMARY KEY` (invalid in ALTER ... ADD COLUMN) and\n // suppress single-column UNIQUE on engines that require inline unique at\n // table-create time (DuckDB) — but an ADD COLUMN has no inline-constraint\n // pass, so the UNIQUE must be emitted here. mapType still maps abstract\n // types per dialect (UUID→native uuid / TEXT — R11); invalid types fall\n // back to TEXT, matching the compareColumns guard.\n const validatedType: SQLDataType = isValidSQLDataType(colDef.type)\n ? colDef.type\n : 'TEXT';\n if (!isValidSQLDataType(colDef.type)) {\n logger.warn(\n `[SchemaComparer] Invalid manifest type \"${colDef.type}\" for ${tableName}.${colName}, treating as TEXT`,\n );\n }\n\n const parts: string[] = [\n this.quoteIdentifier(colName),\n this.ddlStrategy.mapType(validatedType),\n ];\n\n if (colDef.notNull) {\n parts.push('NOT NULL');\n }\n if (colDef.unique) {\n parts.push('UNIQUE');\n }\n if (colDef.defaultValue !== undefined) {\n const defaultVal = this.ddlStrategy.formatDefaultValue(\n colDef.defaultValue,\n validatedType,\n );\n parts.push(`DEFAULT ${defaultVal}`);\n }\n if (colDef.check) {\n parts.push(`CHECK (${colDef.check})`);\n }\n\n const columnDefinition = parts.join(' ');\n\n return `ALTER TABLE ${this.quoteIdentifier(tableName)} ADD COLUMN ${columnDefinition}`;\n }\n\n /**\n * Generate SQL for dropping a column\n */\n private generateDropColumnSQL(tableName: string, colName: string): string {\n return `ALTER TABLE ${this.quoteIdentifier(tableName)} DROP COLUMN ${this.quoteIdentifier(colName)}`;\n }\n\n /**\n * Generate SQL for adding an index\n */\n private generateAddIndexSQL(tableName: string, idx: IndexDefinition): string {\n const uniqueStr = idx.unique ? 'UNIQUE ' : '';\n const target = renderIndexTarget(idx, this.engine);\n return `CREATE ${uniqueStr}INDEX ${this.quoteIdentifier(idx.name)} ON ${this.quoteIdentifier(tableName)} (${target})`;\n }\n\n /**\n * Generate SQL for dropping an index.\n *\n * This SQL is consumed by the manifest-driven execution path:\n *\n * - `db:migrate` runs the SQL we put in `change.sql` directly, with the\n * tracker's `executePostgresStatements` adding CONCURRENTLY when\n * `--postgres-safe` is on.\n *\n * PostgreSQL ends up with `CONCURRENTLY` when it should.\n * Keeping this method engine-agnostic also means the diff preview text\n * stays readable (no engine-specific noise) for engines like SQLite\n * where CONCURRENTLY isn't a thing.\n */\n private generateDropIndexSQL(indexName: string): string {\n return `DROP INDEX IF EXISTS ${this.quoteIdentifier(indexName)}`;\n }\n}\n\n/**\n * Generate a SchemaDiff from manifest and database\n */\nexport async function generateSchemaDiff(\n db: DatabaseInterface,\n manifestSchemas: Record<string, SchemaDefinition>,\n options: DiffOptions = {},\n): Promise<SchemaDiff> {\n const comparer = new SchemaComparer(db, options);\n return comparer.compare(manifestSchemas);\n}\n\n/**\n * Check if a diff has any actionable changes (excluding type mismatches)\n */\nexport function hasActionableChanges(diff: SchemaDiff): boolean {\n if (diff.added_tables.length > 0) return true;\n if (diff.dropped_tables.length > 0) return true;\n return diff.changes.some((c) => c.type !== 'type_mismatch');\n}\n\n/**\n * Get SQL statements from a diff for execution\n */\nexport function getSQLFromDiff(diff: SchemaDiff): string[] {\n const statements: string[] = [];\n\n // Add table creation (requires full DDL generation - not included here)\n // This is typically handled by ensureSchema()\n\n // Add column and index changes\n for (const change of diff.changes) {\n if (change.type !== 'type_mismatch') {\n statements.push(\n ...(change.sqlStatements ?? (change.sql ? [change.sql] : [])),\n );\n }\n }\n\n return statements;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"differ.js","sources":["../../src/migrations/differ.ts"],"sourcesContent":["/**\n * Schema Differ\n *\n * Compares manifest schemas to database schemas and generates\n * a SchemaDiff with the differences.\n */\n\nimport { createLogger } from '@happyvertical/logger';\nimport { detectEngine, getDDLStrategy } from '../schema/ddl/index.js';\nimport type { DatabaseEngine } from '../schema/ddl/types.js';\nimport type {\n ColumnDefinition,\n IndexDefinition,\n SchemaChange,\n SchemaDefinition,\n SchemaDiff,\n SQLDataType,\n} from '../schema/types.js';\nimport { isJsonPathIndex, renderIndexTarget } from '../schema/utils.js';\nimport type { DatabaseInterface, SqlTableSchemaInfo } from './types.js';\n\nconst logger = createLogger({ level: 'info' });\n\n/**\n * Valid SQLDataType values for validation\n */\nconst VALID_SQL_DATA_TYPES: Set<SQLDataType> = new Set([\n 'TEXT',\n 'INTEGER',\n 'REAL',\n 'BLOB',\n 'BOOLEAN',\n 'JSON',\n 'TIMESTAMP',\n 'UUID',\n]);\n\ninterface GeneratedTypeUpgradeSQL {\n sql: string;\n statements?: string[];\n}\n\n/**\n * Check if a string is a valid SQLDataType\n */\nfunction isValidSQLDataType(type: string): type is SQLDataType {\n return VALID_SQL_DATA_TYPES.has(type as SQLDataType);\n}\n\n/**\n * Options for schema comparison\n */\nexport interface DiffOptions {\n /** Include dropped tables in diff (default: false for safety) */\n includeDroppedTables?: boolean;\n /** Include dropped columns in diff (default: false for safety) */\n includeDroppedColumns?: boolean;\n /**\n * Drop indexes that exist in the database but are absent from the manifest\n * AND are not functionally equivalent to anything in the manifest. Default:\n * false. The differ always skips primary-key indexes (`*_pkey`) and the\n * implicit indexes that PostgreSQL creates from inline UNIQUE constraints\n * (`*_key`) — those are owned by table-level constraints, not by the\n * index list, and dropping them here would break the constraint.\n */\n includeDroppedIndexes?: boolean;\n /** Ignore type mismatches (just log warnings) */\n ignoreTypeMismatches?: boolean;\n /**\n * Explicit engine hint forwarded to `detectEngine` when picking the DDL\n * strategy used for *existing-table* SQL (ALTER/CREATE INDEX/etc.). Use\n * this when `db.url` is empty or ambiguous (e.g. JSON adapter, in-memory\n * wrappers where the URL lives on `db.config?.url`). Without it the\n * comparer falls back to URL-only detection, which can produce SQLite-\n * flavored SQL on a connection whose caller meant Postgres or DuckDB.\n */\n engineHint?: string;\n}\n\n/**\n * Suffix patterns for indexes that the differ refuses to drop.\n * - `_pkey`: PostgreSQL primary key implicit index.\n * - `_key`: PostgreSQL implicit index for inline `UNIQUE (...)` table\n * constraints. Dropping these by name does not drop the underlying\n * constraint, and dropping the constraint requires a separate DDL path\n * (`ALTER TABLE ... DROP CONSTRAINT`) the differ does not emit today.\n */\nconst PROTECTED_INDEX_SUFFIXES = ['_pkey', '_key'];\n\nfunction isProtectedDbIndexName(name: string): boolean {\n return PROTECTED_INDEX_SUFFIXES.some((suffix) => name.endsWith(suffix));\n}\n\nfunction resolveDatabaseUrl(db: DatabaseInterface): string {\n const dbWithConfig = db as DatabaseInterface & {\n config?: { url?: string };\n };\n return db.url || dbWithConfig.config?.url || '';\n}\n\n/**\n * Normalize a partial-index `WHERE` predicate so semantically-identical\n * clauses from different sources compare equal (issue #1692).\n *\n * The manifest stores predicates roughly as written (`_meta_type = 'Article'`),\n * SQLite/DuckDB echo the original CREATE INDEX text verbatim, and PostgreSQL\n * re-renders them with type casts and extra parentheses\n * (`((_meta_type)::text = 'Article'::text)`). Normalization:\n *\n * - strips a leading `WHERE` keyword,\n * - removes PostgreSQL `::type` casts (single-word type names — the only kind\n * SMRT-generated partial predicates produce, e.g. `_meta_type::text`),\n * - removes parentheses (SMRT only emits simple `col = 'literal'` predicates,\n * so grouping carries no meaning here),\n * - lowercases everything OUTSIDE single-quoted string literals (SQL keywords\n * and identifiers are case-insensitive; literals such as STI discriminator\n * class names are case-sensitive, so they are preserved verbatim),\n * - collapses whitespace and tightens spacing around comparison operators.\n *\n * Returns '' for an absent/empty predicate (i.e. a non-partial index).\n */\nexport function normalizeIndexPredicate(where?: string | null): string {\n if (!where) return '';\n const stripped = where.trim().replace(/^WHERE\\s+/i, '');\n if (!stripped) return '';\n\n let out = '';\n let i = 0;\n while (i < stripped.length) {\n if (stripped[i] === \"'\") {\n // Consume a single-quoted string literal verbatim, honoring the SQL\n // `''` escape for an embedded quote.\n let literal = \"'\";\n i++;\n while (i < stripped.length) {\n if (stripped[i] === \"'\") {\n if (stripped[i + 1] === \"'\") {\n literal += \"''\";\n i += 2;\n continue;\n }\n literal += \"'\";\n i++;\n break;\n }\n literal += stripped[i];\n i++;\n }\n out += literal;\n } else {\n let run = '';\n while (i < stripped.length && stripped[i] !== \"'\") {\n run += stripped[i];\n i++;\n }\n out += normalizeNonLiteralPredicateRun(run);\n }\n }\n return out;\n}\n\n/**\n * Normalize the non-literal portion of a predicate (everything outside a\n * single-quoted string literal). Type casts and parentheses are dropped,\n * keywords/identifiers are lowercased, and whitespace is canonicalized.\n */\nfunction normalizeNonLiteralPredicateRun(run: string): string {\n return run\n .replace(/::[A-Za-z_]\\w*/g, '') // drop single-word PostgreSQL type casts\n .replace(/[()]/g, '') // drop parentheses\n .toLowerCase()\n .replace(/\\s+/g, ' ')\n .replace(/\\s*([=<>!]+)\\s*/g, '$1') // tighten comparison operators\n .trim();\n}\n\n/**\n * Extract the normalized partial-index predicate from a `CREATE INDEX`\n * statement — the `WHERE` tail that follows the column-list close paren.\n * Works for both SQLite/DuckDB `sqlite_master.sql` text and PostgreSQL\n * `pg_indexes.indexdef`. Returns '' for a non-partial index.\n */\nexport function extractIndexPredicate(createIndexSql: string): string {\n // The predicate is the tail after the column-list ')': `... (cols) WHERE x`.\n // Anchoring on `) WHERE` (rather than a bare `WHERE`) avoids matching a\n // column literally named \"where\" inside the indexed column list.\n const match = createIndexSql.match(/\\)\\s*WHERE\\s+([\\s\\S]+?)\\s*;?\\s*$/i);\n if (!match) return '';\n return normalizeIndexPredicate(match[1]);\n}\n\n/**\n * SchemaComparer class for comparing manifest schemas to database\n */\nexport class SchemaComparer {\n private db: DatabaseInterface;\n private options: DiffOptions;\n private engine: DatabaseEngine;\n private ddlStrategy: ReturnType<typeof getDDLStrategy>;\n\n constructor(db: DatabaseInterface, options: DiffOptions = {}) {\n this.db = db;\n this.options = {\n includeDroppedTables: false,\n includeDroppedColumns: false,\n includeDroppedIndexes: false,\n ignoreTypeMismatches: false,\n ...options,\n };\n // Use the shared detectEngine utility for consistent detection.\n // Handles :memory:, .json, and other edge cases. The JSON adapter is\n // detected structurally (it exposes `exportTable`) because its url can be\n // empty; otherwise fall back to URL-based detection, where `engineHint`\n // lets callers override when `db.url` is empty or points at an adapter\n // whose engine isn't obvious from the URL alone (some in-memory wrappers).\n this.engine =\n typeof (this.db as { exportTable?: unknown }).exportTable === 'function'\n ? 'json'\n : detectEngine(resolveDatabaseUrl(this.db), this.options.engineHint);\n this.ddlStrategy = getDDLStrategy(this.engine);\n }\n\n /**\n * Compare manifest schemas to database and return differences\n */\n async compare(\n manifestSchemas: Record<string, SchemaDefinition>,\n ): Promise<SchemaDiff> {\n const diff: SchemaDiff = {\n added_tables: [],\n dropped_tables: [],\n changes: [],\n has_changes: false,\n };\n\n // Get list of existing tables\n const existingTables = await this.getExistingTables();\n\n // Check each manifest schema against database\n for (const [tableName, schema] of Object.entries(manifestSchemas)) {\n if (!existingTables.has(tableName)) {\n // Table doesn't exist - add to added_tables\n diff.added_tables.push(schema);\n diff.has_changes = true;\n } else {\n // Table exists - compare columns and indexes\n const tableChanges = await this.compareTable(tableName, schema);\n if (tableChanges.length > 0) {\n diff.changes.push(...tableChanges);\n diff.has_changes = true;\n }\n }\n }\n\n // Check for dropped tables (if enabled)\n if (this.options.includeDroppedTables) {\n for (const tableName of existingTables) {\n // Skip system tables\n if (tableName.startsWith('_smrt_') || tableName.startsWith('sqlite_')) {\n continue;\n }\n if (!manifestSchemas[tableName]) {\n diff.dropped_tables.push(tableName);\n diff.has_changes = true;\n }\n }\n }\n\n return diff;\n }\n\n /**\n * Compare a single table's schema to manifest\n */\n async compareTable(\n tableName: string,\n manifest: SchemaDefinition,\n ): Promise<SchemaChange[]> {\n const changes: SchemaChange[] = [];\n\n // Get current table schema from database\n const dbSchema = await this.db.getTableSchema?.(tableName);\n if (!dbSchema) {\n // Table doesn't exist - this is an add_table case\n return changes;\n }\n\n // Compare columns\n const columnChanges = this.compareColumns(tableName, manifest, dbSchema);\n changes.push(...columnChanges);\n\n // Partial-index predicates are not surfaced by `getTableSchema()` (the\n // @happyvertical/sql introspection returns only name/columns/unique), so\n // introspect them separately. Without this, two indexes on the same\n // column(s) that differ only by their WHERE clause — e.g. distinct STI\n // child partial indexes — would compare equal and the differ would miss\n // adds/drops/changes of the predicate (issue #1692).\n const dbIndexPredicates = await this.getDbIndexPredicates(tableName);\n\n // Compare indexes\n const indexChanges = this.compareIndexes(\n tableName,\n manifest,\n dbSchema,\n dbIndexPredicates,\n );\n changes.push(...indexChanges);\n\n return changes;\n }\n\n /**\n * Compare columns between manifest and database\n */\n private compareColumns(\n tableName: string,\n manifest: SchemaDefinition,\n dbSchema: SqlTableSchemaInfo,\n ): SchemaChange[] {\n const changes: SchemaChange[] = [];\n const dbColumnNames = new Set(Object.keys(dbSchema.columns));\n\n // Check for new and modified columns\n for (const [colName, colDef] of Object.entries(manifest.columns)) {\n if (!dbColumnNames.has(colName)) {\n // Column doesn't exist - add it\n changes.push({\n type: 'add_column',\n table: tableName,\n name: colName,\n column: colDef,\n sql: this.generateAddColumnSQL(tableName, colName, colDef),\n });\n } else {\n // Column exists - check for type mismatch\n const dbCol = dbSchema.columns[colName];\n\n // Map manifest's abstract type to engine-specific type\n // e.g., JSON → TEXT for SQLite, JSON → JSONB for PostgreSQL\n // Validate the manifest type before mapping\n const manifestType = colDef.type;\n if (!isValidSQLDataType(manifestType)) {\n // Invalid manifest type - treat as TEXT (safest fallback)\n logger.warn(\n `[SchemaComparer] Invalid manifest type \"${manifestType}\" for ${tableName}.${colName}, treating as TEXT`,\n );\n }\n const validatedType: SQLDataType = isValidSQLDataType(manifestType)\n ? manifestType\n : 'TEXT';\n const expectedEngineType = this.ddlStrategy.mapType(validatedType);\n const normalizedExpected = this.normalizeType(expectedEngineType);\n const normalizedActual = this.normalizeType(dbCol.type);\n\n // R11: native `uuid` and `text` are interchangeable for SMRT-owned\n // identifiers/references, but not for arbitrary provenance text. Keep\n // the tolerance directional:\n // - manifest UUID + DB text is tolerated for structural ID/ref\n // columns so old deployments are not forced into native UUID.\n // - manifest TEXT + DB uuid is tolerated only for structural ID/ref\n // columns that are intentionally UUID-compatible.\n // Plain TEXT columns with DB uuid now surface as repairable drift.\n const isUuidTextEquivalent = this.isUuidTextEquivalentColumn(\n colName,\n colDef,\n normalizedExpected,\n normalizedActual,\n );\n\n // #1335: native `json`/`jsonb` (DB) and `text` (manifest) are\n // interchangeable for SMRT — the convention is to serialize JSON values\n // into TEXT columns, and a native-json column already holds exactly that\n // data. So the differ must NOT flag a json<->text difference in EITHER\n // direction:\n // - manifest TEXT vs DB json (native-json column, text-convention manifest)\n // - manifest JSON vs DB text (the canary case: an enum/plain field\n // mis-inferred as JSON by a downstream scanner, sitting on a real\n // `text` column holding bare values like 'active')\n // Generating an ALTER here is pure churn at best and data-destroying at\n // worst: `status::jsonb` on a column holding 'active' raises\n // \"invalid input syntax for type json\" and aborts the whole atomic\n // migration. Like the uuid/text tolerance, this lives at the equality\n // gate only (not in `normalizeType`) so `isCompatibleTypeUpgrade` still\n // treats JSON and TEXT as distinct buckets for OTHER upgrade paths.\n const isJsonTextEquivalent =\n (normalizedExpected === 'JSON' && normalizedActual === 'TEXT') ||\n (normalizedExpected === 'TEXT' && normalizedActual === 'JSON');\n\n if (\n normalizedExpected !== normalizedActual &&\n !isUuidTextEquivalent &&\n !isJsonTextEquivalent\n ) {\n // Check if this is a safe type upgrade that SMRT can handle\n // Since SMRT owns the data lifecycle, we know the intent from the manifest\n if (this.isCompatibleTypeUpgrade(colDef.type, dbCol.type)) {\n // Generate type upgrade SQL\n const generatedSQL = this.generateTypeUpgradeSQL(\n tableName,\n colName,\n colDef,\n dbCol.type,\n );\n changes.push({\n type: 'type_upgrade',\n table: tableName,\n name: colName,\n column: colDef,\n mismatch: {\n expected: colDef.type,\n actual: dbCol.type,\n },\n sql: generatedSQL.sql,\n ...(generatedSQL.statements\n ? { sqlStatements: generatedSQL.statements }\n : {}),\n });\n } else if (!this.options.ignoreTypeMismatches) {\n changes.push({\n type: 'type_mismatch',\n table: tableName,\n name: colName,\n mismatch: {\n expected: colDef.type,\n actual: dbCol.type,\n },\n });\n }\n }\n }\n }\n\n // Check for dropped columns (if enabled)\n if (this.options.includeDroppedColumns) {\n const manifestColumnNames = new Set(Object.keys(manifest.columns));\n for (const colName of dbColumnNames) {\n if (!manifestColumnNames.has(colName)) {\n changes.push({\n type: 'drop_column',\n table: tableName,\n name: colName,\n sql: this.generateDropColumnSQL(tableName, colName),\n });\n }\n }\n }\n\n return changes;\n }\n\n private isUuidTextEquivalentColumn(\n columnName: string,\n colDef: ColumnDefinition,\n normalizedExpected: string,\n normalizedActual: string,\n ): boolean {\n const expectedUuidActualText =\n normalizedExpected === 'UUID' && normalizedActual === 'TEXT';\n const expectedTextActualUuid =\n normalizedExpected === 'TEXT' && normalizedActual === 'UUID';\n\n if (!expectedUuidActualText && !expectedTextActualUuid) {\n return false;\n }\n\n return this.isStructuralUuidCompatibleColumn(columnName, colDef);\n }\n\n private isStructuralUuidCompatibleColumn(\n columnName: string,\n colDef: ColumnDefinition,\n ): boolean {\n return (\n colDef.primaryKey === true ||\n Boolean(colDef.foreignKey) ||\n colDef.referenceKind === 'id' ||\n colDef.referenceKind === 'foreignKey' ||\n colDef.referenceKind === 'crossPackageRef' ||\n colDef.referenceKind === 'tenantId' ||\n (columnName === 'id' && colDef.type === 'TEXT')\n );\n }\n\n /**\n * Compare indexes between manifest and database\n *\n * Four classes of drift the differ now detects:\n *\n * 1. **Missing index** — manifest has an index neither the DB has by name\n * nor any equivalent-by-signature. Emit `add_index`. (Issue #741: the\n * signature check protects against creating duplicates when STI child\n * classes register indexes with different name prefixes.)\n *\n * 2. **Same-name shape drift** — DB has an index with the manifest's name,\n * but its columns, uniqueness flag, or partial-index `WHERE` predicate\n * differ. This covers the uniqueness flip in issue #1165\n * (`tenants_slug_context_meta_type_idx` materialized non-unique while\n * the manifest declares it unique) and the predicate drift in issue\n * #1692 (a partial index whose `WHERE` clause was added, removed, or\n * altered). Emit `drop_index` + `add_index` so the next migrate cycle\n * recreates it with the correct shape.\n *\n * 3. **Orphan in DB** — DB has an index with no manifest counterpart by\n * name and no signature equivalent. Emit `drop_index` *only* when the\n * caller opts in via `includeDroppedIndexes`, and even then never for\n * PostgreSQL implicit indexes (`*_pkey`, `*_key`) — those are owned by\n * table-level constraints and need a separate `DROP CONSTRAINT` path\n * that the differ does not emit yet.\n *\n * 4. **Partial-index predicate drift / collision** — two indexes on the\n * same column(s) and uniqueness that differ only by their `WHERE`\n * predicate (e.g. distinct STI child partial indexes) are no longer\n * collapsed to one signature, so the signature-equivalence path (b)\n * won't claim one for the other.\n *\n * @param dbIndexPredicates - Normalized `WHERE` predicate per DB index\n * name from {@link getDbIndexPredicates}. `null` means predicate\n * introspection was unavailable for this engine/adapter, in which case\n * the comparison falls back to predicate-unaware signatures (the prior\n * behavior) so existing partial indexes are never flagged as false drift.\n */\n private compareIndexes(\n tableName: string,\n manifest: SchemaDefinition,\n dbSchema: SqlTableSchemaInfo,\n dbIndexPredicates: Map<string, string> | null = null,\n ): SchemaChange[] {\n const changes: SchemaChange[] = [];\n\n // Only fold predicates into signatures when we actually read them back\n // from the live DB. If introspection was unavailable both sides use the\n // empty predicate, which reproduces the prior column+unique-only behavior\n // and cannot manufacture false positives on existing partial indexes.\n const predicateAware = dbIndexPredicates !== null;\n const dbPredicateFor = (name: string): string =>\n predicateAware ? (dbIndexPredicates?.get(name) ?? '') : '';\n const manifestPredicateFor = (idx: IndexDefinition): string =>\n predicateAware ? normalizeIndexPredicate(idx.where) : '';\n\n // Index DB indexes by name and by signature for fast lookup.\n // dbIndexSignatures groups *all* DB index names sharing a signature so\n // duplicates under different names all get claimed by a single matching\n // manifest entry — otherwise the orphan sweep would drop the un-claimed\n // siblings even though they are functionally equivalent to the manifest.\n const dbIndexesByName = new Map<\n string,\n { columns: string[]; unique: boolean }\n >();\n const dbIndexSignatures = new Map<string, Set<string>>();\n for (const idx of dbSchema.indexes) {\n const unique = idx.unique ?? false;\n dbIndexesByName.set(idx.name, { columns: idx.columns, unique });\n const signature = this.getIndexSignature(\n idx.columns,\n unique,\n dbPredicateFor(idx.name),\n );\n let bucket = dbIndexSignatures.get(signature);\n if (!bucket) {\n bucket = new Set();\n dbIndexSignatures.set(signature, bucket);\n }\n bucket.add(idx.name);\n }\n\n // Manifest signatures — used during the orphan sweep to skip DB indexes\n // that match a manifest entry's signature even if no specific manifest\n // entry \"claimed\" them by name.\n const manifestSignatureSet = new Set<string>();\n for (const idx of manifest.indexes) {\n manifestSignatureSet.add(\n this.getIndexSignature(idx, undefined, manifestPredicateFor(idx)),\n );\n }\n\n // Track which DB indexes a manifest entry has claimed, so the orphan\n // pass below doesn't re-flag indexes that match by signature alone.\n const claimedDbIndexes = new Set<string>();\n\n for (const idx of manifest.indexes) {\n const manifestSignature = this.getIndexSignature(\n idx,\n undefined,\n manifestPredicateFor(idx),\n );\n\n // (a) Same name in DB — verify shape matches.\n const dbByName = dbIndexesByName.get(idx.name);\n if (dbByName) {\n claimedDbIndexes.add(idx.name);\n\n // JSON-path indexes (`@meta({ indexed: true })`) cannot be reliably\n // compared by DB introspection — SQLite expression indexes surface\n // as `[null]` columns, so the signature would always mismatch and\n // every diff run would emit drop+recreate. Trust the name match\n // here; if the json path itself changes, the index name changes\n // too (we encode the field name into it), so a name match is a\n // stronger guarantee than the column list for this index family.\n if (isJsonPathIndex(idx)) {\n continue;\n }\n\n const dbSignature = this.getIndexSignature(\n dbByName.columns,\n dbByName.unique,\n dbPredicateFor(idx.name),\n );\n if (dbSignature === manifestSignature) {\n continue; // Same name, same shape — nothing to do.\n }\n\n // Same name, drifted shape. Most often this is a uniqueness flip\n // (issue #1165: 3-column index materialized non-unique). Recreate.\n //\n // Rollback caveat: the auto-generated DOWN script for the\n // `add_index` half drops the (newly correct) index, and the\n // `drop_index` half has no DOWN. Rolling back a recreate leaves\n // the table without the index entirely instead of restoring the\n // wrong-shape original. Capturing the original shape would\n // require richer DB introspection than the differ currently has,\n // so this asymmetry is accepted — the failure mode after an\n // un-rolled-back recreate is \"missing index\" rather than\n // \"permanently broken UPSERT,\" which is recoverable.\n changes.push({\n type: 'drop_index',\n table: tableName,\n name: idx.name,\n sql: this.generateDropIndexSQL(idx.name),\n });\n changes.push({\n type: 'add_index',\n table: tableName,\n name: idx.name,\n index: idx,\n sql: this.generateAddIndexSQL(tableName, idx),\n });\n continue;\n }\n\n // (b) Different name in DB but functionally equivalent — keep as-is.\n // Claim *every* DB name sharing this signature so duplicate-shape\n // indexes (e.g., a stale `<name>_idx` plus the implicit `<name>_key`\n // from the same constraint) all survive the orphan sweep.\n const equivalentIndexNames = dbIndexSignatures.get(manifestSignature);\n if (equivalentIndexNames && equivalentIndexNames.size > 0) {\n for (const name of equivalentIndexNames) {\n claimedDbIndexes.add(name);\n }\n continue;\n }\n\n // (c) Genuinely missing — add it.\n changes.push({\n type: 'add_index',\n table: tableName,\n name: idx.name,\n index: idx,\n sql: this.generateAddIndexSQL(tableName, idx),\n });\n }\n\n // Orphan-index sweep (opt-in via includeDroppedIndexes).\n if (this.options.includeDroppedIndexes) {\n for (const idx of dbSchema.indexes) {\n if (claimedDbIndexes.has(idx.name)) continue;\n if (isProtectedDbIndexName(idx.name)) continue;\n\n // Belt-and-suspenders: even if a DB index wasn't formally claimed\n // by a manifest entry (e.g., shape-drift recreate consumed the\n // claim slot), don't drop it if its signature still matches\n // something the manifest declares. That would contradict the\n // option doc (\"not functionally equivalent to anything in the\n // manifest\") and risk dropping a still-needed index.\n const idxSignature = this.getIndexSignature(\n idx.columns,\n idx.unique ?? false,\n dbPredicateFor(idx.name),\n );\n if (manifestSignatureSet.has(idxSignature)) continue;\n\n changes.push({\n type: 'drop_index',\n table: tableName,\n name: idx.name,\n sql: this.generateDropIndexSQL(idx.name),\n });\n }\n }\n\n return changes;\n }\n\n /**\n * Generate a signature for an index based on its columns, uniqueness, and\n * (normalized) partial-index predicate. Used for functional equivalence\n * checking (Issue #741) and predicate-drift detection (Issue #1692).\n *\n * Note: Column order is preserved because it is semantically significant for\n * composite indexes. An index on (a, b) is NOT equivalent to (b, a) - they\n * have different query performance characteristics.\n *\n * The trailing predicate component distinguishes partial indexes that share\n * columns and uniqueness but differ by their `WHERE` clause (e.g. distinct\n * STI child partial indexes). Callers pass the already-normalized predicate\n * so both the manifest (desired) and introspected (DB) sides compare equal\n * for semantically-identical clauses. An empty string means \"no predicate\"\n * (a non-partial index) and is also used on both sides when predicate\n * introspection is unavailable, preserving the prior behavior.\n *\n * For JSON-path indexes (`@meta({ indexed: true })`) the signature is\n * derived from the JSON path instead of an empty column list, so the\n * differ can distinguish two jsonPath indexes against different paths.\n *\n * @param idxOrColumns - Either an IndexDefinition or a column array (legacy)\n * @param uniqueArg - Unique flag (used when first arg is a column array)\n * @param predicateArg - Normalized partial-index predicate (default '')\n * @returns Signature string\n */\n private getIndexSignature(\n idxOrColumns: IndexDefinition | string[],\n uniqueArg?: boolean,\n predicateArg = '',\n ): string {\n if (Array.isArray(idxOrColumns)) {\n return `${idxOrColumns.join(',')}:${Boolean(uniqueArg)}:${predicateArg}`;\n }\n const idx = idxOrColumns;\n if (isJsonPathIndex(idx) && idx.jsonPath) {\n return `json:${idx.jsonPath.column}.${idx.jsonPath.path}:${Boolean(idx.unique)}:${predicateArg}`;\n }\n return `${(idx.columns ?? []).join(',')}:${Boolean(idx.unique)}:${predicateArg}`;\n }\n\n /**\n * Whether the active engine supports partial indexes (`CREATE INDEX … WHERE`).\n *\n * SQLite and PostgreSQL do. DuckDB rejects them outright, and the JSON\n * adapter is DuckDB-backed, so on those engines a \"partial\" index can only\n * ever exist as a full index. Treating the predicate as significant there\n * would (a) flag existing full indexes as false drift and (b) emit\n * `CREATE INDEX … WHERE` DDL the engine rejects, breaking the migration.\n * Gating on this keeps both the comparison and the generated DDL aligned\n * with what the engine actually accepts (a partial index degrades to a\n * full index), matching the pre-#1692 behavior on those engines.\n */\n private supportsPartialIndexes(): boolean {\n return this.engine === 'sqlite' || this.engine === 'postgres';\n }\n\n /**\n * Introspect partial-index predicates for a table, keyed by index name.\n *\n * `getTableSchema()` (the @happyvertical/sql introspection) returns only\n * name/columns/unique, so the `WHERE` predicate is read directly here:\n *\n * - PostgreSQL: `pg_indexes.indexdef` carries the full CREATE INDEX text.\n * - SQLite: the `sqlite_master.sql` column carries the original CREATE INDEX\n * text.\n *\n * Engines that don't support partial indexes (DuckDB / the DuckDB-backed\n * JSON adapter) short-circuit to `null` so the comparison stays\n * predicate-unaware there — see {@link supportsPartialIndexes}.\n *\n * Non-partial indexes are omitted from the map (callers treat a missing\n * entry as the empty predicate). Returns `null` when the catalog query\n * fails — e.g. an adapter exposing neither catalog — so the index\n * comparison can fall back to predicate-unaware behavior rather than\n * flagging every existing partial index as false drift.\n */\n private async getDbIndexPredicates(\n tableName: string,\n ): Promise<Map<string, string> | null> {\n if (!this.supportsPartialIndexes()) {\n return null;\n }\n const predicates = new Map<string, string>();\n try {\n if (this.engine === 'postgres') {\n const result = await this.db.query(\n `SELECT indexname, indexdef FROM pg_indexes WHERE schemaname = 'public' AND tablename = ${this.quoteLiteral(\n tableName,\n )}`,\n );\n for (const row of result.rows as {\n indexname?: string;\n indexdef?: string;\n }[]) {\n if (!row.indexname || !row.indexdef) continue;\n const predicate = extractIndexPredicate(row.indexdef);\n if (predicate) predicates.set(row.indexname, predicate);\n }\n return predicates;\n }\n\n // SQLite exposes the `sqlite_master` catalog whose `sql` column preserves\n // the original CREATE INDEX text. Implicit indexes carry a NULL `sql` and\n // are skipped. (DuckDB / JSON already short-circuited above.)\n const result = await this.db.query(\n `SELECT name, sql FROM sqlite_master WHERE type = 'index' AND tbl_name = ${this.quoteLiteral(\n tableName,\n )} AND name NOT LIKE 'sqlite_%'`,\n );\n for (const row of result.rows as {\n name?: string;\n sql?: string | null;\n }[]) {\n if (!row.name || !row.sql) continue;\n const predicate = extractIndexPredicate(row.sql);\n if (predicate) predicates.set(row.name, predicate);\n }\n return predicates;\n } catch (err) {\n logger.debug(\n `[SchemaComparer] Partial-index predicate introspection unavailable for ${tableName}; falling back to predicate-unaware index comparison`,\n { error: err instanceof Error ? err.message : String(err) },\n );\n return null;\n }\n }\n\n /**\n * Get list of existing tables from database\n */\n private async getExistingTables(): Promise<Set<string>> {\n let query: string;\n if (this.engine === 'postgres') {\n query = `SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'`;\n } else {\n // SQLite and DuckDB both expose the SQLite-compatible `sqlite_master`\n // catalog — DuckDB ships it as a built-in compatibility view, so a single\n // introspection query covers both engines. Verified against a live DuckDB\n // v1.4.3 (json mode): `SELECT name FROM sqlite_master WHERE type='table'`\n // returns user tables with the expected `name` column (#1579).\n query = `SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'`;\n }\n\n const result = await this.db.query(query);\n const rows = result.rows as { name?: string; table_name?: string }[];\n return new Set(\n rows.map((r) => r.name || r.table_name || '').filter(Boolean),\n );\n }\n\n /**\n * Normalize SQL types for comparison\n */\n private normalizeType(type: string): string {\n const upper = type.toUpperCase().trim();\n\n // Integer types\n if (/^(INTEGER|INT|BIGINT|SMALLINT|TINYINT)$/i.test(upper)) {\n return 'INTEGER';\n }\n\n // Text types\n if (/^(TEXT|CLOB|STRING|VARCHAR|CHAR)/i.test(upper)) {\n return 'TEXT';\n }\n\n // UUID normalizes to its own bucket — deliberately NOT folded into TEXT.\n // The text<->uuid drift tolerance (R11) is applied at the equality gate\n // in `compare()` only, so that `isCompatibleTypeUpgrade` (which also\n // calls normalizeType) still treats `uuid` as distinct from text and\n // won't mis-classify e.g. `uuid`->`timestamp` as a compatible\n // \"TEXT->TIMESTAMP\" upgrade.\n if (/^UUID$/i.test(upper)) {\n return 'UUID';\n }\n\n // Decimal types\n if (/^(REAL|FLOAT|DOUBLE|DECIMAL|NUMERIC|NUMBER)/i.test(upper)) {\n return 'REAL';\n }\n\n // Boolean types\n if (/^(BOOLEAN|BOOL)/i.test(upper)) {\n return 'BOOLEAN';\n }\n\n // Date/time types\n if (/^(DATETIME|TIMESTAMP|DATE|TIME)/i.test(upper)) {\n return 'TIMESTAMP';\n }\n\n // Blob types\n if (/^(BLOB|BINARY|BYTEA)/i.test(upper)) {\n return 'BLOB';\n }\n\n // JSON types\n if (/^(JSON|JSONB)/i.test(upper)) {\n return 'JSON';\n }\n\n return upper;\n }\n\n /**\n * Check if a type change is a safe upgrade that can be auto-migrated.\n *\n * SMRT controls the data lifecycle for these columns, so we know:\n * - TEXT→JSON: The column stores JSON data serialized as text (arrays, objects)\n * - TEXT/JSON→TIMESTAMP: Legacy system columns stored timestamp strings\n * before newer manifests normalized the column type.\n * - INTEGER→REAL: Safe widening of integer to floating point\n * - TEXT/REAL→INTEGER on PostgreSQL: explicit data-checked repairs for\n * legacy integer columns that were previously stored as text/real.\n *\n * @param manifestType - The abstract type from the manifest (e.g., 'JSON')\n * @param dbType - The actual type in the database (e.g., 'TEXT')\n * @returns true if the change from dbType to manifestType is a safe upgrade\n */\n private isCompatibleTypeUpgrade(\n manifestType: string,\n dbType: string,\n ): boolean {\n const manifest = this.normalizeType(manifestType);\n const db = this.normalizeType(dbType);\n\n // TEXT → JSON is safe: SMRT serializes arrays/objects as JSON text\n // When the manifest says JSON, the data is already valid JSON in TEXT column\n if (manifest === 'JSON' && db === 'TEXT') {\n return true;\n }\n\n // JSON → TEXT is also safe (downgrade, but data is preserved as-is)\n if (manifest === 'TEXT' && db === 'JSON') {\n return true;\n }\n\n // UUID → TEXT is safe for plain text/provenance fields that were\n // mistakenly materialized as native uuid: the stored UUID value can be\n // rendered losslessly as text.\n if (manifest === 'TEXT' && db === 'UUID') {\n return true;\n }\n\n // INTEGER → REAL is safe (widening)\n if (manifest === 'REAL' && db === 'INTEGER') {\n return true;\n }\n\n // PostgreSQL can safely repair legacy integer columns when the generated\n // migration validates that every existing value is already an integer.\n if (\n this.engine === 'postgres' &&\n manifest === 'INTEGER' &&\n (db === 'TEXT' || db === 'REAL')\n ) {\n return true;\n }\n\n // TEXT/JSON → TIMESTAMP is a legacy-drift repair. Invalid values fail\n // explicitly during migration rather than being silently coerced.\n if (manifest === 'TIMESTAMP' && (db === 'TEXT' || db === 'JSON')) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Generate SQL for a type upgrade migration.\n *\n * Engine-specific SQL:\n * - SQLite: TEXT and JSON are equivalent, no-op or comment\n * - DuckDB: ALTER COLUMN TYPE (native type conversion)\n * - PostgreSQL: ALTER COLUMN TYPE with USING clause\n */\n private generateTypeUpgradeSQL(\n tableName: string,\n colName: string,\n colDef: ColumnDefinition,\n dbType: string,\n ): GeneratedTypeUpgradeSQL {\n const quotedTable = this.quoteIdentifier(tableName);\n const quotedCol = this.quoteIdentifier(colName);\n const manifestType = colDef.type;\n\n // Validate manifestType before mapping\n const validatedType: SQLDataType = isValidSQLDataType(manifestType)\n ? manifestType\n : 'TEXT';\n const targetType = this.ddlStrategy.mapType(validatedType);\n\n switch (this.engine) {\n case 'sqlite':\n // SQLite has dynamic typing - TEXT and JSON are functionally equivalent\n // For SQLite, we just return a comment since no actual change is needed\n if (\n this.normalizeType(manifestType) === 'JSON' &&\n this.normalizeType(dbType) === 'TEXT'\n ) {\n return {\n sql: `-- SQLite: ${quotedCol} already stores JSON as TEXT (no change needed)`,\n };\n }\n // For other type upgrades, SQLite requires recreating the table\n return {\n sql: `-- SQLite: Type upgrade for ${quotedCol} requires table recreation`,\n };\n\n case 'postgres': {\n // PostgreSQL defaults must be dropped/reset around some type changes\n // so drift repairs can succeed even when an existing default cannot\n // be cast automatically to the target type.\n const manifestNormalized = this.normalizeType(manifestType);\n const dbNormalized = this.normalizeType(dbType);\n const preflightSQL =\n manifestNormalized === 'INTEGER' &&\n (dbNormalized === 'TEXT' || dbNormalized === 'REAL')\n ? this.generatePostgresIntegerPreflightSQL(\n quotedTable,\n quotedCol,\n tableName,\n colName,\n dbNormalized,\n )\n : null;\n const clauses: string[] = [];\n\n if (colDef.defaultValue !== undefined) {\n clauses.push(`ALTER COLUMN ${quotedCol} DROP DEFAULT`);\n }\n\n let typeClause = `ALTER COLUMN ${quotedCol} TYPE ${targetType}`;\n if (manifestNormalized === 'JSON' && dbNormalized === 'TEXT') {\n // #1335: a bare `${col}::jsonb` cast raises \"invalid input syntax for\n // type json\" on any row whose text is not already valid JSON (e.g. a\n // legacy enum column holding 'active'). `to_jsonb(col)` instead wraps\n // ANY text value as a JSON string and never errors, so a genuine\n // TEXT->JSON widening survives non-JSON legacy data. (Note: with the\n // json<->text equality tolerance added in this fix, the normal\n // compare path no longer reaches here; this keeps the SQL safe for\n // callers that construct a type_upgrade directly.)\n typeClause += ` USING to_jsonb(${quotedCol})`;\n } else if (manifestNormalized === 'TEXT' && dbNormalized === 'JSON') {\n // #1335: a native-json column cast back to text is value-preserving\n // (`::text` renders the stored JSON as its text form), so this arm is\n // safe. (Note: like the TEXT->JSON arm above, the json<->text equality\n // tolerance means the normal compare path no longer reaches here; this\n // keeps the SQL safe for callers that construct a type_upgrade\n // directly.)\n typeClause += ` USING ${quotedCol}::text`;\n } else if (manifestNormalized === 'TEXT' && dbNormalized === 'UUID') {\n typeClause += ` USING ${quotedCol}::text`;\n } else if (\n manifestNormalized === 'INTEGER' &&\n dbNormalized === 'TEXT'\n ) {\n typeClause += ` USING trim(${quotedCol}::text)::integer`;\n } else if (\n manifestNormalized === 'INTEGER' &&\n dbNormalized === 'REAL'\n ) {\n typeClause += ` USING ${quotedCol}::integer`;\n } else if (\n manifestNormalized === 'TIMESTAMP' &&\n (dbNormalized === 'TEXT' || dbNormalized === 'JSON')\n ) {\n typeClause += ` USING NULLIF(NULLIF(trim(both '\"' from ${quotedCol}::text), ''), 'null')::timestamp`;\n }\n\n clauses.push(typeClause);\n\n if (colDef.defaultValue !== undefined) {\n const formattedDefault = this.ddlStrategy.formatDefaultValue(\n colDef.defaultValue,\n validatedType,\n );\n const defaultSql =\n manifestNormalized === 'JSON'\n ? `${formattedDefault}::${targetType.toLowerCase()}`\n : formattedDefault;\n clauses.push(`ALTER COLUMN ${quotedCol} SET DEFAULT ${defaultSql}`);\n }\n\n const alterSql = `ALTER TABLE ${quotedTable} ${clauses.join(', ')}`;\n\n return preflightSQL\n ? { sql: alterSql, statements: [preflightSQL, alterSql] }\n : { sql: alterSql };\n }\n\n case 'duckdb':\n // DuckDB supports ALTER COLUMN TYPE for type conversions\n return {\n sql: `ALTER TABLE ${quotedTable} ALTER COLUMN ${quotedCol} TYPE ${targetType}`,\n };\n\n default: {\n // Escape special characters in type names for safe comment generation\n const safeDbType = dbType.replace(/[^\\w]/g, '_');\n const safeManifestType = manifestType.replace(/[^\\w]/g, '_');\n return {\n sql: `-- Type upgrade for ${quotedCol}: ${safeDbType} → ${safeManifestType}`,\n };\n }\n }\n }\n\n /**\n * Quote a SQL identifier\n */\n private quoteIdentifier(name: string): string {\n return `\"${name.replace(/\"/g, '\"\"')}\"`;\n }\n\n /**\n * Generate a PostgreSQL preflight guard for narrowing legacy columns to\n * INTEGER. PostgreSQL's REAL→INTEGER cast rounds fractional values, so the\n * generated migration must fail before the ALTER can silently change data.\n */\n private generatePostgresIntegerPreflightSQL(\n quotedTable: string,\n quotedCol: string,\n tableName: string,\n colName: string,\n dbNormalized: string,\n ): string {\n const invalidCondition =\n dbNormalized === 'REAL'\n ? `${quotedCol} IS NOT NULL AND ${quotedCol} <> trunc(${quotedCol})`\n : `${quotedCol} IS NOT NULL AND trim(${quotedCol}::text) !~ '^[+-]?[0-9]+$'`;\n const message = `Cannot convert ${tableName}.${colName} to INTEGER: found non-integer values`;\n\n return `DO $$ BEGIN IF EXISTS (SELECT 1 FROM ${quotedTable} WHERE ${invalidCondition}) THEN RAISE EXCEPTION ${this.quoteLiteral(message)}; END IF; END $$`;\n }\n\n private quoteLiteral(value: string): string {\n return `'${value.replace(/'/g, \"''\")}'`;\n }\n\n /**\n * Generate SQL for adding a column\n */\n private generateAddColumnSQL(\n tableName: string,\n colName: string,\n colDef: ColumnDefinition,\n ): string {\n // Build the ADD COLUMN definition inline (main) rather than delegating to\n // the DDL strategy's generateColumnDefinition: that builder is for CREATE\n // TABLE and would emit `PRIMARY KEY` (invalid in ALTER ... ADD COLUMN) and\n // suppress single-column UNIQUE on engines that require inline unique at\n // table-create time (DuckDB) — but an ADD COLUMN has no inline-constraint\n // pass, so the UNIQUE must be emitted here. mapType still maps abstract\n // types per dialect (UUID→native uuid / TEXT — R11); invalid types fall\n // back to TEXT, matching the compareColumns guard.\n const validatedType: SQLDataType = isValidSQLDataType(colDef.type)\n ? colDef.type\n : 'TEXT';\n if (!isValidSQLDataType(colDef.type)) {\n logger.warn(\n `[SchemaComparer] Invalid manifest type \"${colDef.type}\" for ${tableName}.${colName}, treating as TEXT`,\n );\n }\n\n const parts: string[] = [\n this.quoteIdentifier(colName),\n this.ddlStrategy.mapType(validatedType),\n ];\n\n if (colDef.notNull) {\n parts.push('NOT NULL');\n }\n if (colDef.unique) {\n parts.push('UNIQUE');\n }\n if (colDef.defaultValue !== undefined) {\n const defaultVal = this.ddlStrategy.formatDefaultValue(\n colDef.defaultValue,\n validatedType,\n );\n parts.push(`DEFAULT ${defaultVal}`);\n }\n if (colDef.check) {\n parts.push(`CHECK (${colDef.check})`);\n }\n\n const columnDefinition = parts.join(' ');\n\n return `ALTER TABLE ${this.quoteIdentifier(tableName)} ADD COLUMN ${columnDefinition}`;\n }\n\n /**\n * Generate SQL for dropping a column\n */\n private generateDropColumnSQL(tableName: string, colName: string): string {\n return `ALTER TABLE ${this.quoteIdentifier(tableName)} DROP COLUMN ${this.quoteIdentifier(colName)}`;\n }\n\n /**\n * Generate SQL for adding an index.\n *\n * On engines that support partial indexes (SQLite/PostgreSQL) this mirrors\n * the canonical CREATE INDEX path in the DDL strategies: a partial index\n * appends its `WHERE` predicate so a detected predicate add/alter (issue\n * #1692) recreates the index with the correct partial condition rather than\n * silently widening it to a full index. On DuckDB / the JSON adapter — which\n * reject partial indexes — the predicate is dropped so the emitted DDL stays\n * executable (a partial index degrades to a full index there). The predicate\n * is trimmed and a redundant leading `WHERE` stripped for robustness.\n */\n private generateAddIndexSQL(tableName: string, idx: IndexDefinition): string {\n const uniqueStr = idx.unique ? 'UNIQUE ' : '';\n const target = renderIndexTarget(idx, this.engine);\n let sql = `CREATE ${uniqueStr}INDEX ${this.quoteIdentifier(idx.name)} ON ${this.quoteIdentifier(tableName)} (${target})`;\n const where = idx.where?.trim().replace(/^WHERE\\s+/i, '');\n if (this.supportsPartialIndexes() && where) {\n sql += ` WHERE ${where}`;\n }\n return sql;\n }\n\n /**\n * Generate SQL for dropping an index.\n *\n * This SQL is consumed by the manifest-driven execution path:\n *\n * - `db:migrate` runs the SQL we put in `change.sql` directly, with the\n * tracker's `executePostgresStatements` adding CONCURRENTLY when\n * `--postgres-safe` is on.\n *\n * PostgreSQL ends up with `CONCURRENTLY` when it should.\n * Keeping this method engine-agnostic also means the diff preview text\n * stays readable (no engine-specific noise) for engines like SQLite\n * where CONCURRENTLY isn't a thing.\n */\n private generateDropIndexSQL(indexName: string): string {\n return `DROP INDEX IF EXISTS ${this.quoteIdentifier(indexName)}`;\n }\n}\n\n/**\n * Generate a SchemaDiff from manifest and database\n */\nexport async function generateSchemaDiff(\n db: DatabaseInterface,\n manifestSchemas: Record<string, SchemaDefinition>,\n options: DiffOptions = {},\n): Promise<SchemaDiff> {\n const comparer = new SchemaComparer(db, options);\n return comparer.compare(manifestSchemas);\n}\n\n/**\n * Check if a diff has any actionable changes (excluding type mismatches)\n */\nexport function hasActionableChanges(diff: SchemaDiff): boolean {\n if (diff.added_tables.length > 0) return true;\n if (diff.dropped_tables.length > 0) return true;\n return diff.changes.some((c) => c.type !== 'type_mismatch');\n}\n\n/**\n * Get SQL statements from a diff for execution\n */\nexport function getSQLFromDiff(diff: SchemaDiff): string[] {\n const statements: string[] = [];\n\n // Add table creation (requires full DDL generation - not included here)\n // This is typically handled by ensureSchema()\n\n // Add column and index changes\n for (const change of diff.changes) {\n if (change.type !== 'type_mismatch') {\n statements.push(\n ...(change.sqlStatements ?? (change.sql ? [change.sql] : [])),\n );\n }\n }\n\n return statements;\n}\n"],"names":["result"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assert-valid-pattern.js","sources":["../../../../../../../../../../node_modules/.pnpm/minimatch@10.2.
|
|
1
|
+
{"version":3,"file":"assert-valid-pattern.js","sources":["../../../../../../../../../../node_modules/.pnpm/minimatch@10.2.5/node_modules/minimatch/dist/esm/assert-valid-pattern.js"],"sourcesContent":["const MAX_PATTERN_LENGTH = 1024 * 64;\nexport const assertValidPattern = (pattern) => {\n if (typeof pattern !== 'string') {\n throw new TypeError('invalid pattern');\n }\n if (pattern.length > MAX_PATTERN_LENGTH) {\n throw new TypeError('pattern is too long');\n }\n};\n//# sourceMappingURL=assert-valid-pattern.js.map"],"names":[],"mappings":"AAAA,MAAM,qBAAqB,OAAO;AACtB,MAAC,qBAAqB,CAAC,YAAY;AAC3C,MAAI,OAAO,YAAY,UAAU;AAC7B,UAAM,IAAI,UAAU,iBAAiB;AAAA,EACzC;AACA,MAAI,QAAQ,SAAS,oBAAoB;AACrC,UAAM,IAAI,UAAU,qBAAqB;AAAA,EAC7C;AACJ;","x_google_ignoreList":[0]}
|
|
@@ -116,13 +116,7 @@ class AST {
|
|
|
116
116
|
}
|
|
117
117
|
// reconstructs the pattern
|
|
118
118
|
toString() {
|
|
119
|
-
|
|
120
|
-
return this.#toString;
|
|
121
|
-
if (!this.type) {
|
|
122
|
-
return this.#toString = this.#parts.map((p) => String(p)).join("");
|
|
123
|
-
} else {
|
|
124
|
-
return this.#toString = this.type + "(" + this.#parts.map((p) => String(p)).join("|") + ")";
|
|
125
|
-
}
|
|
119
|
+
return this.#toString !== void 0 ? this.#toString : !this.type ? this.#toString = this.#parts.map((p) => String(p)).join("") : this.#toString = this.type + "(" + this.#parts.map((p) => String(p)).join("|") + ")";
|
|
126
120
|
}
|
|
127
121
|
#fillNegs() {
|
|
128
122
|
if (this !== this.#root)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ast.js","sources":["../../../../../../../../../../node_modules/.pnpm/minimatch@10.2.5/node_modules/minimatch/dist/esm/ast.js"],"sourcesContent":["// parse a single path portion\nvar _a;\nimport { parseClass } from './brace-expressions.js';\nimport { unescape } from './unescape.js';\nconst types = new Set(['!', '?', '+', '*', '@']);\nconst isExtglobType = (c) => types.has(c);\nconst isExtglobAST = (c) => isExtglobType(c.type);\n// Map of which extglob types can adopt the children of a nested extglob\n//\n// anything but ! can adopt a matching type:\n// +(a|+(b|c)|d) => +(a|b|c|d)\n// *(a|*(b|c)|d) => *(a|b|c|d)\n// @(a|@(b|c)|d) => @(a|b|c|d)\n// ?(a|?(b|c)|d) => ?(a|b|c|d)\n//\n// * can adopt anything, because 0 or repetition is allowed\n// *(a|?(b|c)|d) => *(a|b|c|d)\n// *(a|+(b|c)|d) => *(a|b|c|d)\n// *(a|@(b|c)|d) => *(a|b|c|d)\n//\n// + can adopt @, because 1 or repetition is allowed\n// +(a|@(b|c)|d) => +(a|b|c|d)\n//\n// + and @ CANNOT adopt *, because 0 would be allowed\n// +(a|*(b|c)|d) => would match \"\", on *(b|c)\n// @(a|*(b|c)|d) => would match \"\", on *(b|c)\n//\n// + and @ CANNOT adopt ?, because 0 would be allowed\n// +(a|?(b|c)|d) => would match \"\", on ?(b|c)\n// @(a|?(b|c)|d) => would match \"\", on ?(b|c)\n//\n// ? can adopt @, because 0 or 1 is allowed\n// ?(a|@(b|c)|d) => ?(a|b|c|d)\n//\n// ? and @ CANNOT adopt * or +, because >1 would be allowed\n// ?(a|*(b|c)|d) => would match bbb on *(b|c)\n// @(a|*(b|c)|d) => would match bbb on *(b|c)\n// ?(a|+(b|c)|d) => would match bbb on +(b|c)\n// @(a|+(b|c)|d) => would match bbb on +(b|c)\n//\n// ! CANNOT adopt ! (nothing else can either)\n// !(a|!(b|c)|d) => !(a|b|c|d) would fail to match on b (not not b|c)\n//\n// ! can adopt @\n// !(a|@(b|c)|d) => !(a|b|c|d)\n//\n// ! CANNOT adopt *\n// !(a|*(b|c)|d) => !(a|b|c|d) would match on bbb, not allowed\n//\n// ! CANNOT adopt +\n// !(a|+(b|c)|d) => !(a|b|c|d) would match on bbb, not allowed\n//\n// ! CANNOT adopt ?\n// x!(a|?(b|c)|d) => x!(a|b|c|d) would fail to match \"x\"\nconst adoptionMap = new Map([\n ['!', ['@']],\n ['?', ['?', '@']],\n ['@', ['@']],\n ['*', ['*', '+', '?', '@']],\n ['+', ['+', '@']],\n]);\n// nested extglobs that can be adopted in, but with the addition of\n// a blank '' element.\nconst adoptionWithSpaceMap = new Map([\n ['!', ['?']],\n ['@', ['?']],\n ['+', ['?', '*']],\n]);\n// union of the previous two maps\nconst adoptionAnyMap = new Map([\n ['!', ['?', '@']],\n ['?', ['?', '@']],\n ['@', ['?', '@']],\n ['*', ['*', '+', '?', '@']],\n ['+', ['+', '@', '?', '*']],\n]);\n// Extglobs that can take over their parent if they are the only child\n// the key is parent, value maps child to resulting extglob parent type\n// '@' is omitted because it's a special case. An `@` extglob with a single\n// member can always be usurped by that subpattern.\nconst usurpMap = new Map([\n ['!', new Map([['!', '@']])],\n [\n '?',\n new Map([\n ['*', '*'],\n ['+', '*'],\n ]),\n ],\n [\n '@',\n new Map([\n ['!', '!'],\n ['?', '?'],\n ['@', '@'],\n ['*', '*'],\n ['+', '+'],\n ]),\n ],\n [\n '+',\n new Map([\n ['?', '*'],\n ['*', '*'],\n ]),\n ],\n]);\n// Patterns that get prepended to bind to the start of either the\n// entire string, or just a single path portion, to prevent dots\n// and/or traversal patterns, when needed.\n// Exts don't need the ^ or / bit, because the root binds that already.\nconst startNoTraversal = '(?!(?:^|/)\\\\.\\\\.?(?:$|/))';\nconst startNoDot = '(?!\\\\.)';\n// characters that indicate a start of pattern needs the \"no dots\" bit,\n// because a dot *might* be matched. ( is not in the list, because in\n// the case of a child extglob, it will handle the prevention itself.\nconst addPatternStart = new Set(['[', '.']);\n// cases where traversal is A-OK, no dot prevention needed\nconst justDots = new Set(['..', '.']);\nconst reSpecials = new Set('().*{}+?[]^$\\\\!');\nconst regExpEscape = (s) => s.replace(/[-[\\]{}()*+?.,\\\\^$|#\\s]/g, '\\\\$&');\n// any single thing other than /\nconst qmark = '[^/]';\n// * => any number of characters\nconst star = qmark + '*?';\n// use + when we need to ensure that *something* matches, because the * is\n// the only thing in the path portion.\nconst starNoEmpty = qmark + '+?';\n// remove the \\ chars that we added if we end up doing a nonmagic compare\n// const deslash = (s: string) => s.replace(/\\\\(.)/g, '$1')\nlet ID = 0;\nexport class AST {\n type;\n #root;\n #hasMagic;\n #uflag = false;\n #parts = [];\n #parent;\n #parentIndex;\n #negs;\n #filledNegs = false;\n #options;\n #toString;\n // set to true if it's an extglob with no children\n // (which really means one child of '')\n #emptyExt = false;\n id = ++ID;\n get depth() {\n return (this.#parent?.depth ?? -1) + 1;\n }\n [Symbol.for('nodejs.util.inspect.custom')]() {\n return {\n '@@type': 'AST',\n id: this.id,\n type: this.type,\n root: this.#root.id,\n parent: this.#parent?.id,\n depth: this.depth,\n partsLength: this.#parts.length,\n parts: this.#parts,\n };\n }\n constructor(type, parent, options = {}) {\n this.type = type;\n // extglobs are inherently magical\n if (type)\n this.#hasMagic = true;\n this.#parent = parent;\n this.#root = this.#parent ? this.#parent.#root : this;\n this.#options = this.#root === this ? options : this.#root.#options;\n this.#negs = this.#root === this ? [] : this.#root.#negs;\n if (type === '!' && !this.#root.#filledNegs)\n this.#negs.push(this);\n this.#parentIndex = this.#parent ? this.#parent.#parts.length : 0;\n }\n get hasMagic() {\n /* c8 ignore start */\n if (this.#hasMagic !== undefined)\n return this.#hasMagic;\n /* c8 ignore stop */\n for (const p of this.#parts) {\n if (typeof p === 'string')\n continue;\n if (p.type || p.hasMagic)\n return (this.#hasMagic = true);\n }\n // note: will be undefined until we generate the regexp src and find out\n return this.#hasMagic;\n }\n // reconstructs the pattern\n toString() {\n return (this.#toString !== undefined ? this.#toString\n : !this.type ?\n (this.#toString = this.#parts.map(p => String(p)).join(''))\n : (this.#toString =\n this.type +\n '(' +\n this.#parts.map(p => String(p)).join('|') +\n ')'));\n }\n #fillNegs() {\n /* c8 ignore start */\n if (this !== this.#root)\n throw new Error('should only call on root');\n if (this.#filledNegs)\n return this;\n /* c8 ignore stop */\n // call toString() once to fill this out\n this.toString();\n this.#filledNegs = true;\n let n;\n while ((n = this.#negs.pop())) {\n if (n.type !== '!')\n continue;\n // walk up the tree, appending everthing that comes AFTER parentIndex\n let p = n;\n let pp = p.#parent;\n while (pp) {\n for (let i = p.#parentIndex + 1; !pp.type && i < pp.#parts.length; i++) {\n for (const part of n.#parts) {\n /* c8 ignore start */\n if (typeof part === 'string') {\n throw new Error('string part in extglob AST??');\n }\n /* c8 ignore stop */\n part.copyIn(pp.#parts[i]);\n }\n }\n p = pp;\n pp = p.#parent;\n }\n }\n return this;\n }\n push(...parts) {\n for (const p of parts) {\n if (p === '')\n continue;\n /* c8 ignore start */\n if (typeof p !== 'string' &&\n !(p instanceof _a && p.#parent === this)) {\n throw new Error('invalid part: ' + p);\n }\n /* c8 ignore stop */\n this.#parts.push(p);\n }\n }\n toJSON() {\n const ret = this.type === null ?\n this.#parts\n .slice()\n .map(p => (typeof p === 'string' ? p : p.toJSON()))\n : [this.type, ...this.#parts.map(p => p.toJSON())];\n if (this.isStart() && !this.type)\n ret.unshift([]);\n if (this.isEnd() &&\n (this === this.#root ||\n (this.#root.#filledNegs && this.#parent?.type === '!'))) {\n ret.push({});\n }\n return ret;\n }\n isStart() {\n if (this.#root === this)\n return true;\n // if (this.type) return !!this.#parent?.isStart()\n if (!this.#parent?.isStart())\n return false;\n if (this.#parentIndex === 0)\n return true;\n // if everything AHEAD of this is a negation, then it's still the \"start\"\n const p = this.#parent;\n for (let i = 0; i < this.#parentIndex; i++) {\n const pp = p.#parts[i];\n if (!(pp instanceof _a && pp.type === '!')) {\n return false;\n }\n }\n return true;\n }\n isEnd() {\n if (this.#root === this)\n return true;\n if (this.#parent?.type === '!')\n return true;\n if (!this.#parent?.isEnd())\n return false;\n if (!this.type)\n return this.#parent?.isEnd();\n // if not root, it'll always have a parent\n /* c8 ignore start */\n const pl = this.#parent ? this.#parent.#parts.length : 0;\n /* c8 ignore stop */\n return this.#parentIndex === pl - 1;\n }\n copyIn(part) {\n if (typeof part === 'string')\n this.push(part);\n else\n this.push(part.clone(this));\n }\n clone(parent) {\n const c = new _a(this.type, parent);\n for (const p of this.#parts) {\n c.copyIn(p);\n }\n return c;\n }\n static #parseAST(str, ast, pos, opt, extDepth) {\n const maxDepth = opt.maxExtglobRecursion ?? 2;\n let escaping = false;\n let inBrace = false;\n let braceStart = -1;\n let braceNeg = false;\n if (ast.type === null) {\n // outside of a extglob, append until we find a start\n let i = pos;\n let acc = '';\n while (i < str.length) {\n const c = str.charAt(i++);\n // still accumulate escapes at this point, but we do ignore\n // starts that are escaped\n if (escaping || c === '\\\\') {\n escaping = !escaping;\n acc += c;\n continue;\n }\n if (inBrace) {\n if (i === braceStart + 1) {\n if (c === '^' || c === '!') {\n braceNeg = true;\n }\n }\n else if (c === ']' && !(i === braceStart + 2 && braceNeg)) {\n inBrace = false;\n }\n acc += c;\n continue;\n }\n else if (c === '[') {\n inBrace = true;\n braceStart = i;\n braceNeg = false;\n acc += c;\n continue;\n }\n // we don't have to check for adoption here, because that's\n // done at the other recursion point.\n const doRecurse = !opt.noext &&\n isExtglobType(c) &&\n str.charAt(i) === '(' &&\n extDepth <= maxDepth;\n if (doRecurse) {\n ast.push(acc);\n acc = '';\n const ext = new _a(c, ast);\n i = _a.#parseAST(str, ext, i, opt, extDepth + 1);\n ast.push(ext);\n continue;\n }\n acc += c;\n }\n ast.push(acc);\n return i;\n }\n // some kind of extglob, pos is at the (\n // find the next | or )\n let i = pos + 1;\n let part = new _a(null, ast);\n const parts = [];\n let acc = '';\n while (i < str.length) {\n const c = str.charAt(i++);\n // still accumulate escapes at this point, but we do ignore\n // starts that are escaped\n if (escaping || c === '\\\\') {\n escaping = !escaping;\n acc += c;\n continue;\n }\n if (inBrace) {\n if (i === braceStart + 1) {\n if (c === '^' || c === '!') {\n braceNeg = true;\n }\n }\n else if (c === ']' && !(i === braceStart + 2 && braceNeg)) {\n inBrace = false;\n }\n acc += c;\n continue;\n }\n else if (c === '[') {\n inBrace = true;\n braceStart = i;\n braceNeg = false;\n acc += c;\n continue;\n }\n const doRecurse = !opt.noext &&\n isExtglobType(c) &&\n str.charAt(i) === '(' &&\n /* c8 ignore start - the maxDepth is sufficient here */\n (extDepth <= maxDepth || (ast && ast.#canAdoptType(c)));\n /* c8 ignore stop */\n if (doRecurse) {\n const depthAdd = ast && ast.#canAdoptType(c) ? 0 : 1;\n part.push(acc);\n acc = '';\n const ext = new _a(c, part);\n part.push(ext);\n i = _a.#parseAST(str, ext, i, opt, extDepth + depthAdd);\n continue;\n }\n if (c === '|') {\n part.push(acc);\n acc = '';\n parts.push(part);\n part = new _a(null, ast);\n continue;\n }\n if (c === ')') {\n if (acc === '' && ast.#parts.length === 0) {\n ast.#emptyExt = true;\n }\n part.push(acc);\n acc = '';\n ast.push(...parts, part);\n return i;\n }\n acc += c;\n }\n // unfinished extglob\n // if we got here, it was a malformed extglob! not an extglob, but\n // maybe something else in there.\n ast.type = null;\n ast.#hasMagic = undefined;\n ast.#parts = [str.substring(pos - 1)];\n return i;\n }\n #canAdoptWithSpace(child) {\n return this.#canAdopt(child, adoptionWithSpaceMap);\n }\n #canAdopt(child, map = adoptionMap) {\n if (!child ||\n typeof child !== 'object' ||\n child.type !== null ||\n child.#parts.length !== 1 ||\n this.type === null) {\n return false;\n }\n const gc = child.#parts[0];\n if (!gc || typeof gc !== 'object' || gc.type === null) {\n return false;\n }\n return this.#canAdoptType(gc.type, map);\n }\n #canAdoptType(c, map = adoptionAnyMap) {\n return !!map.get(this.type)?.includes(c);\n }\n #adoptWithSpace(child, index) {\n const gc = child.#parts[0];\n const blank = new _a(null, gc, this.options);\n blank.#parts.push('');\n gc.push(blank);\n this.#adopt(child, index);\n }\n #adopt(child, index) {\n const gc = child.#parts[0];\n this.#parts.splice(index, 1, ...gc.#parts);\n for (const p of gc.#parts) {\n if (typeof p === 'object')\n p.#parent = this;\n }\n this.#toString = undefined;\n }\n #canUsurpType(c) {\n const m = usurpMap.get(this.type);\n return !!m?.has(c);\n }\n #canUsurp(child) {\n if (!child ||\n typeof child !== 'object' ||\n child.type !== null ||\n child.#parts.length !== 1 ||\n this.type === null ||\n this.#parts.length !== 1) {\n return false;\n }\n const gc = child.#parts[0];\n if (!gc || typeof gc !== 'object' || gc.type === null) {\n return false;\n }\n return this.#canUsurpType(gc.type);\n }\n #usurp(child) {\n const m = usurpMap.get(this.type);\n const gc = child.#parts[0];\n const nt = m?.get(gc.type);\n /* c8 ignore start - impossible */\n if (!nt)\n return false;\n /* c8 ignore stop */\n this.#parts = gc.#parts;\n for (const p of this.#parts) {\n if (typeof p === 'object') {\n p.#parent = this;\n }\n }\n this.type = nt;\n this.#toString = undefined;\n this.#emptyExt = false;\n }\n static fromGlob(pattern, options = {}) {\n const ast = new _a(null, undefined, options);\n _a.#parseAST(pattern, ast, 0, options, 0);\n return ast;\n }\n // returns the regular expression if there's magic, or the unescaped\n // string if not.\n toMMPattern() {\n // should only be called on root\n /* c8 ignore start */\n if (this !== this.#root)\n return this.#root.toMMPattern();\n /* c8 ignore stop */\n const glob = this.toString();\n const [re, body, hasMagic, uflag] = this.toRegExpSource();\n // if we're in nocase mode, and not nocaseMagicOnly, then we do\n // still need a regular expression if we have to case-insensitively\n // match capital/lowercase characters.\n const anyMagic = hasMagic ||\n this.#hasMagic ||\n (this.#options.nocase &&\n !this.#options.nocaseMagicOnly &&\n glob.toUpperCase() !== glob.toLowerCase());\n if (!anyMagic) {\n return body;\n }\n const flags = (this.#options.nocase ? 'i' : '') + (uflag ? 'u' : '');\n return Object.assign(new RegExp(`^${re}$`, flags), {\n _src: re,\n _glob: glob,\n });\n }\n get options() {\n return this.#options;\n }\n // returns the string match, the regexp source, whether there's magic\n // in the regexp (so a regular expression is required) and whether or\n // not the uflag is needed for the regular expression (for posix classes)\n // TODO: instead of injecting the start/end at this point, just return\n // the BODY of the regexp, along with the start/end portions suitable\n // for binding the start/end in either a joined full-path makeRe context\n // (where we bind to (^|/), or a standalone matchPart context (where\n // we bind to ^, and not /). Otherwise slashes get duped!\n //\n // In part-matching mode, the start is:\n // - if not isStart: nothing\n // - if traversal possible, but not allowed: ^(?!\\.\\.?$)\n // - if dots allowed or not possible: ^\n // - if dots possible and not allowed: ^(?!\\.)\n // end is:\n // - if not isEnd(): nothing\n // - else: $\n //\n // In full-path matching mode, we put the slash at the START of the\n // pattern, so start is:\n // - if first pattern: same as part-matching mode\n // - if not isStart(): nothing\n // - if traversal possible, but not allowed: /(?!\\.\\.?(?:$|/))\n // - if dots allowed or not possible: /\n // - if dots possible and not allowed: /(?!\\.)\n // end is:\n // - if last pattern, same as part-matching mode\n // - else nothing\n //\n // Always put the (?:$|/) on negated tails, though, because that has to be\n // there to bind the end of the negated pattern portion, and it's easier to\n // just stick it in now rather than try to inject it later in the middle of\n // the pattern.\n //\n // We can just always return the same end, and leave it up to the caller\n // to know whether it's going to be used joined or in parts.\n // And, if the start is adjusted slightly, can do the same there:\n // - if not isStart: nothing\n // - if traversal possible, but not allowed: (?:/|^)(?!\\.\\.?$)\n // - if dots allowed or not possible: (?:/|^)\n // - if dots possible and not allowed: (?:/|^)(?!\\.)\n //\n // But it's better to have a simpler binding without a conditional, for\n // performance, so probably better to return both start options.\n //\n // Then the caller just ignores the end if it's not the first pattern,\n // and the start always gets applied.\n //\n // But that's always going to be $ if it's the ending pattern, or nothing,\n // so the caller can just attach $ at the end of the pattern when building.\n //\n // So the todo is:\n // - better detect what kind of start is needed\n // - return both flavors of starting pattern\n // - attach $ at the end of the pattern when creating the actual RegExp\n //\n // Ah, but wait, no, that all only applies to the root when the first pattern\n // is not an extglob. If the first pattern IS an extglob, then we need all\n // that dot prevention biz to live in the extglob portions, because eg\n // +(*|.x*) can match .xy but not .yx.\n //\n // So, return the two flavors if it's #root and the first child is not an\n // AST, otherwise leave it to the child AST to handle it, and there,\n // use the (?:^|/) style of start binding.\n //\n // Even simplified further:\n // - Since the start for a join is eg /(?!\\.) and the start for a part\n // is ^(?!\\.), we can just prepend (?!\\.) to the pattern (either root\n // or start or whatever) and prepend ^ or / at the Regexp construction.\n toRegExpSource(allowDot) {\n const dot = allowDot ?? !!this.#options.dot;\n if (this.#root === this) {\n this.#flatten();\n this.#fillNegs();\n }\n if (!isExtglobAST(this)) {\n const noEmpty = this.isStart() &&\n this.isEnd() &&\n !this.#parts.some(s => typeof s !== 'string');\n const src = this.#parts\n .map(p => {\n const [re, _, hasMagic, uflag] = typeof p === 'string' ?\n _a.#parseGlob(p, this.#hasMagic, noEmpty)\n : p.toRegExpSource(allowDot);\n this.#hasMagic = this.#hasMagic || hasMagic;\n this.#uflag = this.#uflag || uflag;\n return re;\n })\n .join('');\n let start = '';\n if (this.isStart()) {\n if (typeof this.#parts[0] === 'string') {\n // this is the string that will match the start of the pattern,\n // so we need to protect against dots and such.\n // '.' and '..' cannot match unless the pattern is that exactly,\n // even if it starts with . or dot:true is set.\n const dotTravAllowed = this.#parts.length === 1 && justDots.has(this.#parts[0]);\n if (!dotTravAllowed) {\n const aps = addPatternStart;\n // check if we have a possibility of matching . or ..,\n // and prevent that.\n const needNoTrav = \n // dots are allowed, and the pattern starts with [ or .\n (dot && aps.has(src.charAt(0))) ||\n // the pattern starts with \\., and then [ or .\n (src.startsWith('\\\\.') && aps.has(src.charAt(2))) ||\n // the pattern starts with \\.\\., and then [ or .\n (src.startsWith('\\\\.\\\\.') && aps.has(src.charAt(4)));\n // no need to prevent dots if it can't match a dot, or if a\n // sub-pattern will be preventing it anyway.\n const needNoDot = !dot && !allowDot && aps.has(src.charAt(0));\n start =\n needNoTrav ? startNoTraversal\n : needNoDot ? startNoDot\n : '';\n }\n }\n }\n // append the \"end of path portion\" pattern to negation tails\n let end = '';\n if (this.isEnd() &&\n this.#root.#filledNegs &&\n this.#parent?.type === '!') {\n end = '(?:$|\\\\/)';\n }\n const final = start + src + end;\n return [\n final,\n unescape(src),\n (this.#hasMagic = !!this.#hasMagic),\n this.#uflag,\n ];\n }\n // We need to calculate the body *twice* if it's a repeat pattern\n // at the start, once in nodot mode, then again in dot mode, so a\n // pattern like *(?) can match 'x.y'\n const repeated = this.type === '*' || this.type === '+';\n // some kind of extglob\n const start = this.type === '!' ? '(?:(?!(?:' : '(?:';\n let body = this.#partsToRegExp(dot);\n if (this.isStart() && this.isEnd() && !body && this.type !== '!') {\n // invalid extglob, has to at least be *something* present, if it's\n // the entire path portion.\n const s = this.toString();\n const me = this;\n me.#parts = [s];\n me.type = null;\n me.#hasMagic = undefined;\n return [s, unescape(this.toString()), false, false];\n }\n let bodyDotAllowed = !repeated || allowDot || dot || !startNoDot ?\n ''\n : this.#partsToRegExp(true);\n if (bodyDotAllowed === body) {\n bodyDotAllowed = '';\n }\n if (bodyDotAllowed) {\n body = `(?:${body})(?:${bodyDotAllowed})*?`;\n }\n // an empty !() is exactly equivalent to a starNoEmpty\n let final = '';\n if (this.type === '!' && this.#emptyExt) {\n final = (this.isStart() && !dot ? startNoDot : '') + starNoEmpty;\n }\n else {\n const close = this.type === '!' ?\n // !() must match something,but !(x) can match ''\n '))' +\n (this.isStart() && !dot && !allowDot ? startNoDot : '') +\n star +\n ')'\n : this.type === '@' ? ')'\n : this.type === '?' ? ')?'\n : this.type === '+' && bodyDotAllowed ? ')'\n : this.type === '*' && bodyDotAllowed ? `)?`\n : `)${this.type}`;\n final = start + body + close;\n }\n return [\n final,\n unescape(body),\n (this.#hasMagic = !!this.#hasMagic),\n this.#uflag,\n ];\n }\n #flatten() {\n if (!isExtglobAST(this)) {\n for (const p of this.#parts) {\n if (typeof p === 'object') {\n p.#flatten();\n }\n }\n }\n else {\n // do up to 10 passes to flatten as much as possible\n let iterations = 0;\n let done = false;\n do {\n done = true;\n for (let i = 0; i < this.#parts.length; i++) {\n const c = this.#parts[i];\n if (typeof c === 'object') {\n c.#flatten();\n if (this.#canAdopt(c)) {\n done = false;\n this.#adopt(c, i);\n }\n else if (this.#canAdoptWithSpace(c)) {\n done = false;\n this.#adoptWithSpace(c, i);\n }\n else if (this.#canUsurp(c)) {\n done = false;\n this.#usurp(c);\n }\n }\n }\n } while (!done && ++iterations < 10);\n }\n this.#toString = undefined;\n }\n #partsToRegExp(dot) {\n return this.#parts\n .map(p => {\n // extglob ASTs should only contain parent ASTs\n /* c8 ignore start */\n if (typeof p === 'string') {\n throw new Error('string type in extglob ast??');\n }\n /* c8 ignore stop */\n // can ignore hasMagic, because extglobs are already always magic\n const [re, _, _hasMagic, uflag] = p.toRegExpSource(dot);\n this.#uflag = this.#uflag || uflag;\n return re;\n })\n .filter(p => !(this.isStart() && this.isEnd()) || !!p)\n .join('|');\n }\n static #parseGlob(glob, hasMagic, noEmpty = false) {\n let escaping = false;\n let re = '';\n let uflag = false;\n // multiple stars that aren't globstars coalesce into one *\n let inStar = false;\n for (let i = 0; i < glob.length; i++) {\n const c = glob.charAt(i);\n if (escaping) {\n escaping = false;\n re += (reSpecials.has(c) ? '\\\\' : '') + c;\n continue;\n }\n if (c === '*') {\n if (inStar)\n continue;\n inStar = true;\n re += noEmpty && /^[*]+$/.test(glob) ? starNoEmpty : star;\n hasMagic = true;\n continue;\n }\n else {\n inStar = false;\n }\n if (c === '\\\\') {\n if (i === glob.length - 1) {\n re += '\\\\\\\\';\n }\n else {\n escaping = true;\n }\n continue;\n }\n if (c === '[') {\n const [src, needUflag, consumed, magic] = parseClass(glob, i);\n if (consumed) {\n re += src;\n uflag = uflag || needUflag;\n i += consumed - 1;\n hasMagic = hasMagic || magic;\n continue;\n }\n }\n if (c === '?') {\n re += qmark;\n hasMagic = true;\n continue;\n }\n re += regExpEscape(c);\n }\n return [re, unescape(glob), !!hasMagic, uflag];\n }\n}\n_a = AST;\n//# sourceMappingURL=ast.js.map"],"names":["i","acc","start","final"],"mappings":"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","x_google_ignoreList":[0]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"brace-expressions.js","sources":["../../../../../../../../../../node_modules/.pnpm/minimatch@10.2.
|
|
1
|
+
{"version":3,"file":"brace-expressions.js","sources":["../../../../../../../../../../node_modules/.pnpm/minimatch@10.2.5/node_modules/minimatch/dist/esm/brace-expressions.js"],"sourcesContent":["// translate the various posix character classes into unicode properties\n// this works across all unicode locales\n// { <posix class>: [<translation>, /u flag required, negated]\nconst posixClasses = {\n '[:alnum:]': ['\\\\p{L}\\\\p{Nl}\\\\p{Nd}', true],\n '[:alpha:]': ['\\\\p{L}\\\\p{Nl}', true],\n '[:ascii:]': ['\\\\x' + '00-\\\\x' + '7f', false],\n '[:blank:]': ['\\\\p{Zs}\\\\t', true],\n '[:cntrl:]': ['\\\\p{Cc}', true],\n '[:digit:]': ['\\\\p{Nd}', true],\n '[:graph:]': ['\\\\p{Z}\\\\p{C}', true, true],\n '[:lower:]': ['\\\\p{Ll}', true],\n '[:print:]': ['\\\\p{C}', true],\n '[:punct:]': ['\\\\p{P}', true],\n '[:space:]': ['\\\\p{Z}\\\\t\\\\r\\\\n\\\\v\\\\f', true],\n '[:upper:]': ['\\\\p{Lu}', true],\n '[:word:]': ['\\\\p{L}\\\\p{Nl}\\\\p{Nd}\\\\p{Pc}', true],\n '[:xdigit:]': ['A-Fa-f0-9', false],\n};\n// only need to escape a few things inside of brace expressions\n// escapes: [ \\ ] -\nconst braceEscape = (s) => s.replace(/[[\\]\\\\-]/g, '\\\\$&');\n// escape all regexp magic characters\nconst regexpEscape = (s) => s.replace(/[-[\\]{}()*+?.,\\\\^$|#\\s]/g, '\\\\$&');\n// everything has already been escaped, we just have to join\nconst rangesToString = (ranges) => ranges.join('');\n// takes a glob string at a posix brace expression, and returns\n// an equivalent regular expression source, and boolean indicating\n// whether the /u flag needs to be applied, and the number of chars\n// consumed to parse the character class.\n// This also removes out of order ranges, and returns ($.) if the\n// entire class just no good.\nexport const parseClass = (glob, position) => {\n const pos = position;\n /* c8 ignore start */\n if (glob.charAt(pos) !== '[') {\n throw new Error('not in a brace expression');\n }\n /* c8 ignore stop */\n const ranges = [];\n const negs = [];\n let i = pos + 1;\n let sawStart = false;\n let uflag = false;\n let escaping = false;\n let negate = false;\n let endPos = pos;\n let rangeStart = '';\n WHILE: while (i < glob.length) {\n const c = glob.charAt(i);\n if ((c === '!' || c === '^') && i === pos + 1) {\n negate = true;\n i++;\n continue;\n }\n if (c === ']' && sawStart && !escaping) {\n endPos = i + 1;\n break;\n }\n sawStart = true;\n if (c === '\\\\') {\n if (!escaping) {\n escaping = true;\n i++;\n continue;\n }\n // escaped \\ char, fall through and treat like normal char\n }\n if (c === '[' && !escaping) {\n // either a posix class, a collation equivalent, or just a [\n for (const [cls, [unip, u, neg]] of Object.entries(posixClasses)) {\n if (glob.startsWith(cls, i)) {\n // invalid, [a-[] is fine, but not [a-[:alpha]]\n if (rangeStart) {\n return ['$.', false, glob.length - pos, true];\n }\n i += cls.length;\n if (neg)\n negs.push(unip);\n else\n ranges.push(unip);\n uflag = uflag || u;\n continue WHILE;\n }\n }\n }\n // now it's just a normal character, effectively\n escaping = false;\n if (rangeStart) {\n // throw this range away if it's not valid, but others\n // can still match.\n if (c > rangeStart) {\n ranges.push(braceEscape(rangeStart) + '-' + braceEscape(c));\n }\n else if (c === rangeStart) {\n ranges.push(braceEscape(c));\n }\n rangeStart = '';\n i++;\n continue;\n }\n // now might be the start of a range.\n // can be either c-d or c-] or c<more...>] or c] at this point\n if (glob.startsWith('-]', i + 1)) {\n ranges.push(braceEscape(c + '-'));\n i += 2;\n continue;\n }\n if (glob.startsWith('-', i + 1)) {\n rangeStart = c;\n i += 2;\n continue;\n }\n // not the start of a range, just a single character\n ranges.push(braceEscape(c));\n i++;\n }\n if (endPos < i) {\n // didn't see the end of the class, not a valid class,\n // but might still be valid as a literal match.\n return ['', false, 0, false];\n }\n // if we got no ranges and no negates, then we have a range that\n // cannot possibly match anything, and that poisons the whole glob\n if (!ranges.length && !negs.length) {\n return ['$.', false, glob.length - pos, true];\n }\n // if we got one positive range, and it's a single character, then that's\n // not actually a magic pattern, it's just that one literal character.\n // we should not treat that as \"magic\", we should just return the literal\n // character. [_] is a perfectly valid way to escape glob magic chars.\n if (negs.length === 0 &&\n ranges.length === 1 &&\n /^\\\\?.$/.test(ranges[0]) &&\n !negate) {\n const r = ranges[0].length === 2 ? ranges[0].slice(-1) : ranges[0];\n return [regexpEscape(r), false, endPos - pos, false];\n }\n const sranges = '[' + (negate ? '^' : '') + rangesToString(ranges) + ']';\n const snegs = '[' + (negate ? '' : '^') + rangesToString(negs) + ']';\n const comb = ranges.length && negs.length ? '(' + sranges + '|' + snegs + ')'\n : ranges.length ? sranges\n : snegs;\n return [comb, uflag, endPos - pos, true];\n};\n//# sourceMappingURL=brace-expressions.js.map"],"names":[],"mappings":"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","x_google_ignoreList":[0]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"escape.js","sources":["../../../../../../../../../../node_modules/.pnpm/minimatch@10.2.
|
|
1
|
+
{"version":3,"file":"escape.js","sources":["../../../../../../../../../../node_modules/.pnpm/minimatch@10.2.5/node_modules/minimatch/dist/esm/escape.js"],"sourcesContent":["/**\n * Escape all magic characters in a glob pattern.\n *\n * If the {@link MinimatchOptions.windowsPathsNoEscape}\n * option is used, then characters are escaped by wrapping in `[]`, because\n * a magic character wrapped in a character class can only be satisfied by\n * that exact character. In this mode, `\\` is _not_ escaped, because it is\n * not interpreted as a magic character, but instead as a path separator.\n *\n * If the {@link MinimatchOptions.magicalBraces} option is used,\n * then braces (`{` and `}`) will be escaped.\n */\nexport const escape = (s, { windowsPathsNoEscape = false, magicalBraces = false, } = {}) => {\n // don't need to escape +@! because we escape the parens\n // that make those magic, and escaping ! as [!] isn't valid,\n // because [!]] is a valid glob class meaning not ']'.\n if (magicalBraces) {\n return windowsPathsNoEscape ?\n s.replace(/[?*()[\\]{}]/g, '[$&]')\n : s.replace(/[?*()[\\]\\\\{}]/g, '\\\\$&');\n }\n return windowsPathsNoEscape ?\n s.replace(/[?*()[\\]]/g, '[$&]')\n : s.replace(/[?*()[\\]\\\\]/g, '\\\\$&');\n};\n//# sourceMappingURL=escape.js.map"],"names":[],"mappings":"AAYY,MAAC,SAAS,CAAC,GAAG,EAAE,uBAAuB,OAAO,gBAAgB,MAAK,IAAM,OAAO;AAIxF,MAAI,eAAe;AACf,WAAO,uBACH,EAAE,QAAQ,gBAAgB,MAAM,IAC9B,EAAE,QAAQ,kBAAkB,MAAM;AAAA,EAC5C;AACA,SAAO,uBACH,EAAE,QAAQ,cAAc,MAAM,IAC5B,EAAE,QAAQ,gBAAgB,MAAM;AAC1C;","x_google_ignoreList":[0]}
|
|
@@ -10,7 +10,7 @@ const minimatch = (p, pattern, options = {}) => {
|
|
|
10
10
|
}
|
|
11
11
|
return new Minimatch(pattern, options).match(p);
|
|
12
12
|
};
|
|
13
|
-
const starDotExtRE = /^\*+([
|
|
13
|
+
const starDotExtRE = /^\*+([^+@!?*[(]*)$/;
|
|
14
14
|
const starDotExtTest = (ext2) => (f) => !f.startsWith(".") && f.endsWith(ext2);
|
|
15
15
|
const starDotExtTestDot = (ext2) => (f) => f.endsWith(ext2);
|
|
16
16
|
const starDotExtTestNocase = (ext2) => {
|
|
@@ -29,7 +29,7 @@ const dotStarTest = (f) => f !== "." && f !== ".." && f.startsWith(".");
|
|
|
29
29
|
const starRE = /^\*+$/;
|
|
30
30
|
const starTest = (f) => f.length !== 0 && !f.startsWith(".");
|
|
31
31
|
const starTestDot = (f) => f.length !== 0 && f !== "." && f !== "..";
|
|
32
|
-
const qmarksRE = /^\?+([
|
|
32
|
+
const qmarksRE = /^\?+([^+@!?*[(]*)?$/;
|
|
33
33
|
const qmarksTestNocase = ([$0, ext2 = ""]) => {
|
|
34
34
|
const noext = qmarksTestNoExt([$0]);
|
|
35
35
|
if (!ext2)
|
|
@@ -248,10 +248,10 @@ class Minimatch {
|
|
|
248
248
|
// of patterns that we have to process.
|
|
249
249
|
preprocess(globParts) {
|
|
250
250
|
if (this.options.noglobstar) {
|
|
251
|
-
for (
|
|
252
|
-
for (let j = 0; j <
|
|
253
|
-
if (
|
|
254
|
-
|
|
251
|
+
for (const partset of globParts) {
|
|
252
|
+
for (let j = 0; j < partset.length; j++) {
|
|
253
|
+
if (partset[j] === "**") {
|
|
254
|
+
partset[j] = "*";
|
|
255
255
|
}
|
|
256
256
|
}
|
|
257
257
|
}
|
|
@@ -329,7 +329,7 @@ class Minimatch {
|
|
|
329
329
|
let dd = 0;
|
|
330
330
|
while (-1 !== (dd = parts.indexOf("..", dd + 1))) {
|
|
331
331
|
const p = parts[dd - 1];
|
|
332
|
-
if (p && p !== "." && p !== ".." && p !== "**") {
|
|
332
|
+
if (p && p !== "." && p !== ".." && p !== "**" && !(this.isWindows && /^[a-z]:$/i.test(p))) {
|
|
333
333
|
didSomething = true;
|
|
334
334
|
parts.splice(dd - 1, 2);
|
|
335
335
|
dd -= 2;
|
|
@@ -527,7 +527,11 @@ class Minimatch {
|
|
|
527
527
|
#matchGlobstar(file, pattern, partial, fileIndex, patternIndex) {
|
|
528
528
|
const firstgs = pattern.indexOf(GLOBSTAR, patternIndex);
|
|
529
529
|
const lastgs = pattern.lastIndexOf(GLOBSTAR);
|
|
530
|
-
const [head, body, tail] = [
|
|
530
|
+
const [head, body, tail] = partial ? [
|
|
531
|
+
pattern.slice(patternIndex, firstgs),
|
|
532
|
+
pattern.slice(firstgs + 1),
|
|
533
|
+
[]
|
|
534
|
+
] : [
|
|
531
535
|
pattern.slice(patternIndex, firstgs),
|
|
532
536
|
pattern.slice(firstgs + 1, lastgs),
|
|
533
537
|
pattern.slice(lastgs + 1)
|
|
@@ -567,7 +571,7 @@ class Minimatch {
|
|
|
567
571
|
return false;
|
|
568
572
|
}
|
|
569
573
|
}
|
|
570
|
-
return sawSome;
|
|
574
|
+
return partial || sawSome;
|
|
571
575
|
}
|
|
572
576
|
const bodySegments = [[[], 0]];
|
|
573
577
|
let currentBody = bodySegments[0];
|
|
@@ -619,7 +623,7 @@ class Minimatch {
|
|
|
619
623
|
}
|
|
620
624
|
fileIndex++;
|
|
621
625
|
}
|
|
622
|
-
return null;
|
|
626
|
+
return partial || null;
|
|
623
627
|
}
|
|
624
628
|
#matchOne(file, pattern, partial, fileIndex, patternIndex) {
|
|
625
629
|
let fi;
|
|
@@ -741,7 +745,7 @@ class Minimatch {
|
|
|
741
745
|
re = "^(?!" + re + ").+$";
|
|
742
746
|
try {
|
|
743
747
|
this.regexp = new RegExp(re, [...flags].join(""));
|
|
744
|
-
} catch
|
|
748
|
+
} catch {
|
|
745
749
|
this.regexp = false;
|
|
746
750
|
}
|
|
747
751
|
return this.regexp;
|
|
@@ -749,7 +753,7 @@ class Minimatch {
|
|
|
749
753
|
slashSplit(p) {
|
|
750
754
|
if (this.preserveMultipleSlashes) {
|
|
751
755
|
return p.split("/");
|
|
752
|
-
} else if (this.isWindows && /^\/\/[
|
|
756
|
+
} else if (this.isWindows && /^\/\/[^/]+/.test(p)) {
|
|
753
757
|
return ["", ...p.split(/\/+/)];
|
|
754
758
|
} else {
|
|
755
759
|
return p.split(/\/+/);
|
|
@@ -780,8 +784,7 @@ class Minimatch {
|
|
|
780
784
|
filename = ff[i];
|
|
781
785
|
}
|
|
782
786
|
}
|
|
783
|
-
for (
|
|
784
|
-
const pattern = set[i];
|
|
787
|
+
for (const pattern of set) {
|
|
785
788
|
let file = ff;
|
|
786
789
|
if (options.matchBase && pattern.length === 1) {
|
|
787
790
|
file = [filename];
|