@pgsql/transform 18.1.0 → 18.3.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 (113) hide show
  1. package/README.md +29 -73
  2. package/categorize.d.ts +52 -0
  3. package/categorize.js +56 -0
  4. package/esm/categorize.js +51 -0
  5. package/esm/facts.js +289 -0
  6. package/esm/fixture-closure.js +197 -0
  7. package/esm/index.js +7 -22
  8. package/esm/qualify.js +297 -0
  9. package/esm/round-trip-core.js +126 -0
  10. package/esm/round-trip.js +116 -0
  11. package/esm/transform.js +1169 -0
  12. package/facts.d.ts +69 -0
  13. package/facts.js +292 -0
  14. package/fixture-closure.d.ts +71 -0
  15. package/fixture-closure.js +200 -0
  16. package/index.d.ts +14 -28
  17. package/index.js +43 -76
  18. package/package.json +22 -14
  19. package/qualify.d.ts +125 -0
  20. package/qualify.js +303 -0
  21. package/round-trip-core.d.ts +60 -0
  22. package/round-trip-core.js +133 -0
  23. package/round-trip.d.ts +47 -0
  24. package/round-trip.js +123 -0
  25. package/transform.d.ts +259 -0
  26. package/transform.js +1190 -0
  27. package/13/enums.d.ts +0 -62
  28. package/13/enums.js +0 -2
  29. package/13/types.d.ts +0 -2103
  30. package/13/types.js +0 -2
  31. package/14/enums.d.ts +0 -62
  32. package/14/enums.js +0 -2
  33. package/14/types.d.ts +0 -2164
  34. package/14/types.js +0 -2
  35. package/15/enums.d.ts +0 -64
  36. package/15/enums.js +0 -2
  37. package/15/types.d.ts +0 -2222
  38. package/15/types.js +0 -2
  39. package/16/enums.d.ts +0 -69
  40. package/16/enums.js +0 -2
  41. package/16/types.d.ts +0 -2328
  42. package/16/types.js +0 -2
  43. package/17/enums.d.ts +0 -76
  44. package/17/enums.js +0 -2
  45. package/17/types.d.ts +0 -2488
  46. package/17/types.js +0 -2
  47. package/18/enums.d.ts +0 -78
  48. package/18/enums.js +0 -2
  49. package/18/types.d.ts +0 -2538
  50. package/18/types.js +0 -2
  51. package/esm/13/enums.js +0 -1
  52. package/esm/13/types.js +0 -1
  53. package/esm/14/enums.js +0 -1
  54. package/esm/14/types.js +0 -1
  55. package/esm/15/enums.js +0 -1
  56. package/esm/15/types.js +0 -1
  57. package/esm/16/enums.js +0 -1
  58. package/esm/16/types.js +0 -1
  59. package/esm/17/enums.js +0 -1
  60. package/esm/17/types.js +0 -1
  61. package/esm/18/enums.js +0 -1
  62. package/esm/18/types.js +0 -1
  63. package/esm/multi-version-transformer.js +0 -80
  64. package/esm/transformers/context.js +0 -1
  65. package/esm/transformers/v13-to-v14.js +0 -2767
  66. package/esm/transformers/v14-to-v15.js +0 -1218
  67. package/esm/transformers/v15-to-v16.js +0 -2935
  68. package/esm/transformers/v16-to-v17.js +0 -1526
  69. package/esm/transformers/v17-to-v18.js +0 -204
  70. package/esm/transformers-direct/index.js +0 -13
  71. package/esm/transformers-direct/v13-to-v17/index.js +0 -74
  72. package/esm/transformers-direct/v13-to-v18/index.js +0 -84
  73. package/esm/transformers-direct/v14-to-v17/index.js +0 -63
  74. package/esm/transformers-direct/v14-to-v18/index.js +0 -73
  75. package/esm/transformers-direct/v15-to-v17/index.js +0 -53
  76. package/esm/transformers-direct/v15-to-v18/index.js +0 -62
  77. package/esm/transformers-direct/v16-to-v17/index.js +0 -40
  78. package/esm/transformers-direct/v16-to-v18/index.js +0 -51
  79. package/esm/transformers-direct/v17-to-v18/index.js +0 -39
  80. package/multi-version-transformer.d.ts +0 -14
  81. package/multi-version-transformer.js +0 -84
  82. package/transformers/context.d.ts +0 -4
  83. package/transformers/context.js +0 -2
  84. package/transformers/v13-to-v14.d.ts +0 -255
  85. package/transformers/v13-to-v14.js +0 -2771
  86. package/transformers/v14-to-v15.d.ts +0 -615
  87. package/transformers/v14-to-v15.js +0 -1222
  88. package/transformers/v15-to-v16.d.ts +0 -632
  89. package/transformers/v15-to-v16.js +0 -2939
  90. package/transformers/v16-to-v17.d.ts +0 -640
  91. package/transformers/v16-to-v17.js +0 -1530
  92. package/transformers/v17-to-v18.d.ts +0 -54
  93. package/transformers/v17-to-v18.js +0 -208
  94. package/transformers-direct/index.d.ts +0 -13
  95. package/transformers-direct/index.js +0 -25
  96. package/transformers-direct/v13-to-v17/index.d.ts +0 -27
  97. package/transformers-direct/v13-to-v17/index.js +0 -78
  98. package/transformers-direct/v13-to-v18/index.d.ts +0 -28
  99. package/transformers-direct/v13-to-v18/index.js +0 -88
  100. package/transformers-direct/v14-to-v17/index.d.ts +0 -26
  101. package/transformers-direct/v14-to-v17/index.js +0 -67
  102. package/transformers-direct/v14-to-v18/index.d.ts +0 -27
  103. package/transformers-direct/v14-to-v18/index.js +0 -77
  104. package/transformers-direct/v15-to-v17/index.d.ts +0 -25
  105. package/transformers-direct/v15-to-v17/index.js +0 -57
  106. package/transformers-direct/v15-to-v18/index.d.ts +0 -26
  107. package/transformers-direct/v15-to-v18/index.js +0 -66
  108. package/transformers-direct/v16-to-v17/index.d.ts +0 -24
  109. package/transformers-direct/v16-to-v17/index.js +0 -44
  110. package/transformers-direct/v16-to-v18/index.d.ts +0 -25
  111. package/transformers-direct/v16-to-v18/index.js +0 -55
  112. package/transformers-direct/v17-to-v18/index.d.ts +0 -24
  113. package/transformers-direct/v17-to-v18/index.js +0 -43
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Round-trip validation for the schema transform.
3
+ *
4
+ * After the transform deparses its mutated AST to SQL text, the emitted text
5
+ * must parse back to an AST that is structurally identical to the AST we
6
+ * deparsed (AST1 === AST2 after normalization). Any mismatch means the
7
+ * deparser dropped or mangled something (e.g. array bounds on a DECLAREd
8
+ * type), even though the output may still be syntactically valid SQL.
9
+ *
10
+ * Two comparisons are performed per file:
11
+ * - the SQL-level parse tree (with volatile fields and function body strings
12
+ * normalized — PL/pgSQL bodies are compared separately)
13
+ * - each PL/pgSQL function body, compared in dehydrated form so both sides
14
+ * go through the same hydrate -> dehydrate rendering
15
+ */
16
+ import { dehydratePlpgsqlAst, transformSync } from 'plpgsql-parser';
17
+ import { CLEAN_TREE_VOLATILE_KEYS, firstDifference, normalizeTree, } from './round-trip-core';
18
+ export { firstDifference };
19
+ /**
20
+ * Fields that legitimately differ between parses. Extends the upstream
21
+ * `cleanTree` volatile set (location/stmt_location/stmt_len) with:
22
+ * - lineno: source positions in PL/pgSQL nodes
23
+ * - dno/varno/recparentno: PL/pgSQL datum numbers — compiler bookkeeping
24
+ * assigned in parse-encounter order, which shifts when the deparser
25
+ * emits an equivalent-but-reordered statement (e.g. INTO placement).
26
+ * Structural identity is still checked via names/fieldnames.
27
+ */
28
+ const VOLATILE_KEYS = new Set([
29
+ ...CLEAN_TREE_VOLATILE_KEYS,
30
+ 'lineno',
31
+ 'dno',
32
+ 'varno',
33
+ 'recparentno',
34
+ ]);
35
+ /**
36
+ * PLpgSQL_recfield datums are created lazily by the PL/pgSQL compiler as
37
+ * record.field references are encountered while parsing expressions, so
38
+ * their presence/order in the datums array depends on expression text
39
+ * layout, not semantics.
40
+ */
41
+ function isRecfieldDatum(node) {
42
+ return !!node && typeof node === 'object' && 'PLpgSQL_recfield' in node;
43
+ }
44
+ /**
45
+ * Fortified, mutation-aware normalizer built on the shared round-trip core.
46
+ * Beyond the upstream `cleanTree` (position stripping + body trimming), it
47
+ * additionally sorts keys, drops lazily-created recfield datums, and replaces
48
+ * DefElem "as" bodies with a sentinel (PL/pgSQL body fidelity is checked
49
+ * separately via the dehydrated PL/pgSQL ASTs).
50
+ */
51
+ export function normalizeParseTree(node) {
52
+ return normalizeTree(node, {
53
+ volatileKeys: VOLATILE_KEYS,
54
+ sortKeys: true,
55
+ dropArrayItem: isRecfieldDatum,
56
+ keyHandlers: {
57
+ DefElem: (defElem, recurse) => defElem?.defname === 'as'
58
+ ? { ...recurse(defElem), arg: '<body>' }
59
+ : recurse(defElem),
60
+ },
61
+ });
62
+ }
63
+ /**
64
+ * Capture the normalized SQL parse tree and dehydrated PL/pgSQL function
65
+ * ASTs from a transform context (as produced by plpgsql-parser's
66
+ * transformSync callback). Call this AFTER mutating the context.
67
+ */
68
+ export function captureTransformAsts(ctx) {
69
+ const plpgsqlAsts = [];
70
+ for (const fn of ctx.functions) {
71
+ if (fn.plpgsql?.hydrated) {
72
+ plpgsqlAsts.push(normalizeParseTree(dehydratePlpgsqlAst(structuredClone(fn.plpgsql.hydrated))));
73
+ }
74
+ }
75
+ return {
76
+ sqlAst: normalizeParseTree(ctx.sql),
77
+ plpgsqlAsts,
78
+ };
79
+ }
80
+ /**
81
+ * Parse already-transformed SQL text and capture its ASTs the same way
82
+ * capture_transform_asts does for the pre-deparse context, so the two
83
+ * sides are directly comparable.
84
+ */
85
+ export function captureAstsFromSql(sql) {
86
+ let captured;
87
+ transformSync(sql, (ctx) => {
88
+ captured = captureTransformAsts(ctx);
89
+ }, { hydrate: true, pretty: true });
90
+ if (!captured) {
91
+ throw new Error('round-trip: failed to capture ASTs from transformed SQL');
92
+ }
93
+ return captured;
94
+ }
95
+ /**
96
+ * Assert that the transformed AST (captured before deparse) matches the AST
97
+ * obtained by re-parsing the emitted SQL. Throws with the first differing
98
+ * path on mismatch.
99
+ */
100
+ export function validateRoundTrip(before, transformedSql) {
101
+ const after = captureAstsFromSql(transformedSql);
102
+ const sqlDiff = firstDifference(before.sqlAst, after.sqlAst);
103
+ if (sqlDiff) {
104
+ throw new Error(`round-trip validation failed: SQL AST mismatch after deparse at ${sqlDiff}`);
105
+ }
106
+ if (before.plpgsqlAsts.length !== after.plpgsqlAsts.length) {
107
+ throw new Error(`round-trip validation failed: PL/pgSQL function count mismatch ` +
108
+ `(${before.plpgsqlAsts.length} before deparse vs ${after.plpgsqlAsts.length} after re-parse)`);
109
+ }
110
+ for (let i = 0; i < before.plpgsqlAsts.length; i++) {
111
+ const diff = firstDifference(before.plpgsqlAsts[i], after.plpgsqlAsts[i]);
112
+ if (diff) {
113
+ throw new Error(`round-trip validation failed: PL/pgSQL AST mismatch in function #${i} at ${diff}`);
114
+ }
115
+ }
116
+ }