pipework 0.17.1 → 0.19.0

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.
Files changed (41) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/REFERENCE.md +1190 -0
  3. package/dist/cli/commands/migrate.d.ts +16 -0
  4. package/dist/cli/commands/migrate.d.ts.map +1 -1
  5. package/dist/cli/commands/migrate.js +35 -4
  6. package/dist/cli/commands/migrate.js.map +1 -1
  7. package/dist/cli/index.d.ts.map +1 -1
  8. package/dist/cli/index.js +0 -2
  9. package/dist/cli/index.js.map +1 -1
  10. package/dist/data/migrate/apply.d.ts +5 -7
  11. package/dist/data/migrate/apply.d.ts.map +1 -1
  12. package/dist/data/migrate/apply.js +7 -95
  13. package/dist/data/migrate/apply.js.map +1 -1
  14. package/dist/data/migrate/check.d.ts +11 -4
  15. package/dist/data/migrate/check.d.ts.map +1 -1
  16. package/dist/data/migrate/check.js +40 -22
  17. package/dist/data/migrate/check.js.map +1 -1
  18. package/dist/data/migrate/index.d.ts +2 -1
  19. package/dist/data/migrate/index.d.ts.map +1 -1
  20. package/dist/data/migrate/index.js +1 -0
  21. package/dist/data/migrate/index.js.map +1 -1
  22. package/dist/data/migrate/post-process.d.ts.map +1 -1
  23. package/dist/data/migrate/post-process.js +15 -5
  24. package/dist/data/migrate/post-process.js.map +1 -1
  25. package/dist/data/migrate/pragma.d.ts +35 -0
  26. package/dist/data/migrate/pragma.d.ts.map +1 -0
  27. package/dist/data/migrate/pragma.js +47 -0
  28. package/dist/data/migrate/pragma.js.map +1 -0
  29. package/dist/data/migrate/run.d.ts +1 -3
  30. package/dist/data/migrate/run.d.ts.map +1 -1
  31. package/dist/data/migrate/run.js +9 -9
  32. package/dist/data/migrate/run.js.map +1 -1
  33. package/dist/data/migrate/safety.d.ts +1 -1
  34. package/dist/data/migrate/safety.d.ts.map +1 -1
  35. package/dist/data/migrate/safety.js +41 -20
  36. package/dist/data/migrate/safety.js.map +1 -1
  37. package/dist/data/migrate/statements.d.ts +65 -0
  38. package/dist/data/migrate/statements.d.ts.map +1 -0
  39. package/dist/data/migrate/statements.js +290 -0
  40. package/dist/data/migrate/statements.js.map +1 -0
  41. package/package.json +1 -1
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Migration pragmas — per-file declarations read from the migration's own
3
+ * comments.
4
+ *
5
+ * Authorization for a hazardous migration lives here rather than on the
6
+ * `pipework migrate` command line, and the distinction is the whole point.
7
+ * A CLI flag authorizes an *invocation*: it is written once, into a deploy
8
+ * workflow, by someone who cannot know what migration 0071 will contain nine
9
+ * months later. The first destructive migration that has to ship puts
10
+ * `--allow-destructive` in CI permanently, and from then on the gate is
11
+ * decorative — every later migration is pre-approved by a decision nobody
12
+ * revisits, and nothing about it shows up in review.
13
+ *
14
+ * A pragma authorizes a *file*. It is written by the person writing the
15
+ * destructive statement, at the moment they write it; it appears in the diff,
16
+ * so it is reviewed; it is versioned, so `git log` says who approved which
17
+ * drop; and it cannot go blanket — a pragma in 0065 says nothing about 0071.
18
+ * The deploy command stays a bare `pipework migrate` forever, which means
19
+ * there is no flag to erode.
20
+ *
21
+ * The migration tracker already records a content hash per applied migration
22
+ * and refuses edited-but-applied files, so a pragma cannot be quietly added
23
+ * after the fact.
24
+ */
25
+ export const PRAGMA_PREFIX = '-- pipework:';
26
+ export const PRAGMA_FOR = {
27
+ destructive: 'pipework:expect-destructive',
28
+ locking: 'pipework:expect-locking',
29
+ dynamic: 'pipework:expect-dynamic',
30
+ };
31
+ /**
32
+ * True when `sql` declares the given pragma. Pragmas are recognized only on
33
+ * their own comment line, so prose that happens to mention one does not
34
+ * authorize anything.
35
+ */
36
+ export function hasPragma(sql, kind) {
37
+ const wanted = PRAGMA_FOR[kind];
38
+ for (const line of sql.split('\n')) {
39
+ const trimmed = line.trim();
40
+ if (!trimmed.startsWith('--'))
41
+ continue;
42
+ if (trimmed.slice(2).trim() === wanted)
43
+ return true;
44
+ }
45
+ return false;
46
+ }
47
+ //# sourceMappingURL=pragma.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pragma.js","sourceRoot":"","sources":["../../../src/data/migrate/pragma.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,MAAM,CAAC,MAAM,aAAa,GAAG,cAAc,CAAA;AAK3C,MAAM,CAAC,MAAM,UAAU,GAA+B;IACpD,WAAW,EAAE,6BAA6B;IAC1C,OAAO,EAAE,yBAAyB;IAClC,OAAO,EAAE,yBAAyB;CACnC,CAAA;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW,EAAE,IAAgB;IACrD,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAA;IAC/B,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;QAC3B,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,SAAQ;QACvC,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,MAAM;YAAE,OAAO,IAAI,CAAA;IACrD,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC"}
@@ -2,8 +2,6 @@ import type { Manifold } from '../../core/pipework.js';
2
2
  import type { ResolvedDatabase } from '../../core/config/index.js';
