neonctl 2.28.0 → 2.29.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 (135) hide show
  1. package/README.md +2 -2
  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 +33 -33
  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
@@ -22,20 +22,20 @@
22
22
  * mirror that exactly, writing to stderr and returning
23
23
  * `{ status: 'error' }`.
24
24
  */
25
- import { scanSlashArgs } from '../scanner/slash.js';
26
- import { writeErr, writeOut, parseBool, parseTriple } from './shared.js';
25
+ import { scanSlashArgs } from "../scanner/slash.js";
26
+ import { parseBool, parseTriple, writeErr, writeOut } from "./shared.js";
27
27
  /** Recognised output-format names accepted by `\pset format`. */
28
28
  const OUTPUT_FORMATS = [
29
- 'aligned',
30
- 'unaligned',
31
- 'wrapped',
32
- 'html',
33
- 'asciidoc',
34
- 'latex',
35
- 'latex-longtable',
36
- 'troff-ms',
37
- 'csv',
38
- 'json',
29
+ "aligned",
30
+ "unaligned",
31
+ "wrapped",
32
+ "html",
33
+ "asciidoc",
34
+ "latex",
35
+ "latex-longtable",
36
+ "troff-ms",
37
+ "csv",
38
+ "json",
39
39
  ];
40
40
  /** Convert OutputFormat to its human-readable display string. */
41
41
  const formatName = (f) => f;
@@ -46,7 +46,7 @@ const formatName = (f) => f;
46
46
  * off → "Expanded display is off."
47
47
  * auto → "Expanded display is used automatically."
48
48
  */
49
- const tripleLabel = (value) => value === 'auto' ? 'used automatically' : value;
49
+ const tripleLabel = (value) => value === "auto" ? "used automatically" : value;
50
50
  /**
51
51
  * `\a` — toggle aligned/unaligned.
52
52
  *
@@ -56,15 +56,15 @@ const tripleLabel = (value) => value === 'auto' ? 'used automatically' : value;
56
56
  * that here, gating the status write on QUIET like the sibling toggles.
57
57
  */
58
58
  export const cmdA = {
59
- name: 'a',
60
- helpKey: 'a',
59
+ name: "a",
60
+ helpKey: "a",
61
61
  run: (ctx) => {
62
62
  const topt = ctx.settings.popt.topt;
63
- topt.format = topt.format === 'aligned' ? 'unaligned' : 'aligned';
63
+ topt.format = topt.format === "aligned" ? "unaligned" : "aligned";
64
64
  if (!ctx.settings.quiet) {
65
65
  writeOut(`Output format is ${formatName(topt.format)}.\n`);
66
66
  }
67
- return Promise.resolve({ status: 'ok' });
67
+ return Promise.resolve({ status: "ok" });
68
68
  },
69
69
  };
70
70
  /**
@@ -75,11 +75,11 @@ export const cmdA = {
75
75
  * `printPsetInfo`.
76
76
  */
77
77
  export const cmdC = {
78
- name: 'C',
79
- helpKey: 'C',
78
+ name: "C",
79
+ helpKey: "C",
80
80
  run: (ctx) => {
81
- const arg = ctx.nextArg('normal');
82
- return Promise.resolve(applyPset(ctx.settings.popt.topt, 'title', arg, ctx.cmdName, ctx.settings.quiet));
81
+ const arg = ctx.nextArg("normal");
82
+ return Promise.resolve(applyPset(ctx.settings.popt.topt, "title", arg, ctx.cmdName, ctx.settings.quiet));
83
83
  },
84
84
  };
85
85
  /**
@@ -87,13 +87,13 @@ export const cmdC = {
87
87
  * print the current value (upstream prints `Field separator is "%s".`).
88
88
  */
