neonctl 2.28.0 → 2.29.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.
Files changed (135) hide show
  1. package/README.md +71 -71
  2. package/dist/analytics.js +35 -33
  3. package/dist/api.js +34 -34
  4. package/dist/auth.js +50 -44
  5. package/dist/cli.js +2 -2
  6. package/dist/commands/auth.js +58 -52
  7. package/dist/commands/bootstrap.js +115 -157
  8. package/dist/commands/branches.js +154 -147
  9. package/dist/commands/bucket.js +124 -118
  10. package/dist/commands/checkout.js +49 -49
  11. package/dist/commands/config.js +212 -88
  12. package/dist/commands/connection_string.js +62 -62
  13. package/dist/commands/data_api.js +96 -96
  14. package/dist/commands/databases.js +23 -23
  15. package/dist/commands/deploy.js +12 -12
  16. package/dist/commands/dev.js +114 -114
  17. package/dist/commands/env.js +43 -43
  18. package/dist/commands/functions.js +97 -98
  19. package/dist/commands/index.js +26 -26
  20. package/dist/commands/init.js +23 -22
  21. package/dist/commands/ip_allow.js +29 -29
  22. package/dist/commands/link.js +223 -166
  23. package/dist/commands/neon_auth.js +381 -363
  24. package/dist/commands/operations.js +11 -11
  25. package/dist/commands/orgs.js +8 -8
  26. package/dist/commands/projects.js +101 -99
  27. package/dist/commands/psql.js +31 -31
  28. package/dist/commands/roles.js +21 -21
  29. package/dist/commands/schema_diff.js +23 -23
  30. package/dist/commands/set_context.js +17 -17
  31. package/dist/commands/status.js +17 -17
  32. package/dist/commands/user.js +5 -5
  33. package/dist/commands/vpc_endpoints.js +50 -50
  34. package/dist/config.js +7 -7
  35. package/dist/config_format.js +5 -5
  36. package/dist/context.js +23 -16
  37. package/dist/current_branch_fast_path.js +6 -6
  38. package/dist/dev/env.js +34 -34
  39. package/dist/dev/functions.js +4 -4
  40. package/dist/dev/inputs.js +6 -6
  41. package/dist/dev/runtime.js +25 -25
  42. package/dist/env.js +14 -14
  43. package/dist/env_file.js +13 -13
  44. package/dist/errors.js +19 -19
  45. package/dist/functions_api.js +10 -10
  46. package/dist/help.js +15 -15
  47. package/dist/index.js +94 -92
  48. package/dist/log.js +2 -2
  49. package/dist/pkg.js +5 -5
  50. package/dist/psql/cli.js +4 -2
  51. package/dist/psql/command/cmd_cond.js +61 -61
  52. package/dist/psql/command/cmd_connect.js +159 -154
  53. package/dist/psql/command/cmd_copy.js +107 -97
  54. package/dist/psql/command/cmd_describe.js +368 -363
  55. package/dist/psql/command/cmd_format.js +276 -263
  56. package/dist/psql/command/cmd_io.js +269 -263
  57. package/dist/psql/command/cmd_lo.js +74 -66
  58. package/dist/psql/command/cmd_meta.js +148 -148
  59. package/dist/psql/command/cmd_misc.js +17 -17
  60. package/dist/psql/command/cmd_pipeline.js +142 -135
  61. package/dist/psql/command/cmd_restrict.js +25 -25
  62. package/dist/psql/command/cmd_show.js +183 -168
  63. package/dist/psql/command/dispatch.js +26 -26
  64. package/dist/psql/command/shared.js +14 -14
  65. package/dist/psql/complete/filenames.js +16 -16
  66. package/dist/psql/complete/index.js +4 -4
  67. package/dist/psql/complete/matcher.js +33 -32
  68. package/dist/psql/complete/psqlVars.js +173 -173
  69. package/dist/psql/complete/queries.js +5 -3
  70. package/dist/psql/complete/rules.js +900 -863
  71. package/dist/psql/core/common.js +136 -133
  72. package/dist/psql/core/help.js +343 -343
  73. package/dist/psql/core/mainloop.js +160 -153
  74. package/dist/psql/core/prompt.js +126 -123
  75. package/dist/psql/core/settings.js +111 -111
  76. package/dist/psql/core/sqlHelp.js +150 -150
  77. package/dist/psql/core/startup.js +211 -205
  78. package/dist/psql/core/syncVars.js +14 -14
  79. package/dist/psql/core/variables.js +24 -24
  80. package/dist/psql/describe/formatters.js +302 -289
  81. package/dist/psql/describe/processNamePattern.js +28 -28
  82. package/dist/psql/describe/queries.js +656 -651
  83. package/dist/psql/index.js +436 -411
  84. package/dist/psql/io/history.js +36 -36
  85. package/dist/psql/io/input.js +15 -15
  86. package/dist/psql/io/lineEditor/buffer.js +27 -25
  87. package/dist/psql/io/lineEditor/complete.js +15 -15
  88. package/dist/psql/io/lineEditor/filename.js +22 -22
  89. package/dist/psql/io/lineEditor/index.js +65 -62
  90. package/dist/psql/io/lineEditor/keymap.js +325 -318
  91. package/dist/psql/io/lineEditor/vt100.js +60 -60
  92. package/dist/psql/io/pgpass.js +18 -18
  93. package/dist/psql/io/pgservice.js +14 -14
  94. package/dist/psql/io/psqlrc.js +46 -46
  95. package/dist/psql/print/aligned.js +175 -166
  96. package/dist/psql/print/asciidoc.js +51 -51
  97. package/dist/psql/print/crosstab.js +34 -31
  98. package/dist/psql/print/csv.js +25 -22
  99. package/dist/psql/print/html.js +54 -54
  100. package/dist/psql/print/json.js +12 -12
  101. package/dist/psql/print/latex.js +118 -118
  102. package/dist/psql/print/pager.js +28 -26
  103. package/dist/psql/print/troff.js +48 -48
  104. package/dist/psql/print/unaligned.js +15 -14
  105. package/dist/psql/print/units.js +17 -17
  106. package/dist/psql/scanner/slash.js +48 -46
  107. package/dist/psql/scanner/sql.js +88 -84
  108. package/dist/psql/scanner/stringutils.js +21 -17
  109. package/dist/psql/types/index.js +7 -7
  110. package/dist/psql/types/scanner.js +8 -8
  111. package/dist/psql/wire/connection.js +341 -327
  112. package/dist/psql/wire/copy.js +7 -7
  113. package/dist/psql/wire/pipeline.js +26 -24
  114. package/dist/psql/wire/protocol.js +102 -102
  115. package/dist/psql/wire/sasl.js +62 -62
  116. package/dist/psql/wire/tls.js +79 -73
  117. package/dist/storage_api.js +15 -15
  118. package/dist/test_utils/fixtures.js +34 -31
  119. package/dist/test_utils/oauth_server.js +5 -5
  120. package/dist/utils/api_enums.js +13 -13
  121. package/dist/utils/branch_notice.js +5 -5
  122. package/dist/utils/branch_picker.js +26 -26
  123. package/dist/utils/compute_units.js +4 -4
  124. package/dist/utils/enrichers.js +20 -15
  125. package/dist/utils/esbuild.js +28 -28
  126. package/dist/utils/formats.js +1 -1
  127. package/dist/utils/middlewares.js +3 -3
  128. package/dist/utils/package_manager.js +68 -0
  129. package/dist/utils/point_in_time.js +12 -12
  130. package/dist/utils/psql.js +30 -30
  131. package/dist/utils/string.js +2 -2
  132. package/dist/utils/ui.js +9 -9
  133. package/dist/utils/zip.js +1 -1
  134. package/dist/writer.js +17 -17
  135. package/package.json +6 -7