3
3
  import { type MigrationCheckResult } from './check.js';
4
4
  export interface MigrateOptions {
5
- allowDestructive?: boolean;
6
- acknowledgeLock?: boolean;
7
5
  }
8
6
  export interface MigrateResult {
9
7
  database: string;
@@ -17,5 +15,5 @@ export declare class UnsafeMigrationError extends Error {
17
15
  constructor(check: MigrationCheckResult, message: string);
18
16
  }
19
17
  export declare function migrateAll(instance: Manifold, options?: MigrateOptions): Promise<MigrateResult[]>;
20
- export declare function migrateOne(instance: Manifold, dbConfig: ResolvedDatabase, options?: MigrateOptions): Promise<MigrateResult>;
18
+ export declare function migrateOne(instance: Manifold, dbConfig: ResolvedDatabase, _options?: MigrateOptions): Promise<MigrateResult>;
21
19
  //# sourceMappingURL=run.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/data/migrate/run.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAElE,OAAO,EAAmB,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAIvE,MAAM,WAAW,cAAc;IAC7B,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,MAAM,CAAA;IACrB,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,WAAW,EAAE,oBAAoB,CAAA;CAClC;AAED,qBAAa,oBAAqB,SAAQ,KAAK;aAG3B,KAAK,EAAE,oBAAoB;IAF7C,SAAkB,IAAI,0BAAyB;gBAE7B,KAAK,EAAE,oBAAoB,EAC3C,OAAO,EAAE,MAAM;CAIlB;AAED,wBAAsB,UAAU,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAU3G;AAED,wBAAsB,UAAU,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,gBAAgB,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,aAAa,CAAC,CAgDrI"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/data/migrate/run.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAElE,OAAO,EAAmB,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAQvE,MAAM,WAAW,cAAc;CAAG;AAElC,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,MAAM,CAAA;IACrB,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,WAAW,EAAE,oBAAoB,CAAA;CAClC;AAED,qBAAa,oBAAqB,SAAQ,KAAK;aAG3B,KAAK,EAAE,oBAAoB;IAF7C,SAAkB,IAAI,0BAAyB;gBAE7B,KAAK,EAAE,oBAAoB,EAC3C,OAAO,EAAE,MAAM;CAIlB;AAED,wBAAsB,UAAU,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAU3G;AAED,wBAAsB,UAAU,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,gBAAgB,EAAE,QAAQ,GAAE,cAAmB,GAAG,OAAO,CAAC,aAAa,CAAC,CA4CtI"}
@@ -21,7 +21,7 @@ export async function migrateAll(instance, options = {}) {
21
21
  }
22
22
  return results;
23
23
  }