89
89
  export const cmdF = {
90
- name: 'f',
91
- helpKey: 'f',
90
+ name: "f",
91
+ helpKey: "f",
92
92
  run: (ctx) => {
93
- const arg = ctx.nextArg('normal');
93
+ const arg = ctx.nextArg("normal");
94
94
  if (arg === null) {
95
95
  writeOut(`Field separator is "${ctx.settings.popt.topt.fieldSep}".\n`);
96
- return Promise.resolve({ status: 'ok' });
96
+ return Promise.resolve({ status: "ok" });
97
97
  }
98
98
  ctx.settings.popt.topt.fieldSep = arg;
99
99
  // Upstream confirms the change (quiet-gated), like the other \pset-style
@@ -101,7 +101,7 @@ export const cmdF = {
101
101
  if (!ctx.settings.quiet) {
102
102
  writeOut(`Field separator is "${arg}".\n`);
103
103
  }
104
- return Promise.resolve({ status: 'ok' });
104
+ return Promise.resolve({ status: "ok" });
105
105
  },
106
106
  };
107
107
  /**
@@ -110,12 +110,12 @@ export const cmdF = {
110
110
  * loosely — we always restore `aligned` to match the documented behaviour).
111
111
  */
112
112
  export const cmdH = {
113
- name: 'H',
114
- helpKey: 'H',
113
+ name: "H",
114
+ helpKey: "H",
115
115
  run: (ctx) => {
116
116
  const topt = ctx.settings.popt.topt;
117
- topt.format = topt.format === 'html' ? 'aligned' : 'html';
118
- return Promise.resolve({ status: 'ok' });
117
+ topt.format = topt.format === "html" ? "aligned" : "html";
118
+ return Promise.resolve({ status: "ok" });
119
119
  },
120
120
  };
121
121
  /**
@@ -129,11 +129,11 @@ export const cmdH = {
129
129
  * `printPsetInfo`, so the status line is suppressed.
130
130
  */
131
131
  export const cmdT = {
132
- name: 't',
133
- helpKey: 't',
132
+ name: "t",
133
+ helpKey: "t",
134
134
  run: (ctx) => {
135
- const arg = ctx.nextArg('normal');
136
- return Promise.resolve(applyPset(ctx.settings.popt.topt, 'tuples_only', arg, ctx.cmdName, ctx.settings.quiet));
135
+ const arg = ctx.nextArg("normal");
136
+ return Promise.resolve(applyPset(ctx.settings.popt.topt, "tuples_only", arg, ctx.cmdName, ctx.settings.quiet));
137
137
  },
138
138
  };
139
139
  /**
@@ -144,32 +144,32 @@ export const cmdT = {
144
144
  * by `printPsetInfo`.
145
145
  */
146
146
  export const cmdTitleAttr = {
147
- name: 'T',
148
- helpKey: 'T',
147
+ name: "T",
148
+ helpKey: "T",
149
149
  run: (ctx) => {
150
- const arg = ctx.nextArg('normal');
151
- return Promise.resolve(applyPset(ctx.settings.popt.topt, 'tableattr', arg, ctx.cmdName, ctx.settings.quiet));
150
+ const arg = ctx.nextArg("normal");
151
+ return Promise.resolve(applyPset(ctx.settings.popt.topt, "tableattr", arg, ctx.cmdName, ctx.settings.quiet));
152
152
  },
153
153
  };
154
154
  /** `\x [on|off|auto|toggle]` — expanded output. No arg → toggle. */
155
155
  export const cmdX = {
156
- name: 'x',
157
- helpKey: 'x',
156
+ name: "x",
157
+ helpKey: "x",
158
158
  run: (ctx) => {
159
- const arg = ctx.nextArg('normal');
159
+ const arg = ctx.nextArg("normal");
160
160
  const topt = ctx.settings.popt.topt;
161
161
  let next;
162
162
  if (arg === null) {
163
- next = topt.expanded === 'on' ? 'off' : 'on';
163
+ next = topt.expanded === "on" ? "off" : "on";
164
164
  }
165
165
  else {
166
166
  const parsed = parseTriple(arg);
167
167
  if (parsed === null) {
168
168
  writeErr(`\\${ctx.cmdName}: unrecognized value "${arg}": Boolean expected\n`);
169
- return Promise.resolve({ status: 'error', errorWritten: true });
169
+ return Promise.resolve({ status: "error", errorWritten: true });
170
170
  }
171
- if (parsed === 'toggle') {
172
- next = topt.expanded === 'on' ? 'off' : 'on';
171
+ if (parsed === "toggle") {
172
+ next = topt.expanded === "on" ? "off" : "on";
173
173
  }
174
174
  else {
175
175
  next = parsed;
@@ -177,7 +177,7 @@ export const cmdX = {
177
177
  }
178
178
  topt.expanded = next;
179
179
  writeOut(`Expanded display is ${tripleLabel(next)}.\n`);
180
- return Promise.resolve({ status: 'ok' });
180
+ return Promise.resolve({ status: "ok" });
181
181
  },
182
182
  };
183
183
  /**
@@ -190,62 +190,62 @@ export const cmdX = {
190
190
  * server reject genuinely unusable ones.
191
191
  */
192
192
  const NORMALISED_ENCODINGS = new Set([
193
- 'sqlascii',
194
- 'eucjp',
195
- 'euccn',
196
- 'euckr',
197
- 'euctw',
198
- 'eucjis2004',
199
- 'utf8',
200
- 'muleinternal',
201
- 'latin1',
202
- 'latin2',
203
- 'latin3',
204
- 'latin4',
205
- 'latin5',
206
- 'latin6',
207
- 'latin7',
208
- 'latin8',
209
- 'latin9',
210
- 'latin10',
211
- 'win1256',
212
- 'win1258',
213
- 'win866',
214
- 'win874',
215
- 'koi8r',
216
- 'win1251',
217
- 'win1252',
218
- 'iso88595',
219
- 'iso88596',
220
- 'iso88597',
221
- 'iso88598',
222
- 'win1250',
223
- 'win1253',
224
- 'win1254',
225
- 'win1255',
226
- 'win1257',
227
- 'koi8u',
228
- 'sjis',
229
- 'big5',
230
- 'gbk',
231
- 'uhc',
232
- 'gb18030',
233
- 'johab',
234
- 'shiftjis2004',
193
+ "sqlascii",
194
+ "eucjp",
195
+ "euccn",
196
+ "euckr",
197
+ "euctw",
198
+ "eucjis2004",
199
+ "utf8",
200
+ "muleinternal",
201
+ "latin1",
202
+ "latin2",
203
+ "latin3",
204
+ "latin4",
205
+ "latin5",
206
+ "latin6",
207
+ "latin7",
208
+ "latin8",
209
+ "latin9",
210
+ "latin10",
211
+ "win1256",
212
+ "win1258",
213
+ "win866",
214
+ "win874",
215
+ "koi8r",
216
+ "win1251",
217
+ "win1252",
218
+ "iso88595",
219
+ "iso88596",
220
+ "iso88597",
221
+ "iso88598",
222
+ "win1250",
223
+ "win1253",
224
+ "win1254",
225
+ "win1255",
226
+ "win1257",
227
+ "koi8u",
228
+ "sjis",
229
+ "big5",
230
+ "gbk",
231
+ "uhc",
232
+ "gb18030",
233
+ "johab",
234
+ "shiftjis2004",
235
235
  // Aliases upstream's encoding_match_list accepts as recognised names.
236
- 'unicode', // → UTF8
237
- 'mskanji', // → SJIS
238
- 'shiftjis', // → SJIS
239
- 'windows949', // → UHC
240
- 'windows950', // → BIG5
241
- 'windows936', // → GBK
242
- 'tcvn', // → WIN1258
243
- 'tcvn5712', // → WIN1258
244
- 'vscii', // → WIN1258
245
- 'alt', // → WIN866
246
- 'win', // → WIN1251
247
- 'koi8', // → KOI8R
248
- 'abc', // → WIN1258
236
+ "unicode", // → UTF8
237
+ "mskanji", // → SJIS
238
+ "shiftjis", // → SJIS
239
+ "windows949", // → UHC
240
+ "windows950", // → BIG5
241
+ "windows936", // → GBK
242
+ "tcvn", // → WIN1258
243
+ "tcvn5712", // → WIN1258
244
+ "vscii", // → WIN1258
245
+ "alt", // → WIN866
246
+ "win", // → WIN1251
247
+ "koi8", // → KOI8R
248
+ "abc", // → WIN1258
249
249
  ]);
250
250
  /**
251
251
  * Mirror upstream `pg_char_to_encoding`'s name normalisation: drop every
@@ -253,7 +253,7 @@ const NORMALISED_ENCODINGS = new Set([
253
253
  * Used to reproduce `\encoding`'s `invalid encoding name` guard without a
254
254
  * server round-trip.
255
255
  */
256
- const isValidEncodingName = (name) => NORMALISED_ENCODINGS.has(name.replace(/[-_]/g, '').toLowerCase());
256
+ const isValidEncodingName = (name) => NORMALISED_ENCODINGS.has(name.replace(/[-_]/g, "").toLowerCase());
257
257
  /**
258
258
  * `\encoding [name]` — show or set the client encoding.
259
259
  *
@@ -266,19 +266,19 @@ const isValidEncodingName = (name) => NORMALISED_ENCODINGS.has(name.replace(/[-_
266
266
  * mirror it into `topt.encoding` so prompts/printer see the new value.
267
267
  */
268
268
  export const cmdEncoding = {
269
- name: 'encoding',
270
- helpKey: 'encoding',
269
+ name: "encoding",
270
+ helpKey: "encoding",
271
271
  run: async (ctx) => {
272
- const arg = ctx.nextArg('normal');
272
+ const arg = ctx.nextArg("normal");
273
273
  if (arg === null) {
274
274
  writeOut(`${ctx.settings.popt.topt.encoding}\n`);
275
- return { status: 'ok' };
275
+ return { status: "ok" };
276
276
  }
277
277
  if (!isValidEncodingName(arg)) {
278
278
  // Upstream `do_encoding` reports the rejected name verbatim and leaves
279
279
  // the current encoding in place.
280
280
  writeErr(`\\${ctx.cmdName}: invalid encoding name "${arg}"\n`);
281
- return { status: 'error', errorWritten: true };
281
+ return { status: "error", errorWritten: true };
282
282
  }
283
283
  const { db } = ctx.settings;
284
284
  // `PgConnection` always implements setClientEncoding; the optional call
@@ -294,11 +294,11 @@ export const cmdEncoding = {
294
294
  // upstream's "leave the encoding as it was on failure" behaviour.
295
295
  const msg = err instanceof Error ? err.message : String(err);
296
296
  writeErr(`\\${ctx.cmdName}: ${msg}\n`);
297
- return { status: 'error', errorWritten: true };
297
+ return { status: "error", errorWritten: true };
298
298
  }
299
299
  }
300
300
  ctx.settings.popt.topt.encoding = arg;
301
- return { status: 'ok' };
301
+ return { status: "ok" };
302
302
  },
303
303
  };
304
304
  /**
@@ -335,10 +335,10 @@ silent = false) => {
335
335
  const writeOutMaybe = silent ? () => undefined : writeOut;
336
336
  const opt = option.toLowerCase();
337
337
  switch (opt) {
338
- case 'format': {
338
+ case "format": {
339
339
  if (value === null) {
340
340
  writeOutMaybe(`Output format is ${formatName(topt.format)}.\n`);
341
- return { status: 'ok' };
341
+ return { status: "ok" };
342
342
  }
343
343
  const v = value.toLowerCase();
344
344
  // Upstream `do_pset` accepts unambiguous prefix matches for the
@@ -352,69 +352,73 @@ silent = false) => {
352
352
  // with `v` (the order in OUTPUT_FORMATS — `latex` before
353
353
  // `latex-longtable` etc. — encodes which canonical name wins
354
354
  // when one is a prefix of another).
355
- const startsWithBoth = 'aligned'.startsWith(v) && 'asciidoc'.startsWith(v);
355
+ const startsWithBoth = "aligned".startsWith(v) && "asciidoc".startsWith(v);
356
356
  if (startsWithBoth) {
357
357
  writeErr(`\\pset: ambiguous abbreviation "${value}" matches both "aligned" and "asciidoc"\n`);
358
- return { status: 'error', errorWritten: true };
358
+ return { status: "error", errorWritten: true };
359
359
  }
360
360
  const match = OUTPUT_FORMATS.find((f) => f.startsWith(v));
361
361
  if (!match) {
362
362
  writeErr(`\\pset: allowed formats are aligned, asciidoc, csv, html, json, latex, latex-longtable, troff-ms, unaligned, wrapped\n`);
363
- return { status: 'error', errorWritten: true };
363
+ return { status: "error", errorWritten: true };
364
364
  }
365
365
  topt.format = match;
366
366
  writeOutMaybe(`Output format is ${formatName(match)}.\n`);
367
- return { status: 'ok' };
367
+ return { status: "ok" };
368
368
  }
369
- case 'border': {
369
+ case "border": {
370
370
  if (value === null) {
371
371
  writeOutMaybe(`Border style is ${topt.border}.\n`);
372
- return { status: 'ok' };
372
+ return { status: "ok" };
373
373
  }
374
374
  const n = parseInt(value, 10);
375
375
  if (!Number.isFinite(n) || n < 0 || n > 3) {
376
376
  writeErr(`\\pset: invalid border "${value}"\n`);
377
- return { status: 'error', errorWritten: true };
377
+ return { status: "error", errorWritten: true };
378
378
  }
379
379
  topt.border = n;
380
380
  writeOutMaybe(`Border style is ${topt.border}.\n`);
381
- return { status: 'ok' };
381
+ return { status: "ok" };
382
382
  }
383
- case 'expanded':
384
- case 'x': {
383
+ case "expanded":
384
+ case "x": {
385
385
  if (value === null) {
386
- topt.expanded = topt.expanded === 'on' ? 'off' : 'on';
386
+ topt.expanded = topt.expanded === "on" ? "off" : "on";
387
387
  }
388
388
  else {
389
389
  const p = parseTriple(value);
390
390
  if (p === null) {
391
391
  writeErr(`\\pset: unrecognized value "${value}" for "expanded": Boolean expected\n`);
392
- return { status: 'error', errorWritten: true };
392
+ return { status: "error", errorWritten: true };
393
393
  }
394
394
  topt.expanded =
395
- p === 'toggle' ? (topt.expanded === 'on' ? 'off' : 'on') : p;
395
+ p === "toggle"
396
+ ? topt.expanded === "on"
397
+ ? "off"
398
+ : "on"
399
+ : p;
396
400
  }
397
401
  writeOutMaybe(`Expanded display is ${tripleLabel(topt.expanded)}.\n`);
398
- return { status: 'ok' };
402
+ return { status: "ok" };
399
403
  }
400
- case 'fieldsep': {
404
+ case "fieldsep": {
401
405
  if (value === null) {
402
406
  writeOutMaybe(`Field separator is "${topt.fieldSep}".\n`);
403
- return { status: 'ok' };
407
+ return { status: "ok" };
404
408
  }
405
409
  topt.fieldSep = value;
406
410
  writeOutMaybe(`Field separator is "${topt.fieldSep}".\n`);
407
- return { status: 'ok' };
411
+ return { status: "ok" };
408
412
  }
409
- case 'fieldsep_zero': {
413
+ case "fieldsep_zero": {
410
414
  // Upstream: any value (or none) forces fieldSep to the NUL byte.
411
415
  // The bulk-view's `fieldsep_zero` line is derived from fieldSep
412
416
  // (on iff fieldSep === '\0').
413
- topt.fieldSep = '\0';
414
- writeOutMaybe('Field separator is zero byte.\n');
415
- return { status: 'ok' };
417
+ topt.fieldSep = "\0";
418
+ writeOutMaybe("Field separator is zero byte.\n");
419
+ return { status: "ok" };
416
420
  }
417
- case 'footer': {
421
+ case "footer": {
418
422
  if (value !== null) {
419
423
  // Upstream `do_pset` returns directly from `ParseVariableBool`
420
424
  // for `footer`, bypassing the `printPsetInfo` call entirely
@@ -423,18 +427,18 @@ silent = false) => {
423
427
  const b = parseBool(value);
424
428
  if (b === null) {
425
429
  writeErr(`\\pset: unrecognized value "${value}" for "footer": Boolean expected\n`);
426
- return { status: 'error', errorWritten: true };
430
+ return { status: "error", errorWritten: true };
427
431
  }
428
432
  topt.defaultFooter = b;
429
- return { status: 'ok' };
433
+ return { status: "ok" };
430
434
  }
431
435
  topt.defaultFooter = !topt.defaultFooter;
432
436
  writeOutMaybe(topt.defaultFooter
433
- ? 'Default footer is on.\n'
434
- : 'Default footer is off.\n');
435
- return { status: 'ok' };
437
+ ? "Default footer is on.\n"
438
+ : "Default footer is off.\n");
439
+ return { status: "ok" };
436
440
  }
437
- case 'recordsep': {
441
+ case "recordsep": {
438
442
  if (value !== null) {
439
443
  topt.recordSep = value;
440
444
  }
@@ -442,21 +446,21 @@ silent = false) => {
442
446
  // path (handled by the dedicated `recordsep_zero` case), the
443
447
  // "<newline>" sentinel for the literal `\n` byte, and the quoted
444
448
  // verbatim form for everything else.
445
- if (topt.recordSep === '\n') {
446
- writeOutMaybe('Record separator is <newline>.\n');
449
+ if (topt.recordSep === "\n") {
450
+ writeOutMaybe("Record separator is <newline>.\n");
447
451
  }
448
452
  else {
449
453
  writeOutMaybe(`Record separator is "${topt.recordSep}".\n`);
450
454
  }
451
- return { status: 'ok' };
455
+ return { status: "ok" };
452
456
  }
453
- case 'recordsep_zero': {
454
- topt.recordSep = '\0';
455
- writeOutMaybe('Record separator is zero byte.\n');
456
- return { status: 'ok' };
457
+ case "recordsep_zero": {
458
+ topt.recordSep = "\0";
459
+ writeOutMaybe("Record separator is zero byte.\n");
460
+ return { status: "ok" };
457
461
  }
458
- case 'tuples_only':
459
- case 't': {
462
+ case "tuples_only":
463
+ case "t": {
460
464
  if (value !== null) {
461
465
  // Upstream `do_pset` returns directly from `ParseVariableBool`
462
466
  // for `tuples_only`, bypassing `printPsetInfo` — so
@@ -465,86 +469,88 @@ silent = false) => {
465
469
  const b = parseBool(value);
466
470
  if (b === null) {
467
471
  writeErr(`\\pset: unrecognized value "${value}": Boolean expected\n`);
468
- return { status: 'error', errorWritten: true };
472
+ return { status: "error", errorWritten: true };
469
473
  }
470
474
  topt.tuplesOnly = b;
471
- return { status: 'ok' };
475
+ return { status: "ok" };
472
476
  }
473
477
  topt.tuplesOnly = !topt.tuplesOnly;
474
- writeOutMaybe(topt.tuplesOnly ? 'Tuples only is on.\n' : 'Tuples only is off.\n');
475
- return { status: 'ok' };
478
+ writeOutMaybe(topt.tuplesOnly
479
+ ? "Tuples only is on.\n"
480
+ : "Tuples only is off.\n");
481
+ return { status: "ok" };
476
482
  }
477
- case 'title': {
483
+ case "title": {
478
484
  topt.title = value;
479
485
  if (value === null) {
480
- writeOutMaybe('Title is unset.\n');
486
+ writeOutMaybe("Title is unset.\n");
481
487
  }
482
488
  else {
483
489
  writeOutMaybe(`Title is "${value}".\n`);
484
490
  }
485
- return { status: 'ok' };
491
+ return { status: "ok" };
486
492
  }
487
- case 'tableattr':
488
- case 't_a': {
493
+ case "tableattr":
494
+ case "t_a": {
489
495
  topt.tableAttr = value;
490
496
  if (value === null) {
491
- writeOutMaybe('Table attributes unset.\n');
497
+ writeOutMaybe("Table attributes unset.\n");
492
498
  }
493
499
  else {
494
500
  writeOutMaybe(`Table attributes are "${value}".\n`);
495
501
  }
496
- return { status: 'ok' };
502
+ return { status: "ok" };
497
503
  }
498
- case 'pager': {
504
+ case "pager": {
499
505
  if (value === null) {
500
- topt.pager = topt.pager === 'off' ? 'on' : 'off';
506
+ topt.pager = topt.pager === "off" ? "on" : "off";
501
507
  }
502
508
  else {
503
509
  const lower = value.toLowerCase();
504
- if (lower === 'always') {
505
- topt.pager = 'always';
510
+ if (lower === "always") {
511
+ topt.pager = "always";
506
512
  }
507
- else if (lower === 'on' || lower === 'off') {
513
+ else if (lower === "on" || lower === "off") {
508
514
  topt.pager = lower;
509
515
  }
510
516
  else {
511
517
  const b = parseBool(value);
512
518
  if (b === null) {
513
519
  writeErr(`\\pset: unrecognized value "${value}" for "pager"\n`);
514
- return { status: 'error', errorWritten: true };
520
+ return { status: "error", errorWritten: true };
515
521
  }
516
- topt.pager = b ? 'on' : 'off';
522
+ topt.pager = b ? "on" : "off";
517
523
  }
518
524
  }
519
- writeOutMaybe(topt.pager === 'always'
520
- ? 'Pager is always used.\n'
521
- : topt.pager === 'on'
522
- ? 'Pager is used for long output.\n'
523
- : 'Pager usage is off.\n');
524
- return { status: 'ok' };
525
+ writeOutMaybe(topt.pager === "always"
526
+ ? "Pager is always used.\n"
527
+ : topt.pager === "on"
528
+ ? "Pager is used for long output.\n"
529
+ : "Pager usage is off.\n");
530
+ return { status: "ok" };
525
531
  }
526
- case 'pager_min_lines': {
532
+ case "pager_min_lines": {
527
533
  if (value !== null) {
528
534
  const n = parseInt(value, 10);
529
535
  if (!Number.isFinite(n) || n < 0) {
530
536
  writeErr(`\\pset: invalid pager_min_lines "${value}"\n`);
531
- return { status: 'error', errorWritten: true };
537
+ return { status: "error", errorWritten: true };
532
538
  }
533
539
  topt.pagerMinLines = n;
534
540
  }
535
541
  // Upstream uses `ngettext` so singular ("line") fires only for
536
542
  // n == 1; 0 and 2+ render as "lines".
537
543
  const lines = topt.pagerMinLines;
538
- const unit = lines === 1 ? 'line' : 'lines';
544
+ const unit = lines === 1 ? "line" : "lines";
539
545
  writeOutMaybe(`Pager won't be used for less than ${lines} ${unit}.\n`);
540
- return { status: 'ok' };
546
+ return { status: "ok" };
541
547
  }
542
- case 'null': {
543
- topt.nullPrint = value ?? '';
548
+ case "null": {
549
+ topt.nullPrint = value ?? "";
544
550
  writeOutMaybe(`Null display is "${topt.nullPrint}".\n`);
545
- return { status: 'ok' };
551
+ return { status: "ok" };
546
552
  }
547
- case 'csv_fieldsep': {
553
+ case "csv_fieldsep": {
548
554
  if (value !== null) {
549
555
  // Upstream `do_pset` splits the validation in two: length-based
550
556
  // ("must be a single one-byte character") fires for empty / multi-
@@ -552,43 +558,44 @@ silent = false) => {
552
558
  // NUL-terminated, so `'\0'` decodes to an empty C string). The
553
559
  // "cannot be a double quote, a newline, or a carriage return"
554
560
  // path is reserved for the three forbidden single-byte values.
555
- if (value.length !== 1 || value === '\0') {
561
+ if (value.length !== 1 || value === "\0") {
556
562
  writeErr(`\\pset: csv_fieldsep must be a single one-byte character\n`);
557
- return { status: 'error', errorWritten: true };
563
+ return { status: "error", errorWritten: true };
558
564
  }
559
- if (value === '"' || value === '\n' || value === '\r') {
565
+ if (value === '"' || value === "\n" || value === "\r") {
560
566
  writeErr(`\\pset: csv_fieldsep cannot be a double quote, a newline, or a carriage return\n`);
561
- return { status: 'error', errorWritten: true };
567
+ return { status: "error", errorWritten: true };
562
568
  }
563
569
  topt.csvFieldSep = value;
564
570
  }
565
571
  // Upstream wording: "Field separator for CSV is "%s".".
566
572
  writeOutMaybe(`Field separator for CSV is "${topt.csvFieldSep}".\n`);
567
- return { status: 'ok' };
573
+ return { status: "ok" };
568
574
  }
569
- case 'numericlocale': {
575
+ case "numericlocale": {
570
576
  if (value !== null) {
571
577
  // Upstream `do_pset` returns directly from `ParseVariableBool`
572
578
  // for `numericlocale`, bypassing `printPsetInfo`. The toggle
573
579
  // path (no value) still prints the new state.
574
580
  const p = parseTriple(value);
575
- if (p === null || p === 'auto') {
581
+ if (p === null || p === "auto") {
576
582
  writeErr(`\\pset: unrecognized value "${value}" for "numericlocale": Boolean expected\n`);
577
- return { status: 'error', errorWritten: true };
583
+ return { status: "error", errorWritten: true };
578
584
  }
579
- topt.numericLocale = p === 'toggle' ? !topt.numericLocale : p === 'on';
580
- return { status: 'ok' };
585
+ topt.numericLocale =
586
+ p === "toggle" ? !topt.numericLocale : p === "on";
587
+ return { status: "ok" };
581
588
  }
582
589
  topt.numericLocale = !topt.numericLocale;
583
590
  writeOutMaybe(topt.numericLocale
584
- ? 'Locale-adjusted numeric output is on.\n'
585
- : 'Locale-adjusted numeric output is off.\n');
586
- return { status: 'ok' };
591
+ ? "Locale-adjusted numeric output is on.\n"
592
+ : "Locale-adjusted numeric output is off.\n");
593
+ return { status: "ok" };
587
594
  }
588
- case 'linestyle': {
595
+ case "linestyle": {
589
596
  if (value === null) {
590
597
  writeOutMaybe(`Line style is ${topt.unicodeBorderLineStyle}.\n`);
591
- return { status: 'ok' };
598
+ return { status: "ok" };
592
599
  }
593
600
  const lower = value.toLowerCase();
594
601
  // Preserve 'old-ascii' verbatim so the bulk-view (`\pset` with no
@@ -596,40 +603,44 @@ silent = false) => {
596
603
  // table. Upstream `do_pset("linestyle", "old-ascii", …)` flips
597
604
  // `popt.topt.line_style = &pg_asciiformat_old`; we carry the same
598
605
  // three-way distinction on `unicodeBorderLineStyle`.
599
- if (lower === 'ascii' || lower === 'old-ascii' || lower === 'unicode') {
606
+ if (lower === "ascii" ||
607
+ lower === "old-ascii" ||
608
+ lower === "unicode") {
600
609
  const ls = lower;
601
610
  topt.unicodeBorderLineStyle = ls;
602
611
  topt.unicodeColumnLineStyle = ls;
603
612
  topt.unicodeHeaderLineStyle = ls;
604
613
  writeOutMaybe(`Line style is ${ls}.\n`);
605
- return { status: 'ok' };
614
+ return { status: "ok" };
606
615
  }
607
616
  writeErr(`\\pset: allowed line styles are ascii, old-ascii, unicode\n`);
608
- return { status: 'error', errorWritten: true };
617
+ return { status: "error", errorWritten: true };
609
618
  }
610
- case 'columns': {
619
+ case "columns": {
611
620
  if (value !== null) {
612
621
  const n = parseInt(value, 10);
613
622
  if (!Number.isFinite(n) || n < 0) {
614
623
  writeErr(`\\pset: invalid columns "${value}"\n`);
615
- return { status: 'error', errorWritten: true };
624
+ return { status: "error", errorWritten: true };
616
625
  }
617
626
  topt.columns = n;
618
627
  }
619
628
  // Upstream `printPsetInfo` reports `0` as the special "unset"
620
629
  // sentinel — see `command.c:5433`.
621
630
  if (topt.columns === 0) {
622
- writeOutMaybe('Target width is unset.\n');
631
+ writeOutMaybe("Target width is unset.\n");
623
632
  }
624
633
  else {
625
634
  writeOutMaybe(`Target width is ${topt.columns}.\n`);
626
635
  }
627
- return { status: 'ok' };
636
+ return { status: "ok" };
628
637
  }
629
- case 'xheader_width': {
638
+ case "xheader_width": {
630
639
  if (value !== null) {
631
640
  const lower = value.toLowerCase();
632
- if (lower === 'full' || lower === 'column' || lower === 'page') {
641
+ if (lower === "full" ||
642
+ lower === "column" ||
643
+ lower === "page") {
633
644
  topt.xheaderWidth = lower;
634
645
  }
635
646
  else {
@@ -638,7 +649,7 @@ silent = false) => {
638
649
  n <= 0 ||
639
650
  !/^[+]?\d+$/.test(value.trim())) {
640
651
  writeErr(`\\pset: allowed xheader_width values are "full" (default), "column", "page", or a number specifying the exact width\n`);
641
- return { status: 'error', errorWritten: true };
652
+ return { status: "error", errorWritten: true };
642
653
  }
643
654
  topt.xheaderWidth = n;
644
655
  }
@@ -646,55 +657,55 @@ silent = false) => {
646
657
  // Upstream `printPsetInfo` quotes the three named widths
647
658
  // ("full" / "column" / "page") but renders the numeric form
648
659
  // unquoted as `Expanded header width is 33.`.
649
- const current = topt.xheaderWidth ?? 'full';
650
- if (typeof current === 'number') {
660
+ const current = topt.xheaderWidth ?? "full";
661
+ if (typeof current === "number") {
651
662
  writeOutMaybe(`Expanded header width is ${current}.\n`);
652
663
  }
653
664
  else {
654
665
  writeOutMaybe(`Expanded header width is "${current}".\n`);
655
666
  }
656
- return { status: 'ok' };
667
+ return { status: "ok" };
657
668
  }
658
- case 'unicode_border_linestyle':
659
- case 'unicode_column_linestyle':
660
- case 'unicode_header_linestyle': {
669
+ case "unicode_border_linestyle":
670
+ case "unicode_column_linestyle":
671
+ case "unicode_header_linestyle": {
661
672
  // Upstream `printPsetInfo` renders these as
662
673
  // `Unicode border line style is "single".` etc. — note the space
663
674
  // between "line" and "style" in the message (the option name
664
675
  // itself is one token, `linestyle`).
665
- const which = opt === 'unicode_border_linestyle'
666
- ? 'border'
667
- : opt === 'unicode_column_linestyle'
668
- ? 'column'
669
- : 'header';
676
+ const which = opt === "unicode_border_linestyle"
677
+ ? "border"
678
+ : opt === "unicode_column_linestyle"
679
+ ? "column"
680
+ : "header";
670
681
  if (value !== null) {
671
682
  const lower = value.toLowerCase();
672
- if (lower !== 'single' && lower !== 'double') {
683
+ if (lower !== "single" && lower !== "double") {
673
684
  writeErr(`\\pset: ${opt} must be single or double\n`);
674
- return { status: 'error', errorWritten: true };
685
+ return { status: "error", errorWritten: true };
675
686
  }
676
687
  const style = lower;
677
- if (opt === 'unicode_border_linestyle') {
688
+ if (opt === "unicode_border_linestyle") {
678
689
  topt.unicodeBorderStyle = style;
679
690
  }
680
- else if (opt === 'unicode_column_linestyle') {
691
+ else if (opt === "unicode_column_linestyle") {
681
692
  topt.unicodeColumnStyle = style;
682
693
  }
683
694
  else {
684
695
  topt.unicodeHeaderStyle = style;
685
696
  }
686
697
  }
687
- const current = opt === 'unicode_border_linestyle'
688
- ? (topt.unicodeBorderStyle ?? 'single')
689
- : opt === 'unicode_column_linestyle'
690
- ? (topt.unicodeColumnStyle ?? 'single')
691
- : (topt.unicodeHeaderStyle ?? 'single');
698
+ const current = opt === "unicode_border_linestyle"
699
+ ? (topt.unicodeBorderStyle ?? "single")
700
+ : opt === "unicode_column_linestyle"
701
+ ? (topt.unicodeColumnStyle ?? "single")
702
+ : (topt.unicodeHeaderStyle ?? "single");
692
703
  writeOutMaybe(`Unicode ${which} line style is "${current}".\n`);
693
- return { status: 'ok' };
704
+ return { status: "ok" };
694
705
  }
695
706
  default: {
696
707
  writeErr(`\\pset: unknown option "${option}"\n`);
697
- return { status: 'error', errorWritten: true };
708
+ return { status: "error", errorWritten: true };
698
709
  }
699
710
  }
700
711
  };
@@ -707,8 +718,8 @@ silent = false) => {
707
718
  const psetQuotedString = (str) => {
708
719
  let out = "'";
709
720
  for (const ch of str) {
710
- if (ch === '\n')
711
- out += '\\n';
721
+ if (ch === "\n")
722
+ out += "\\n";
712
723
  else if (ch === "'")
713
724
  out += "\\'";
714
725
  else
@@ -723,12 +734,12 @@ const psetQuotedString = (str) => {
723
734
  * `topt.pager` as the upstream-style triple ('off'|'on'|'always') for
724
735
  * `applyPset`'s state machine; this is only the bulk-view conversion.
725
736
  */
726
- const pagerNumeric = (pager) => pager === 'off' ? 0 : pager === 'on' ? 1 : 2;
737
+ const pagerNumeric = (pager) => pager === "off" ? 0 : pager === "on" ? 1 : 2;
727
738
  /**
728
739
  * Render `xheader_width` for the bulk view. Enum values print verbatim;
729
740
  * numeric values print as the integer.
730
741
  */
731
- const xheaderWidthDisplay = (w) => (typeof w === 'number' ? String(w) : w);
742
+ const xheaderWidthDisplay = (w) => (typeof w === "number" ? String(w) : w);
732
743
  /**
733
744
  * Print the full current `\pset` state, one option per line, to stdout.
734
745
  * Used when `\pset` is invoked with no arguments. String-valued settings
@@ -744,51 +755,51 @@ const printAllPset = (topt) => {
744
755
  writeOut(`fieldsep ${psetQuotedString(topt.fieldSep)}\n`);
745
756
  // fieldsep_zero / recordsep_zero are derived: upstream emits "on" iff
746
757
  // the corresponding separator is the NUL byte.
747
- writeOut(`fieldsep_zero ${topt.fieldSep === '\0' ? 'on' : 'off'}\n`);
748
- writeOut(`footer ${topt.defaultFooter ? 'on' : 'off'}\n`);
758
+ writeOut(`fieldsep_zero ${topt.fieldSep === "\0" ? "on" : "off"}\n`);
759
+ writeOut(`footer ${topt.defaultFooter ? "on" : "off"}\n`);
749
760
  writeOut(`format ${topt.format}\n`);
750
761
  writeOut(`linestyle ${topt.unicodeBorderLineStyle}\n`);
751
762
  writeOut(`null ${psetQuotedString(topt.nullPrint)}\n`);
752
- writeOut(`numericlocale ${topt.numericLocale ? 'on' : 'off'}\n`);
763
+ writeOut(`numericlocale ${topt.numericLocale ? "on" : "off"}\n`);
753
764
  // pager is emitted numerically (0/1/2) — upstream uses %d in printPsetInfo.
754
765
  writeOut(`pager ${pagerNumeric(topt.pager)}\n`);
755
766
  writeOut(`pager_min_lines ${topt.pagerMinLines}\n`);
756
767
  writeOut(`recordsep ${psetQuotedString(topt.recordSep)}\n`);
757
- writeOut(`recordsep_zero ${topt.recordSep === '\0' ? 'on' : 'off'}\n`);
758
- writeOut(`tableattr ${topt.tableAttr === null ? '' : psetQuotedString(topt.tableAttr)}\n`);
759
- writeOut(`title ${topt.title === null ? '' : psetQuotedString(topt.title)}\n`);
760
- writeOut(`tuples_only ${topt.tuplesOnly ? 'on' : 'off'}\n`);
761
- writeOut(`unicode_border_linestyle ${topt.unicodeBorderStyle ?? 'single'}\n`);
762
- writeOut(`unicode_column_linestyle ${topt.unicodeColumnStyle ?? 'single'}\n`);
763
- writeOut(`unicode_header_linestyle ${topt.unicodeHeaderStyle ?? 'single'}\n`);
764
- writeOut(`xheader_width ${xheaderWidthDisplay(topt.xheaderWidth ?? 'full')}\n`);
768
+ writeOut(`recordsep_zero ${topt.recordSep === "\0" ? "on" : "off"}\n`);
769
+ writeOut(`tableattr ${topt.tableAttr === null ? "" : psetQuotedString(topt.tableAttr)}\n`);
770
+ writeOut(`title ${topt.title === null ? "" : psetQuotedString(topt.title)}\n`);
771
+ writeOut(`tuples_only ${topt.tuplesOnly ? "on" : "off"}\n`);
772
+ writeOut(`unicode_border_linestyle ${topt.unicodeBorderStyle ?? "single"}\n`);
773
+ writeOut(`unicode_column_linestyle ${topt.unicodeColumnStyle ?? "single"}\n`);
774
+ writeOut(`unicode_header_linestyle ${topt.unicodeHeaderStyle ?? "single"}\n`);
775
+ writeOut(`xheader_width ${xheaderWidthDisplay(topt.xheaderWidth ?? "full")}\n`);
765
776
  };
766
777
  const lexRawArgs = (tail) => {
767
778
  const out = [];
768
779
  let i = 0;
769
- const isSpace = (c) => c === ' ' ||
770
- c === '\t' ||
771
- c === '\n' ||
772
- c === '\r' ||
773
- c === '\f' ||
774
- c === '\v';
780
+ const isSpace = (c) => c === " " ||
781
+ c === "\t" ||
782
+ c === "\n" ||
783
+ c === "\r" ||
784
+ c === "\f" ||
785
+ c === "\v";
775
786
  while (i < tail.length) {
776
787
  while (i < tail.length && isSpace(tail[i]))
777
788
  i++;
778
789
  if (i >= tail.length)
779
790
  break;
780
- if (tail[i] === '\\')
791
+ if (tail[i] === "\\")
781
792
  break;
782
- let arg = '';
783
- while (i < tail.length && !isSpace(tail[i]) && tail[i] !== '\\') {
793
+ let arg = "";
794
+ while (i < tail.length && !isSpace(tail[i]) && tail[i] !== "\\") {
784
795
  const c = tail[i];
785
796
  if (c === "'") {
786
797
  // Single-quoted: keep delimiters in the warning text so the user
787
798
  // sees the literal token.
788
799
  let j = i + 1;
789
- let inner = '';
800
+ let inner = "";
790
801
  while (j < tail.length && tail[j] !== "'") {
791
- if (tail[j] === '\\' && j + 1 < tail.length) {
802
+ if (tail[j] === "\\" && j + 1 < tail.length) {
792
803
  inner += tail[j] + tail[j + 1];
793
804
  j += 2;
794
805
  continue;
@@ -802,7 +813,7 @@ const lexRawArgs = (tail) => {
802
813
  }
803
814
  if (c === '"') {
804
815
  let j = i + 1;
805
- let inner = '';
816
+ let inner = "";
806
817
  while (j < tail.length && tail[j] !== '"') {
807
818
  inner += tail[j];
808
819
  j++;
@@ -811,11 +822,11 @@ const lexRawArgs = (tail) => {
811
822
  i = j < tail.length ? j + 1 : j;
812
823
  continue;
813
824
  }
814
- if (c === '`') {
825
+ if (c === "`") {
815
826
  // Drop the backtick delimiters; don't run the command (OT_NO_EVAL).
816
827
  let j = i + 1;
817
- let inner = '';
818
- while (j < tail.length && tail[j] !== '`') {
828
+ let inner = "";
829
+ while (j < tail.length && tail[j] !== "`") {
819
830
  inner += tail[j];
820
831
  j++;
821
832
  }
@@ -853,8 +864,8 @@ const lexRawArgs = (tail) => {
853
864
  * collapses to `cmd` without running.
854
865
  */
855
866
  export const cmdPset = {
856
- name: 'pset',
857
- helpKey: 'pset',
867
+ name: "pset",
868
+ helpKey: "pset",
858
869
  run: (ctx) => {
859
870
  // Upstream `exec_command_pset` calls `psql_scan_slash_option` twice
860
871
  // (with `OT_NORMAL`, `evaluate=true`) for option + value, then loops
@@ -878,19 +889,21 @@ export const cmdPset = {
878
889
  const rawEntries = lexRawArgs(ctx.rawArgs);
879
890
  if (rawEntries.length === 0) {
880
891
  printAllPset(ctx.settings.popt.topt);
881
- return Promise.resolve({ status: 'ok' });
892
+ return Promise.resolve({ status: "ok" });
882
893
  }
883
894
  // Slice rawArgs up to the end of arg #2 (or arg #1 if only one was
884
895
  // provided) and feed THAT to the eval-mode scanner. Anything past
885
896
  // that boundary lives in the no-eval extras zone.
886
- const headEndIdx = rawEntries.length >= 2 ? rawEntries[1].endIdx : rawEntries[0].endIdx;
897
+ const headEndIdx = rawEntries.length >= 2
898
+ ? rawEntries[1].endIdx
899
+ : rawEntries[0].endIdx;
887
900
  const headSlice = ctx.rawArgs.slice(0, headEndIdx);
888
901
  const varLookup = (name) => ctx.settings.vars.get(name);
889
- const headArgs = scanSlashArgs(headSlice, 'normal', varLookup);
902
+ const headArgs = scanSlashArgs(headSlice, "normal", varLookup);
890
903
  const option = headArgs[0] ?? null;
891
904
  if (option === null) {
892
905
  printAllPset(ctx.settings.popt.topt);
893
- return Promise.resolve({ status: 'ok' });
906
+ return Promise.resolve({ status: "ok" });
894
907
  }
895
908
  const value = headArgs[1] ?? null;
896
909
  // Under `--quiet` / `\set QUIET on`, upstream `exec_command_pset`