@@ -84,8 +84,8 @@
84
84
  * residue and current state, and the caller is expected to read more input and
85
85
  * call again.
86
86
  */
87
- import { initialScanState } from '../types/scanner.js';
88
- import { tryConsumeVarSubstitution } from './stringutils.js';
87
+ import { initialScanState } from "../types/scanner.js";
88
+ import { tryConsumeVarSubstitution } from "./stringutils.js";
89
89
  // ---------------------------------------------------------------------------
90
90
  // Character predicates.
91
91
  //
@@ -142,25 +142,25 @@ const cloneState = (s) => ({
142
142
  // blocks, dollar-quoted bodies). Identifier letters are stored lower-cased.
143
143
  // ---------------------------------------------------------------------------
144
144
  const KEYWORD_PREFIX_LETTERS = new Set([
145
- 'c', // create
146
- 'f', // function
147
- 'p', // procedure
148
- 'o', // or
149
- 'r', // replace
145
+ "c", // create
146
+ "f", // function
147
+ "p", // procedure
148
+ "o", // or
149
+ "r", // replace
150
150
  ]);
151
151
  const PREFIX_MATCHES_CREATE_FN_OR_PROC = (letters) => {
152
- if (letters[0] !== 'c')
152
+ if (letters[0] !== "c")
153
153
  return false;
154
154
  // CREATE FUNCTION
155
- if (letters[1] === 'f')
155
+ if (letters[1] === "f")
156
156
  return true;
157
157
  // CREATE PROCEDURE
158
- if (letters[1] === 'p')
158
+ if (letters[1] === "p")
159
159
  return true;
160
160
  // CREATE OR REPLACE FUNCTION / PROCEDURE
161
- if (letters[1] === 'o' &&
162
- letters[2] === 'r' &&
163
- (letters[3] === 'f' || letters[3] === 'p')) {
161
+ if (letters[1] === "o" &&
162
+ letters[2] === "r" &&
163
+ (letters[3] === "f" || letters[3] === "p")) {
164
164
  return true;
165
165
  }
166
166
  return false;
@@ -178,7 +178,7 @@ const maybeTrackBeginEnd = (st, word) => {
178
178
  // PROCEDURE shape. Subsequent identifiers still bump `identifierCount`
179
179
  // — that lets the prefix slots stay aligned with the first 4 idents only.
180
180
  if (st.identifierCount === 0) {
181
- st.identifierLetters = ['', '', '', ''];
181
+ st.identifierLetters = ["", "", "", ""];
182
182
  }
183
183
  if (st.identifierCount < st.identifierLetters.length &&
184
184
  KEYWORD_PREFIX_LETTERS.has(lower[0])) {
@@ -187,33 +187,33 @@ const maybeTrackBeginEnd = (st, word) => {
187
187
  st.identifierCount++;
188
188
  if (!PREFIX_MATCHES_CREATE_FN_OR_PROC(st.identifierLetters))
189
189
  return;
190
- if (lower === 'begin') {
190
+ if (lower === "begin") {
191
191
  st.beginDepth++;
192
192
  }
193
- else if (lower === 'case') {
193
+ else if (lower === "case") {
194
194
  // Upstream comment: "CASE also ends with END. We only need to track
195
195
  // this if we are already inside a BEGIN." Guard so `SELECT CASE WHEN
196
196
  // ... END` outside a function body doesn't double-bump the counter.
197
197
  if (st.beginDepth >= 1)
198
198
  st.beginDepth++;
199
199
  }
200
- else if (lower === 'end') {
200
+ else if (lower === "end") {
201
201
  if (st.beginDepth > 0)
202
202
  st.beginDepth--;
203
203
  }
204
204
  };
205
205
  const matchDollarDelim = (s, i) => {
206
- if (s[i] !== '$')
206
+ if (s[i] !== "$")
207
207
  return null;
208
208
  // Empty tag: `$$`
209
- if (s[i + 1] === '$')
210
- return { tag: '', end: i + 2 };
209
+ if (s[i + 1] === "$")
210
+ return { tag: "", end: i + 2 };
211
211
  if (!isIdentStart(s[i + 1]))
212
212
  return null;
213
213
  let j = i + 2;
214
214
  while (j < s.length && isIdentCont(s[j]))
215
215
  j++;
216
- if (s[j] !== '$')
216
+ if (s[j] !== "$")
217
217
  return null;
218
218
  return { tag: s.slice(i + 1, j), end: j + 1 };
219
219
  };
@@ -230,7 +230,7 @@ const isExtendedStringStart = (input, quotePos) => {
230
230
  if (quotePos === 0)
231
231
  return false;
232
232
  const prev = input[quotePos - 1];
233
- if (prev !== 'E' && prev !== 'e')
233
+ if (prev !== "E" && prev !== "e")
234
234
  return false;
235
235
  // Must be a standalone E — not part of a longer identifier.
236
236
  if (quotePos >= 2 && isIdentCont(input[quotePos - 2]))
@@ -249,20 +249,20 @@ const consumeXeEscape = (input, i) => {
249
249
  const n = input[i + 1];
250
250
  if (n === undefined)
251
251
  return 1; // trailing backslash at EOF — caller stays open
252
- if (n >= '0' && n <= '7') {
252
+ if (n >= "0" && n <= "7") {
253
253
  // Octal \ooo (1..3 digits)
254
254
  let k = i + 2;
255
255
  let count = 1;
256
256
  while (k < input.length &&
257
257
  count < 3 &&
258
- input[k] >= '0' &&
259
- input[k] <= '7') {
258
+ input[k] >= "0" &&
259
+ input[k] <= "7") {
260
260
  k++;
261
261
  count++;
262
262
  }
263
263
  return k - i;
264
264
  }
265
- if (n === 'x') {
265
+ if (n === "x") {
266
266
  let k = i + 2;
267
267
  let count = 0;
268
268
  while (k < input.length && count < 2 && /[0-9a-fA-F]/.test(input[k])) {
@@ -271,7 +271,7 @@ const consumeXeEscape = (input, i) => {
271
271
  }
272
272
  return k - i; // even \x with no hex digits consumes 2 chars (matches xeunicodefail vibe)
273
273
  }
274
- if (n === 'u') {
274
+ if (n === "u") {
275
275
  let k = i + 2;
276
276
  let count = 0;
277
277
  while (k < input.length && count < 4 && /[0-9a-fA-F]/.test(input[k])) {
@@ -280,7 +280,7 @@ const consumeXeEscape = (input, i) => {
280
280
  }
281
281
  return k - i;
282
282
  }
283
- if (n === 'U') {
283
+ if (n === "U") {
284
284
  let k = i + 2;
285
285
  let count = 0;
286
286
  while (k < input.length && count < 8 && /[0-9a-fA-F]/.test(input[k])) {
@@ -313,12 +313,12 @@ const tryQuoteContinue = (input, i) => {
313
313
  let sawNewline = false;
314
314
  while (k < input.length) {
315
315
  const c = input[k];
316
- if (c === '\n' || c === '\r') {
316
+ if (c === "\n" || c === "\r") {
317
317
  sawNewline = true;
318
318
  k++;
319
319
  continue;
320
320
  }
321
- if (c === ' ' || c === '\t' || c === '\f' || c === '\v') {
321
+ if (c === " " || c === "\t" || c === "\f" || c === "\v") {
322
322
  k++;
323
323
  continue;
324
324
  }
@@ -338,7 +338,7 @@ const tryQuoteContinue = (input, i) => {
338
338
  const skipLineComment = (input, i) => {
339
339
  // Assumes input[i] === '-' and input[i+1] === '-'.
340
340
  let k = i + 2;
341
- while (k < input.length && input[k] !== '\n' && input[k] !== '\r')
341
+ while (k < input.length && input[k] !== "\n" && input[k] !== "\r")
342
342
  k++;
343
343
  return k;
344
344
  };
@@ -355,16 +355,16 @@ const skipLineComment = (input, i) => {
355
355
  // ---------------------------------------------------------------------------
356
356
  const computePromptStatus = (state) => {
357
357
  if (state.inBlockComment > 0)
358
- return 'comment';
358
+ return "comment";
359
359
  if (state.inSingleQuote)
360
- return 'continue-quote';
360
+ return "continue-quote";
361
361
  if (state.inDoubleQuote)
362
- return 'continue-dquote';
362
+ return "continue-dquote";
363
363
  if (state.dollarTag !== null)
364
- return 'continue-dollar';
364
+ return "continue-dollar";
365
365
  if (state.parenDepth > 0)
366
- return 'paren';
367
- return 'continue';
366
+ return "paren";
367
+ return "continue";
368
368
  };
369
369
  export const scanSql = (input, state, varLookup, slashCmdMode, options) => {
370
370
  const singleline = options?.singleline ?? false;
@@ -372,7 +372,7 @@ export const scanSql = (input, state, varLookup, slashCmdMode, options) => {
372
372
  const st = cloneState(state ?? initialScanState());
373
373
  // SQL accumulator. We append characters as we scan; this matches upstream's
374
374
  // `output_buf` which receives all ECHOed text.
375
- let sql = '';
375
+ let sql = "";
376
376
  let i = 0;
377
377
  // Convenience: emit characters from `from` (inclusive) up to `to` (exclusive)
378
378
  // into the SQL accumulator and advance the cursor.
@@ -384,15 +384,15 @@ export const scanSql = (input, state, varLookup, slashCmdMode, options) => {
384
384
  const c = input[i];
385
385
  // --- Inside a block comment: look for nested opens and closes. ---
386
386
  if (st.inBlockComment > 0) {
387
- if (c === '/' && input[i + 1] === '*') {
387
+ if (c === "/" && input[i + 1] === "*") {
388
388
  st.inBlockComment++;
389
- sql += '/*';
389
+ sql += "/*";
390
390
  i += 2;
391
391
  continue;
392
392
  }
393
- if (c === '*' && input[i + 1] === '/') {
393
+ if (c === "*" && input[i + 1] === "/") {
394
394
  st.inBlockComment--;
395
- sql += '*/';
395
+ sql += "*/";
396
396
  i += 2;
397
397
  continue;
398
398
  }
@@ -402,7 +402,7 @@ export const scanSql = (input, state, varLookup, slashCmdMode, options) => {
402
402
  }
403
403
  // --- Inside a single-quoted string (standard or extended). ---
404
404
  if (st.inSingleQuote) {
405
- if (st.inEscapeString && c === '\\') {
405
+ if (st.inEscapeString && c === "\\") {
406
406
  const n = consumeXeEscape(input, i);
407
407
  emit(i, i + n);
408
408
  continue;
@@ -460,7 +460,7 @@ export const scanSql = (input, state, varLookup, slashCmdMode, options) => {
460
460
  }
461
461
  // --- Inside a dollar-quoted string. ---
462
462
  if (st.dollarTag !== null) {
463
- if (c === '$') {
463
+ if (c === "$") {
464
464
  const m = matchDollarDelim(input, i);
465
465
  if (m !== null && m.tag === st.dollarTag) {
466
466
  sql += input.slice(i, m.end);
@@ -471,7 +471,7 @@ export const scanSql = (input, state, varLookup, slashCmdMode, options) => {
471
471
  // Either not a delim or a non-matching tag: consume just the $ and
472
472
  // keep scanning. This matches upstream's `<xdolq>.` fallback which
473
473
  // ECHOes the `$` and continues.
474
- sql += '$';
474
+ sql += "$";
475
475
  i++;
476
476
  continue;
477
477
  }
@@ -492,28 +492,28 @@ export const scanSql = (input, state, varLookup, slashCmdMode, options) => {
492
492
  // whitespace-only line emits the newline and keeps scanning so it never
493
493
  // dispatches an empty statement.
494
494
  if (singleline &&
495
- (c === '\n' || c === '\r') &&
495
+ (c === "\n" || c === "\r") &&
496
496
  st.beginDepth === 0 &&
497
497
  sql.trim().length > 0) {
498
498
  sql += c;
499
499
  i++;
500
500
  // Reset per-statement state, mirroring the `;` boundary below.
501
501
  return {
502
- kind: 'semicolon',
502
+ kind: "semicolon",
503
503
  sql,
504
504
  consumed: i,
505
505
  nextState: initialScanState(),
506
506
  };
507
507
  }
508
508
  // Block comment start.
509
- if (c === '/' && input[i + 1] === '*') {
509
+ if (c === "/" && input[i + 1] === "*") {
510
510
  st.inBlockComment = 1;
511
- sql += '/*';
511
+ sql += "/*";
512
512
  i += 2;
513
513
  continue;
514
514
  }
515
515
  // Line comment.
516
- if (c === '-' && input[i + 1] === '-') {
516
+ if (c === "-" && input[i + 1] === "-") {
517
517
  const end = skipLineComment(input, i);
518
518
  sql += input.slice(i, end);
519
519
  i = end;
@@ -538,7 +538,7 @@ export const scanSql = (input, state, varLookup, slashCmdMode, options) => {
538
538
  continue;
539
539
  }
540
540
  // Dollar-quoted string start.
541
- if (c === '$') {
541
+ if (c === "$") {
542
542
  const m = matchDollarDelim(input, i);
543
543
  if (m !== null) {
544
544
  sql += input.slice(i, m.end);
@@ -547,19 +547,19 @@ export const scanSql = (input, state, varLookup, slashCmdMode, options) => {
547
547
  continue;
548
548
  }
549
549
  // Lone `$` (e.g. param `$1` or just bare `$`): emit and continue.
550
- sql += '$';
550
+ sql += "$";
551
551
  i++;
552
552
  continue;
553
553
  }
554
554
  // Parentheses tracking.
555
- if (c === '(') {
556
- sql += '(';
555
+ if (c === "(") {
556
+ sql += "(";
557
557
  i++;
558
558
  st.parenDepth++;
559
559
  continue;
560
560
  }
561
- if (c === ')') {
562
- sql += ')';
561
+ if (c === ")") {
562
+ sql += ")";
563
563
  i++;
564
564
  if (st.parenDepth > 0)
565
565
  st.parenDepth--;
@@ -572,8 +572,8 @@ export const scanSql = (input, state, varLookup, slashCmdMode, options) => {
572
572
  // ATOMIC SELECT 1; SELECT 2; END;`) do not terminate the surrounding
573
573
  // CREATE statement. The depth-gated case falls through to the catch-all,
574
574
  // which emits the `;` and continues scanning.
575
- if (c === ';' && st.parenDepth === 0 && st.beginDepth === 0) {
576
- sql += ';';
575
+ if (c === ";" && st.parenDepth === 0 && st.beginDepth === 0) {
576
+ sql += ";";
577
577
  i++;
578
578
  // Reset per-statement state. (parenDepth, dollarTag, comment depths,
579
579
  // quote flags, beginDepth, and identifier tracking are all zero here
@@ -587,7 +587,7 @@ export const scanSql = (input, state, varLookup, slashCmdMode, options) => {
587
587
  // looked at yet; we hand that back inside `sql` only if we'd consumed
588
588
  // it. Since we returned right after the `;`, sql ends in `;`.
589
589
  return {
590
- kind: 'semicolon',
590
+ kind: "semicolon",
591
591
  sql,
592
592
  consumed: i,
593
593
  nextState: next,
@@ -604,12 +604,12 @@ export const scanSql = (input, state, varLookup, slashCmdMode, options) => {
604
604
  // hands back the buffered SQL alongside the command name + remaining
605
605
  // args; the mainloop forwards it into `BackslashContext.queryBuf` and the
606
606
  // command's `run()` is free to read or ignore it.
607
- if (c === '\\') {
607
+ if (c === "\\") {
608
608
  // Upstream special: `\;` and `\:` are forced into the query buffer (so a
609
609
  // user can write `SELECT 1\;` to suppress immediate dispatch). We honour
610
610
  // those by emitting just the second char and not breaking.
611
611
  const nxt = input[i + 1];
612
- if (nxt === ';' || nxt === ':') {
612
+ if (nxt === ";" || nxt === ":") {
613
613
  sql += nxt;
614
614
  i += 2;
615
615
  continue;
@@ -634,7 +634,8 @@ export const scanSql = (input, state, varLookup, slashCmdMode, options) => {
634
634
  // modifier on `\d+`/`\dt+`). Underscore is required for psql's
635
635
  // multi-word commands: `\lo_import`, `\lo_export`, `\lo_list`,
636
636
  // `\lo_unlink`, `\bind_named`, `\close_prepared`.
637
- while (cmdEnd < input.length && /[A-Za-z0-9_+]/.test(input[cmdEnd])) {
637
+ while (cmdEnd < input.length &&
638
+ /[A-Za-z0-9_+]/.test(input[cmdEnd])) {
638
639
  cmdEnd++;
639
640
  }
640
641
  }
@@ -657,15 +658,16 @@ export const scanSql = (input, state, varLookup, slashCmdMode, options) => {
657
658
  // commands enter whole-line mode only when the first non-whitespace
658
659
  // character is `|` — matching upstream's `<xslashargstart>` rule.
659
660
  const argMode = slashCmdMode?.(cmd);
660
- let consumeWholeLine = argMode === 'whole-line';
661
- if (argMode === 'filepipe') {
661
+ let consumeWholeLine = argMode === "whole-line";
662
+ if (argMode === "filepipe") {
662
663
  // Skip leading whitespace inside the arg; if the next char is `|`,
663
664
  // upstream switches into `<xslashwholeline>` for the rest of the line.
664
665
  let p = cmdEnd;
665
- while (p < input.length && (input[p] === ' ' || input[p] === '\t')) {
666
+ while (p < input.length &&
667
+ (input[p] === " " || input[p] === "\t")) {
666
668
  p++;
667
669
  }
668
- if (input[p] === '|')
670
+ if (input[p] === "|")
669
671
  consumeWholeLine = true;
670
672
  }
671
673
  // Rest of the line — up to a newline OR (for normal-mode commands)
@@ -699,8 +701,8 @@ export const scanSql = (input, state, varLookup, slashCmdMode, options) => {
699
701
  // the trailing `\` as a fresh empty-name backslash command.
700
702
  let sawDoubleBackslashSeparator = false;
701
703
  while (restEnd < input.length &&
702
- input[restEnd] !== '\n' &&
703
- input[restEnd] !== '\r') {
704
+ input[restEnd] !== "\n" &&
705
+ input[restEnd] !== "\r") {
704
706
  const ch = input[restEnd];
705
707
  if (consumeWholeLine) {
706
708
  // Whole-line / filepipe-pipe path: never break on `\`. Just walk
@@ -710,7 +712,7 @@ export const scanSql = (input, state, varLookup, slashCmdMode, options) => {
710
712
  }
711
713
  if (inSingle) {
712
714
  // C-style `\'` escape inside single quotes.
713
- if (ch === '\\' && input[restEnd + 1] !== undefined) {
715
+ if (ch === "\\" && input[restEnd + 1] !== undefined) {
714
716
  restEnd += 2;
715
717
  continue;
716
718
  }
@@ -722,17 +724,17 @@ export const scanSql = (input, state, varLookup, slashCmdMode, options) => {
722
724
  inDouble = false;
723
725
  }
724
726
  else if (inBack) {
725
- if (ch === '`')
727
+ if (ch === "`")
726
728
  inBack = false;
727
729
  }
728
730
  else {
729
- if (ch === '\\') {
731
+ if (ch === "\\") {
730
732
  // `\\` = "flush and continue" separator: end this command's
731
733
  // args HERE, but consume both backslashes so the next scan
732
734
  // resumes immediately after the pair. A lone `\` is a regular
733
735
  // next-slash-cmd boundary; we stop at it without consuming so
734
736
  // the next iteration picks it up.
735
- if (input[restEnd + 1] === '\\') {
737
+ if (input[restEnd + 1] === "\\") {
736
738
  sawDoubleBackslashSeparator = true;
737
739
  }
738
740
  break;
@@ -741,13 +743,15 @@ export const scanSql = (input, state, varLookup, slashCmdMode, options) => {
741
743
  inSingle = true;
742
744
  else if (ch === '"')
743
745
  inDouble = true;
744
- else if (ch === '`')
746
+ else if (ch === "`")
745
747
  inBack = true;
746
748
  }
747
749
  restEnd++;
748
750
  }
749
751
  const rest = input.slice(cmdEnd, restEnd);
750
- const consumed = sawDoubleBackslashSeparator ? restEnd + 2 : restEnd;
752
+ const consumed = sawDoubleBackslashSeparator
753
+ ? restEnd + 2
754
+ : restEnd;
751
755
  // Note: we *don't* consume the newline; it's left for the next chunk
752
756
  // so caller can see PROMPT1 reset cleanly. Upstream's
753
757
  // `psql_scan_slash_command_end()` does eat the trailing newline, but
@@ -758,7 +762,7 @@ export const scanSql = (input, state, varLookup, slashCmdMode, options) => {
758
762
  // from the working chunk so the next statement's queryBuf doesn't
759
763
  // pick it up via the `eof` accumulation path.
760
764
  return {
761
- kind: 'backslash',
765
+ kind: "backslash",
762
766
  cmd,
763
767
  rest,
764
768
  sql,
@@ -778,12 +782,12 @@ export const scanSql = (input, state, varLookup, slashCmdMode, options) => {
778
782
  // rule before the `:{variable}` rule can fire. We do not need to gate
779
783
  // this on `varLookup` — without substitution the result is byte-
780
784
  // identical to the catch-all path.
781
- if (c === ':' && input[i + 1] === ':') {
782
- sql += '::';
785
+ if (c === ":" && input[i + 1] === ":") {
786
+ sql += "::";
783
787
  i += 2;
784
788
  continue;
785
789
  }
786
- if (c === ':') {
790
+ if (c === ":") {
787
791
  const sub = tryConsumeVarSubstitution(input, i, varLookup);
788
792
  if (sub !== null) {
789
793
  sql += sub.text;
@@ -827,7 +831,7 @@ export const scanSql = (input, state, varLookup, slashCmdMode, options) => {
827
831
  const promptStatus = computePromptStatus(st);
828
832
  st.promptStatus = promptStatus;
829
833
  return {
830
- kind: 'incomplete',
834
+ kind: "incomplete",
831
835
  sql,
832
836
  consumed: i,
833
837
  nextState: cloneState(st),
@@ -839,7 +843,7 @@ export const scanSql = (input, state, varLookup, slashCmdMode, options) => {
839
843
  // mainloop bypasses the scanner and forwards raw lines until `\.`. See the
840
844
  // file header for the contract.
841
845
  return {
842
- kind: 'eof',
846
+ kind: "eof",
843
847
  sql,
844
848
  consumed: i,
845
849
  nextState: cloneState(st),
@@ -873,7 +877,7 @@ export const splitStatements = (input, varLookup, slashCmdMode, options) => {
873
877
  if (++safety > input.length + 10)
874
878
  break;
875
879
  const r = scanSql(remaining, state, varLookup, slashCmdMode, options);
876
- if (r.kind === 'semicolon') {
880
+ if (r.kind === "semicolon") {
877
881
  // When the caller requested variable substitution, the scanner has
878
882
  // already applied it to `r.sql` — we must push the transformed text,
879
883
  // not the raw input slice. Without substitution the slice and `r.sql`
@@ -884,7 +888,7 @@ export const splitStatements = (input, varLookup, slashCmdMode, options) => {
884
888
  state = r.nextState;
885
889
  continue;
886
890
  }
887
- if (r.kind === 'backslash') {
891
+ if (r.kind === "backslash") {
888
892
  // Emit the consumed input slice verbatim (covers any leading whitespace
889
893
  // that scanSql skipped over before the `\`, plus `\cmd rest`). The
890
894
  // slash-arg scanner will do its own variable expansion when the
@@ -894,7 +898,7 @@ export const splitStatements = (input, varLookup, slashCmdMode, options) => {
894
898
  state = r.nextState;
895
899
  continue;
896
900
  }
897
- if (r.kind === 'eof' || r.kind === 'incomplete') {
901
+ if (r.kind === "eof" || r.kind === "incomplete") {
898
902
  // No more boundaries in this input. Append residue if non-empty.
899
903
  // Same as the semicolon branch: emit `r.sql` (with substitutions
900
904
  // applied) when `varLookup` is set, otherwise pass the raw slice
@@ -902,7 +906,7 @@ export const splitStatements = (input, varLookup, slashCmdMode, options) => {
902
906
  if (remaining.length > 0) {
903
907
  out.push(varLookup ? r.sql : remaining);
904
908
  }
905
- remaining = '';
909
+ remaining = "";
906
910
  break;
907
911
  }
908
912
  }
@@ -85,7 +85,7 @@ export const strtokx = (input, whitespace, delim, quote, escape, eAcceptInUnquot
85
85
  while (i < n && whitespace.includes(input[i]))
86
86
  i++;
87
87
  if (i >= n) {
88
- return { token: null, rest: '' };
88
+ return { token: null, rest: "" };
89
89
  }
90
90
  // 2. Single-character delim token.
91
91
  if (delim.length > 0 && delim.includes(input[i])) {
@@ -112,7 +112,7 @@ export const strtokx = (input, whitespace, delim, quote, escape, eAcceptInUnquot
112
112
  eAcceptInUnquoted.includes(input[p]) &&
113
113
  input[p + 1] === "'") {
114
114
  effectiveQuote = "'";
115
- effectiveEscape = '\\';
115
+ effectiveEscape = "\\";
116
116
  p++;
117
117
  }
118
118
  if (effectiveQuote.length > 0 && effectiveQuote.includes(input[p])) {
@@ -121,7 +121,9 @@ export const strtokx = (input, whitespace, delim, quote, escape, eAcceptInUnquot
121
121
  p++; // step over opening quote
122
122
  while (p < n) {
123
123
  const c = input[p];
124
- if (effectiveEscape.length > 0 && c === effectiveEscape && p + 1 < n) {
124
+ if (effectiveEscape.length > 0 &&
125
+ c === effectiveEscape &&
126
+ p + 1 < n) {
125
127
  // escape + anything (except end-of-input) is a literal data char
126
128
  p += 2;
127
129
  continue;
@@ -185,10 +187,10 @@ export const strtokx = (input, whitespace, delim, quote, escape, eAcceptInUnquot
185
187
  */
186
188
  export const quoteIfNeeded = (value, escapeChars, quote) => {
187
189
  if (quote.length !== 1) {
188
- throw new Error('quoteIfNeeded: quote must be exactly one character');
190
+ throw new Error("quoteIfNeeded: quote must be exactly one character");
189
191
  }
190
192
  let needsQuotes = false;
191
- let escaped = '';
193
+ let escaped = "";
192
194
  for (const c of value) {
193
195
  if (c === quote) {
194
196
  needsQuotes = true;
@@ -214,14 +216,16 @@ export const quoteIfNeeded = (value, escapeChars, quote) => {
214
216
  */
215
217
  export const dequote = (value, quote) => {
216
218
  if (quote.length !== 1) {
217
- throw new Error('dequote: quote must be exactly one character');
219
+ throw new Error("dequote: quote must be exactly one character");
218
220
  }
219
- if (value.length < 2 || !value.startsWith(quote) || !value.endsWith(quote)) {
221
+ if (value.length < 2 ||
222
+ !value.startsWith(quote) ||
223
+ !value.endsWith(quote)) {
220
224
  return value;
221
225
  }
222
226
  const inner = value.slice(1, -1);
223
227
  // Undouble embedded quote chars.
224
- let out = '';
228
+ let out = "";
225
229
  let i = 0;
226
230
  while (i < inner.length) {
227
231
  if (inner[i] === quote && inner[i + 1] === quote) {
@@ -246,12 +250,12 @@ export const dequote = (value, quote) => {
246
250
  */
247
251
  export const quoteSqlLiteral = (value) => {
248
252
  let needsEscape = false;
249
- let inner = '';
253
+ let inner = "";
250
254
  for (const c of value) {
251
255
  if (c === "'")
252
256
  inner += "''";
253
- else if (c === '\\') {
254
- inner += '\\\\';
257
+ else if (c === "\\") {
258
+ inner += "\\\\";
255
259
  needsEscape = true;
256
260
  }
257
261
  else {
@@ -265,7 +269,7 @@ export const quoteSqlLiteral = (value) => {
265
269
  * Wraps the value in `"…"` and doubles any embedded `"`.
266
270
  */
267
271
  export const quoteSqlIdent = (value) => {
268
- let inner = '';
272
+ let inner = "";
269
273
  for (const c of value) {
270
274
  inner += c === '"' ? '""' : c;
271
275
  }
@@ -312,13 +316,13 @@ const isVarNameCont = (c) => c !== undefined && VAR_NAME_CONT_RE.test(c);
312
316
  export const tryConsumeVarSubstitution = (s, i, varLookup) => {
313
317
  if (varLookup === undefined)
314
318
  return null;
315
- if (s[i] !== ':')
319
+ if (s[i] !== ":")
316
320
  return null;
317
321
  const next = s[i + 1];
318
322
  if (next === undefined)
319
323
  return null;
320
324
  // `::` cast operator — never a substitution.
321
- if (next === ':')
325
+ if (next === ":")
322
326
  return null;
323
327
  // :{?NAME} — defined-variable test. Emits literal `TRUE` if the named
324
328
  // variable is set, `FALSE` otherwise. Mirrors upstream's
@@ -329,14 +333,14 @@ export const tryConsumeVarSubstitution = (s, i, varLookup) => {
329
333
  // (missing closing `}`, empty NAME, or non-variable_char content) returns
330
334
  // `null` so the caller emits the literal `:` and continues, matching the
331
335
  // upstream flex fallback rule `:\{\?{variable_char}*`.
332
- if (next === '{' && s[i + 2] === '?') {
336
+ if (next === "{" && s[i + 2] === "?") {
333
337
  let j = i + 3;
334
338
  while (j < s.length && isVarNameCont(s[j]))
335
339
  j++;
336
- if (j > i + 3 && s[j] === '}') {
340
+ if (j > i + 3 && s[j] === "}") {
337
341
  const name = s.slice(i + 3, j);
338
342
  const value = varLookup(name);
339
- return { end: j + 1, text: value !== undefined ? 'TRUE' : 'FALSE' };
343
+ return { end: j + 1, text: value !== undefined ? "TRUE" : "FALSE" };
340
344
  }
341
345
  return null;
342
346
  }
@@ -1,7 +1,7 @@
1
- export * from './settings.js';
2
- export * from './variables.js';
3
- export * from './scanner.js';
4
- export * from './printer.js';
5
- export * from './connection.js';
6
- export * from './backslash.js';
7
- export * from './repl.js';
1
+ export * from "./backslash.js";
2
+ export * from "./connection.js";
3
+ export * from "./printer.js";
4
+ export * from "./repl.js";
5
+ export * from "./scanner.js";
6
+ export * from "./settings.js";
7
+ export * from "./variables.js";