24
- export async function migrateOne(instance, dbConfig, options = {}) {
24
+ export async function migrateOne(instance, dbConfig, _options = {}) {
25
25
  const conn = instance.pool.getOrCreate(dbConfig);
26
26
  // Scope the safety gate to pending migrations only — hazards in already-applied
27
27
  // migrations are history, not a decision the operator still gets to make.
@@ -29,14 +29,14 @@ export async function migrateOne(instance, dbConfig, options = {}) {
29
29
  // history can never run a clean no-op `migrate`.
30
30
  const safetyCheck = dbConfig.migrations !== undefined
31
31
  ? checkMigrations(dbConfig.migrations, await readAppliedState(conn.drizzle, dbConfig.migrationTable))
32
- : { safe: true, hasDestructive: false, hasLocking: false, fileHazards: [] };
33
- if (safetyCheck.hasDestructive && options.allowDestructive !== true) {
34
- throw new UnsafeMigrationError(safetyCheck, `Migration for "${dbConfig.name}" contains destructive operations (DROP TABLE, DROP COLUMN, etc.). ` +
35
- `Pass { allowDestructive: true } or use --allow-destructive on the CLI to proceed.`);
36
- }
37
- if (safetyCheck.hasLocking && options.acknowledgeLock !== true) {
38
- throw new UnsafeMigrationError(safetyCheck, `Migration for "${dbConfig.name}" contains operations that acquire heavy locks. ` +
39
- `Pass { acknowledgeLock: true } or use --acknowledge-lock on the CLI to proceed.`);
32
+ : { safe: true, hasDestructive: false, hasLocking: false, hasDynamic: false, declared: true, fileHazards: [] };
33
+ if (!safetyCheck.declared) {
34
+ const files = safetyCheck.fileHazards.filter(f => f.undeclared.length > 0);
35
+ const detail = files
36
+ .map(f => `${f.file} (${f.undeclared.join(', ')})`)
37
+ .join(', ');
38
+ throw new UnsafeMigrationError(safetyCheck, `Migration for "${dbConfig.name}" raises hazards that its own file does not declare: ${detail}. ` +
39
+ `Add the matching \`-- pipework:expect-*\` pragma to each migration and commit it.`);
40
40
  }
41
41
  let extensionsCreated = [];
42
42
  if (dbConfig.extensions.length > 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/data/migrate/run.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/data/migrate/run.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- export type Severity = 'destructive' | 'locking' | 'safe';
1
+ export type Severity = 'destructive' | 'locking' | 'dynamic' | 'safe';
2
2
  export interface MigrationHazard {
3
3
  severity: Severity;
4
4
  operation: string;
@@ -1 +1 @@
1
- {"version":3,"file":"safety.d.ts","sourceRoot":"","sources":["../../../src/data/migrate/safety.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,aAAa,GAAG,SAAS,GAAG,MAAM,CAAA;AAEzD,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,QAAQ,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;CACnB;AA8ED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,EAAE,CAmBzD;AASD,wBAAgB,aAAa,CAAC,OAAO,EAAE,eAAe,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAoB9E"}
1
+ {"version":3,"file":"safety.d.ts","sourceRoot":"","sources":["../../../src/data/migrate/safety.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,QAAQ,GAAG,aAAa,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,CAAA;AAErE,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,QAAQ,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;CACnB;AAuGD,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,EAAE,CAwBzD;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,eAAe,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAoB9E"}
@@ -1,3 +1,4 @@
1
+ import { scanStatements, blankLiterals } from './statements.js';
1
2
  const RULES = [
2
3
  // ── Destructive (data loss / backward-incompatible) ───────────────────
3
4
  {
@@ -63,15 +64,41 @@ const RULES = [
63
64
  operation: 'ADD FOREIGN KEY (without NOT VALID)',
64
65
  suggestion: 'Add the constraint with NOT VALID, then VALIDATE CONSTRAINT in a separate statement.',
65
66
  },
67
+ {
68
+ // Locking rather than destructive: on a non-empty table this fails loudly
69
+ // instead of losing data, so it aborts the deploy rather than silently
70
+ // damaging it. It is still a gate-worthy hazard, hence the rule (#334).
71
+ pattern: /\bADD\s+COLUMN\b[^;]*\bNOT\s+NULL\b/i,
72
+ severity: 'locking',
73
+ operation: 'ADD COLUMN NOT NULL (without DEFAULT)',
74
+ suggestion: 'Add the column nullable, backfill, then SET NOT NULL — or give it a DEFAULT so existing rows can be filled.',
75
+ except: /\bDEFAULT\b/i,
76
+ },
77
+ // ── Dynamic (SQL assembled at runtime — unanalyzable) ────────────────
78
+ {
79
+ // The gate reads text; `EXECUTE` runs text that does not exist yet. Rather
80
+ // than pretend to see through it, name it. This is also what lets string
81
+ // literals be treated as the inert data they almost always are: a literal
82
+ // is dangerous exactly when something EXECUTEs it, and that is structural
83
+ // rather than a guess about its contents (#334).
84
+ pattern: /\bEXECUTE\b/i,
85
+ severity: 'dynamic',
86
+ operation: 'dynamic SQL (EXECUTE)',
87
+ suggestion: 'The gate cannot analyze SQL built at runtime. Prefer static DDL; if runtime assembly is required, declare it in the migration.',
88
+ },
66
89
  ];
67
90
  export function analyzeSQL(sql) {
68
- const statements = splitStatements(sql);
91
+ const statements = scanStatements(sql);
69
92
  const hazards = [];
70
93
  for (const stmt of statements) {
94
+ // Rules match against the statement with string-literal contents blanked:
95
+ // literals are data, and DDL keywords sitting in seed data execute
96
+ // nothing. Dollar-quoted bodies stay intact — those are code.
97
+ const subject = blankLiterals(stmt);
71
98
  for (const rule of RULES) {
72
- if (!rule.pattern.test(stmt))
99
+ if (!rule.pattern.test(subject))
73
100
  continue;
74
- if (rule.except !== undefined && rule.except.test(stmt))
101
+ if (rule.except !== undefined && rule.except.test(subject))
75
102
  continue;
76
103
  hazards.push({
77
104
  severity: rule.severity,
@@ -83,26 +110,20 @@ export function analyzeSQL(sql) {
83
110
  }
84
111
  return hazards;
85
112
  }
86
- function splitStatements(sql) {
87
- return sql
88
- .split(/;/)
89
- .map(s => s.trim())
90
- .filter(s => s.length > 0 && !s.startsWith('--'));
91
- }
92
113
  export function formatHazards(hazards, file) {
93
- const destructive = hazards.filter(h => h.severity === 'destructive');
94
- const locking = hazards.filter(h => h.severity === 'locking');
95
114
  const lines = [];
96
115
  lines.push(` ${file}:`);
97
- for (const h of destructive) {
98
- lines.push(` ✗ DESTRUCTIVE: ${h.operation}`);
99
- lines.push(` ${truncate(h.statement, 120)}`);
100
- lines.push(` → ${h.suggestion}`);
101
- }
102
- for (const h of locking) {
103
- lines.push(` ⚠ LOCKING: ${h.operation}`);
104
- lines.push(` ${truncate(h.statement, 120)}`);
105
- lines.push(` → ${h.suggestion}`);
116
+ const label = {
117
+ destructive: '✗ DESTRUCTIVE',
118
+ locking: '⚠ LOCKING',
119
+ dynamic: '? DYNAMIC',
120
+ };
121
+ for (const severity of ['destructive', 'locking', 'dynamic']) {
122
+ for (const h of hazards.filter(x => x.severity === severity)) {
123
+ lines.push(` ${label[severity]}: ${h.operation}`);
124
+ lines.push(` ${truncate(h.statement, 120)}`);
125
+ lines.push(` → ${h.suggestion}`);
126
+ }
106
127
  }
107
128
  return lines.join('\n');
108
129
  }
@@ -1 +1 @@
1
- {"version":3,"file":"safety.js","sourceRoot":"","sources":["../../../src/data/migrate/safety.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"safety.js","sourceRoot":"","sources":["../../../src/data/migrate/safety.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * One SQL scanner, shared by everything in the migrate pipeline that has to
3
+ * reason about statement boundaries.
4
+ *
5
+ * There were two hand-rolled splitters before this, and they disagreed. The
6
+ * runner (`parseStatements`) learned string literals and dollar-quoted bodies
7
+ * in #317 so a plpgsql function body would survive; the safety gate kept a
8
+ * `sql.split(';')` that then discarded any fragment starting with `--`. Since
9
+ * a statement and the comment above it land in the *same* fragment, the gate
10
+ * dropped comment-led statements entirely and reported migrations clean that
11
+ * dropped tables (#334). Neither splitter knew about block comments or quoted
12
+ * identifiers.
13
+ *
14
+ * The rules, in one place:
15
+ *
16
+ * - `--` runs to end of line; block comments nest, per Postgres.
17
+ * - Comments are removed, replaced by whitespace so they still separate tokens.
18
+ * - `'…'`, `"…"` and `$tag$…$tag$` are copied verbatim — a `;` or `--` inside
19
+ * them is content, not syntax. Backslash escapes apply only in `E'…'`.
20
+ * - Comment state and quote state are decided in the same pass. That ordering
21
+ * is load-bearing: an apostrophe in a comment (`-- the migration's ancestors`)
22
+ * must not open a string literal, and a `--` inside a literal must not open
23
+ * a comment. Either check running first, alone, gets the other case wrong.
24
+ * - An unterminated comment or literal runs to end of input; the SQL is invalid
25
+ * either way and Postgres is what should say so.
26
+ */
27
+ export interface ScanOptions {
28
+ /**
29
+ * Honor drizzle's `--> statement-breakpoint` as an explicit statement
30
+ * separator. The runner needs this (it decides what is sent to Postgres as
31
+ * one statement); the safety gate does not care.
32
+ */
33
+ breakpointSeparator?: boolean;
34
+ }
35
+ /** Splits SQL into statements, stripping comments. */
36
+ export declare function scanStatements(sql: string, options?: ScanOptions): string[];
37
+ /**
38
+ * Removes comments, leaving literals and dollar-quoted bodies intact and
39
+ * statement separators where they were. For callers that need to test SQL
40
+ * against a pattern without a comment supplying a false match or hiding a
41
+ * real one.
42
+ */
43
+ export declare function stripComments(sql: string): string;
44
+ /**
45
+ * Replaces the *contents* of `'…'` string literals with spaces, keeping the
46
+ * quotes and the overall length.
47
+ *
48
+ * A string literal in a migration is data — `INSERT INTO notes VALUES
49
+ * ('a; DROP TABLE x')` drops nothing. Matching hazard rules against literal
50
+ * text raises a hazard for inert seed data, and no amount of pattern-tuning
51
+ * fixes that, because "is this text dangerous" is not answerable from the
52
+ * text. What makes a literal dangerous is `EXECUTE` running it, which is a
53
+ * structural fact and gets its own rule.
54
+ *
55
+ * Dollar-quoted bodies are deliberately NOT blanked: `DO $$ BEGIN DROP TABLE
56
+ * x; END $$` is code, and it executes during the migration.
57
+ */
58
+ export declare function blankLiterals(sql: string): string;
59
+ /**
60
+ * Index of the first character of actual SQL in `sql` — i.e. past any leading
61
+ * whitespace and comments. Lets a text rewriter skip a leading comment block
62
+ * without rewriting words inside it.
63
+ */
64
+ export declare function codeStartOffset(sql: string): number;
65
+ //# sourceMappingURL=statements.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"statements.d.ts","sourceRoot":"","sources":["../../../src/data/migrate/statements.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAMH,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAC9B;AAED,sDAAsD;AACtD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,EAAE,CAqE/E;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAmCjD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAmDjD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAoBnD"}
@@ -0,0 +1,290 @@
1
+ /**
2
+ * One SQL scanner, shared by everything in the migrate pipeline that has to
3
+ * reason about statement boundaries.
4
+ *
5
+ * There were two hand-rolled splitters before this, and they disagreed. The
6
+ * runner (`parseStatements`) learned string literals and dollar-quoted bodies
7
+ * in #317 so a plpgsql function body would survive; the safety gate kept a
8
+ * `sql.split(';')` that then discarded any fragment starting with `--`. Since
9
+ * a statement and the comment above it land in the *same* fragment, the gate
10
+ * dropped comment-led statements entirely and reported migrations clean that
11
+ * dropped tables (#334). Neither splitter knew about block comments or quoted
12
+ * identifiers.
13
+ *
14
+ * The rules, in one place:
15
+ *
16
+ * - `--` runs to end of line; block comments nest, per Postgres.
17
+ * - Comments are removed, replaced by whitespace so they still separate tokens.
18
+ * - `'…'`, `"…"` and `$tag$…$tag$` are copied verbatim — a `;` or `--` inside
19
+ * them is content, not syntax. Backslash escapes apply only in `E'…'`.
20
+ * - Comment state and quote state are decided in the same pass. That ordering
21
+ * is load-bearing: an apostrophe in a comment (`-- the migration's ancestors`)
22
+ * must not open a string literal, and a `--` inside a literal must not open
23
+ * a comment. Either check running first, alone, gets the other case wrong.
24
+ * - An unterminated comment or literal runs to end of input; the SQL is invalid
25
+ * either way and Postgres is what should say so.
26
+ */
27
+ const IDENT_CHAR = /[A-Za-z0-9_]/;
28
+ const STATEMENT_BREAKPOINT = '--> statement-breakpoint';
29
+ /** Splits SQL into statements, stripping comments. */
30
+ export function scanStatements(sql, options = {}) {
31
+ const statements = [];
32
+ let buf = '';
33
+ const flush = () => {
34
+ const stmt = buf.trim();
35
+ if (stmt.length > 0)
36
+ statements.push(stmt);
37
+ buf = '';
38
+ };
39
+ let i = 0;
40
+ while (i < sql.length) {
41
+ const c = sql[i];
42
+ const next = sql[i + 1];
43
+ // Line comment — runs to the newline, which is left to land as whitespace.
44
+ if (c === '-' && next === '-') {
45
+ const nl = sql.indexOf('\n', i);
46
+ const end = nl === -1 ? sql.length : nl;
47
+ if (options.breakpointSeparator === true && sql.slice(i, end).trim() === STATEMENT_BREAKPOINT)
48
+ flush();
49
+ i = end;
50
+ continue;
51
+ }
52
+ // Block comment — Postgres nests these, so track depth.
53
+ if (c === '/' && next === '*') {
54
+ i = skipBlockComment(sql, i);
55
+ buf += ' ';
56
+ continue;
57
+ }
58
+ // Dollar-quoted body — nothing inside is special, only the matching tag ends it.
59
+ const tag = dollarTagAt(sql, i);
60
+ if (tag !== null) {
61
+ const close = sql.indexOf(tag, i + tag.length);
62
+ const end = close === -1 ? sql.length : close + tag.length;
63
+ buf += sql.slice(i, end);
64
+ i = end;
65
+ continue;
66
+ }
67
+ // String literal. Backslashes escape only in an E'' string.
68
+ if (c === "'") {
69
+ const end = consumeQuoted(sql, i, "'", isEscapeString(sql, i));
70
+ buf += sql.slice(i, end);
71
+ i = end;
72
+ continue;
73
+ }
74
+ // Quoted identifier.
75
+ if (c === '"') {
76
+ const end = consumeQuoted(sql, i, '"', false);
77
+ buf += sql.slice(i, end);
78
+ i = end;
79
+ continue;
80
+ }
81
+ if (c === ';') {
82
+ flush();
83
+ i++;
84
+ continue;
85
+ }
86
+ buf += c;
87
+ i++;
88
+ }
89
+ flush();
90
+ return statements;
91
+ }
92
+ /**
93
+ * Removes comments, leaving literals and dollar-quoted bodies intact and
94
+ * statement separators where they were. For callers that need to test SQL
95
+ * against a pattern without a comment supplying a false match or hiding a
96
+ * real one.
97
+ */
98
+ export function stripComments(sql) {
99
+ let out = '';
100
+ let i = 0;
101
+ while (i < sql.length) {
102
+ const c = sql[i];
103
+ const next = sql[i + 1];
104
+ if (c === '-' && next === '-') {
105
+ const nl = sql.indexOf('\n', i);
106
+ i = nl === -1 ? sql.length : nl;
107
+ continue;
108
+ }
109
+ if (c === '/' && next === '*') {
110
+ i = skipBlockComment(sql, i);
111
+ out += ' ';
112
+ continue;
113
+ }
114
+ const tag = dollarTagAt(sql, i);
115
+ if (tag !== null) {
116
+ const close = sql.indexOf(tag, i + tag.length);
117
+ const end = close === -1 ? sql.length : close + tag.length;
118
+ out += sql.slice(i, end);
119
+ i = end;
120
+ continue;
121
+ }
122
+ if (c === "'" || c === '"') {
123
+ const end = consumeQuoted(sql, i, c, c === "'" && isEscapeString(sql, i));
124
+ out += sql.slice(i, end);
125
+ i = end;
126
+ continue;
127
+ }
128
+ out += c;
129
+ i++;
130
+ }
131
+ return out;
132
+ }
133
+ /**
134
+ * Replaces the *contents* of `'…'` string literals with spaces, keeping the
135
+ * quotes and the overall length.
136
+ *
137
+ * A string literal in a migration is data — `INSERT INTO notes VALUES
138
+ * ('a; DROP TABLE x')` drops nothing. Matching hazard rules against literal
139
+ * text raises a hazard for inert seed data, and no amount of pattern-tuning
140
+ * fixes that, because "is this text dangerous" is not answerable from the
141
+ * text. What makes a literal dangerous is `EXECUTE` running it, which is a
142
+ * structural fact and gets its own rule.
143
+ *
144
+ * Dollar-quoted bodies are deliberately NOT blanked: `DO $$ BEGIN DROP TABLE
145
+ * x; END $$` is code, and it executes during the migration.
146
+ */
147
+ export function blankLiterals(sql) {
148
+ let out = '';
149
+ let i = 0;
150
+ while (i < sql.length) {
151
+ const c = sql[i];
152
+ const next = sql[i + 1];
153
+ if (c === '-' && next === '-') {
154
+ const nl = sql.indexOf('\n', i);
155
+ const end = nl === -1 ? sql.length : nl;
156
+ out += sql.slice(i, end);
157
+ i = end;
158
+ continue;
159
+ }
160
+ if (c === '/' && next === '*') {
161
+ const end = skipBlockComment(sql, i);
162
+ out += sql.slice(i, end);
163
+ i = end;
164
+ continue;
165
+ }
166
+ const tag = dollarTagAt(sql, i);
167
+ if (tag !== null) {
168
+ // A dollar-quoted body is code, so it is kept — but the literals inside
169
+ // that code are still data, so recurse rather than copying it whole.
170
+ // `DO $$ BEGIN DROP TABLE x; END $$` must keep its DROP TABLE, while
171
+ // `DO $$ BEGIN EXECUTE 'DROP TABLE x'; END $$` must lose it and be
172
+ // caught by the EXECUTE rule instead.
173
+ const close = sql.indexOf(tag, i + tag.length);
174
+ const end = close === -1 ? sql.length : close + tag.length;
175
+ const inner = sql.slice(i + tag.length, close === -1 ? sql.length : close);
176
+ out += tag + blankLiterals(inner) + (close === -1 ? '' : tag);
177
+ i = end;
178
+ continue;
179
+ }
180
+ if (c === "'") {
181
+ const end = consumeQuoted(sql, i, "'", isEscapeString(sql, i));
182
+ const body = sql.slice(i + 1, Math.max(i + 1, end - 1));
183
+ out += "'" + body.replace(/[^\n]/g, ' ') + (end - i >= 2 ? "'" : '');
184
+ i = end;
185
+ continue;
186
+ }
187
+ if (c === '"') {
188
+ const end = consumeQuoted(sql, i, '"', false);
189
+ out += sql.slice(i, end);
190
+ i = end;
191
+ continue;
192
+ }
193
+ out += c;
194
+ i++;
195
+ }
196
+ return out;
197
+ }
198
+ /**
199
+ * Index of the first character of actual SQL in `sql` — i.e. past any leading
200
+ * whitespace and comments. Lets a text rewriter skip a leading comment block
201
+ * without rewriting words inside it.
202
+ */
203
+ export function codeStartOffset(sql) {
204
+ let i = 0;
205
+ while (i < sql.length) {
206
+ const c = sql[i];
207
+ if (/\s/.test(c)) {
208
+ i++;
209
+ continue;
210
+ }
211
+ if (c === '-' && sql[i + 1] === '-') {
212
+ const nl = sql.indexOf('\n', i);
213
+ i = nl === -1 ? sql.length : nl;
214
+ continue;
215
+ }
216
+ if (c === '/' && sql[i + 1] === '*') {
217
+ i = skipBlockComment(sql, i);
218
+ continue;
219
+ }
220
+ return i;
221
+ }
222
+ return sql.length;
223
+ }
224
+ /** `start` indexes the opening `/*`. Returns the index just past the matching close. */
225
+ function skipBlockComment(sql, start) {
226
+ let depth = 0;
227
+ let i = start;
228
+ while (i < sql.length) {
229
+ if (sql[i] === '/' && sql[i + 1] === '*') {
230
+ depth++;
231
+ i += 2;
232
+ continue;
233
+ }
234
+ if (sql[i] === '*' && sql[i + 1] === '/') {
235
+ depth--;
236
+ i += 2;
237
+ if (depth === 0)
238
+ return i;
239
+ continue;
240
+ }
241
+ i++;
242
+ }
243
+ return sql.length;
244
+ }
245
+ /**
246
+ * Returns the dollar-quote tag opening at `i` (`$$`, `$body$`), or null.
247
+ * Tags may not start with a digit, which is what keeps `$1` positional
248
+ * parameters from being read as the start of a quoted body.
249
+ */
250
+ function dollarTagAt(sql, i) {
251
+ if (sql[i] !== '$')
252
+ return null;
253
+ let j = i + 1;
254
+ while (j < sql.length && IDENT_CHAR.test(sql[j]))
255
+ j++;
256
+ if (sql[j] !== '$')
257
+ return null;
258
+ if (/[0-9]/.test(sql[i + 1] ?? ''))
259
+ return null;
260
+ return sql.slice(i, j + 1);
261
+ }
262
+ /** True when the quote at `i` opens an `E''` escape string. */
263
+ function isEscapeString(sql, i) {
264
+ const prev = sql[i - 1];
265
+ if (prev !== 'e' && prev !== 'E')
266
+ return false;
267
+ const before = sql[i - 2];
268
+ return before === undefined || !IDENT_CHAR.test(before);
269
+ }
270
+ /** Returns the index just past the closing quote, or end of input if unterminated. */
271
+ function consumeQuoted(sql, start, quote, backslashEscapes) {
272
+ let i = start + 1;
273
+ while (i < sql.length) {
274
+ const c = sql[i];
275
+ if (backslashEscapes && c === '\\') {
276
+ i += 2;
277
+ continue;
278
+ }
279
+ if (c === quote) {
280
+ if (sql[i + 1] === quote) {
281
+ i += 2;
282
+ continue;
283
+ }
284
+ return i + 1;
285
+ }
286
+ i++;
287
+ }
288
+ return sql.length;
289
+ }
290
+ //# sourceMappingURL=statements.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"statements.js","sourceRoot":"","sources":["../../../src/data/migrate/statements.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pipework",
3
- "version": "0.17.1",
3
+ "version": "0.19.0",
4
4
  "description": "TypeScript framework for multi-tenant SaaS applications. PostgreSQL-only.",
5
5
  "type": "module",
6
6
  "license": "MIT",