neon 3.0.0 → 3.1.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.
- package/README.md +54 -0
- package/dist/_shared/auth_selection.js +76 -79
- package/dist/_shared/credentials.js +166 -187
- package/dist/_shared/env-core/env.js +354 -517
- package/dist/_shared/env-core/reuse-secrets.js +159 -203
- package/dist/_shared/paths.js +129 -126
- package/dist/_shared/profiles.js +192 -242
- package/dist/_shared/secure_file.js +36 -38
- package/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/analytics.js +163 -207
- package/dist/api.js +815 -758
- package/dist/auth.js +121 -141
- package/dist/auth_context.js +39 -53
- package/dist/cli.js +4 -7
- package/dist/commands/api.js +220 -250
- package/dist/commands/api_keys.js +251 -314
- package/dist/commands/auth.js +283 -328
- package/dist/commands/bootstrap.js +372 -437
- package/dist/commands/branches.js +304 -455
- package/dist/commands/bucket.js +374 -514
- package/dist/commands/checkout.js +213 -298
- package/dist/commands/config.js +573 -690
- package/dist/commands/connection_string.js +137 -165
- package/dist/commands/data_api.js +238 -260
- package/dist/commands/databases.js +67 -76
- package/dist/commands/deploy.js +31 -25
- package/dist/commands/dev.js +639 -719
- package/dist/commands/diff.js +156 -200
- package/dist/commands/env.js +243 -303
- package/dist/commands/functions.js +275 -355
- package/dist/commands/index.js +70 -65
- package/dist/commands/init.js +84 -119
- package/dist/commands/inspect.js +55 -55
- package/dist/commands/ip_allow.js +88 -120
- package/dist/commands/link.js +874 -1019
- package/dist/commands/logs.js +291 -0
- package/dist/commands/neon_auth.js +725 -933
- package/dist/commands/operations.js +34 -25
- package/dist/commands/orgs.js +28 -18
- package/dist/commands/profile.js +614 -845
- package/dist/commands/projects.js +313 -373
- package/dist/commands/psql.js +60 -58
- package/dist/commands/roles.js +55 -58
- package/dist/commands/schema_diff.js +87 -131
- package/dist/commands/set_context.js +34 -26
- package/dist/commands/snapshots.js +288 -413
- package/dist/commands/status.js +41 -37
- package/dist/commands/user.js +21 -10
- package/dist/commands/vpc_endpoints.js +85 -113
- package/dist/config.js +7 -6
- package/dist/config_format.js +50 -66
- package/dist/config_template.js +128 -157
- package/dist/context.js +183 -235
- package/dist/current_branch_fast_path.js +40 -49
- package/dist/dev/env.js +313 -394
- package/dist/dev/functions.js +54 -68
- package/dist/dev/inputs.js +46 -58
- package/dist/dev/runtime.js +135 -164
- package/dist/dev/websocket.js +766 -959
- package/dist/env.js +27 -33
- package/dist/env_file.js +118 -132
- package/dist/env_services.js +36 -38
- package/dist/errors.js +57 -68
- package/dist/functions_api.js +45 -43
- package/dist/help.js +189 -140
- package/dist/index.js +182 -257
- package/dist/init/agents.js +137 -118
- package/dist/init/auth.js +58 -68
- package/dist/init/bootstrap.js +325 -396
- package/dist/init/build_config.js +4 -2
- package/dist/init/detect_agent.js +56 -101
- package/dist/init/editors.js +35 -52
- package/dist/init/enrich_output.js +51 -66
- package/dist/init/extension.js +134 -171
- package/dist/init/inspect.js +179 -266
- package/dist/init/interactive.js +510 -622
- package/dist/init/neonctl.js +117 -168
- package/dist/init/orchestrate.js +157 -173
- package/dist/init/phases/auth.js +188 -202
- package/dist/init/phases/cleanup.js +23 -23
- package/dist/init/phases/db.js +251 -277
- package/dist/init/phases/getting_started.js +213 -223
- package/dist/init/phases/mcp.js +174 -224
- package/dist/init/phases/migrations.js +247 -248
- package/dist/init/phases/neon_auth.js +114 -133
- package/dist/init/phases/setup.js +546 -703
- package/dist/init/phases/skills.js +75 -86
- package/dist/init/phases/status.js +72 -67
- package/dist/init/resolve_context.js +102 -99
- package/dist/init/route_command.js +91 -98
- package/dist/init/skills.js +174 -218
- package/dist/init/vsix.js +77 -99
- package/dist/log.js +17 -16
- package/dist/neon_services.js +104 -129
- package/dist/parameters.gen.js +481 -471
- package/dist/pkg.js +17 -19
- package/dist/profile_keys.js +44 -47
- package/dist/psql/cli.js +44 -47
- package/dist/psql/command/cmd_cond.js +231 -406
- package/dist/psql/command/cmd_connect.js +557 -764
- package/dist/psql/command/cmd_copy.js +727 -983
- package/dist/psql/command/cmd_describe.js +1499 -1688
- package/dist/psql/command/cmd_format.js +733 -905
- package/dist/psql/command/cmd_io.js +1293 -2082
- package/dist/psql/command/cmd_lo.js +297 -359
- package/dist/psql/command/cmd_meta.js +727 -878
- package/dist/psql/command/cmd_misc.js +138 -172
- package/dist/psql/command/cmd_pipeline.js +547 -1099
- package/dist/psql/command/cmd_restrict.js +119 -155
- package/dist/psql/command/cmd_show.js +529 -688
- package/dist/psql/command/dispatch.js +261 -325
- package/dist/psql/command/inputQueue.js +35 -33
- package/dist/psql/command/shared.js +49 -63
- package/dist/psql/complete/filenames.js +90 -133
- package/dist/psql/complete/index.js +59 -97
- package/dist/psql/complete/matcher.js +236 -300
- package/dist/psql/complete/psqlVars.js +218 -223
- package/dist/psql/complete/queries.js +159 -177
- package/dist/psql/complete/rules.js +1493 -2299
- package/dist/psql/core/common.js +762 -1180
- package/dist/psql/core/help.js +456 -546
- package/dist/psql/core/mainloop.js +692 -1302
- package/dist/psql/core/prompt.js +391 -408
- package/dist/psql/core/settings.js +429 -644
- package/dist/psql/core/sqlHelp.js +480 -554
- package/dist/psql/core/startup.js +626 -815
- package/dist/psql/core/syncVars.js +67 -110
- package/dist/psql/core/variables.js +156 -278
- package/dist/psql/describe/formatters.js +884 -1285
- package/dist/psql/describe/processNamePattern.js +173 -260
- package/dist/psql/describe/queries.js +1368 -2403
- package/dist/psql/describe/versionGate.js +32 -41
- package/dist/psql/index.js +1414 -1927
- package/dist/psql/io/history.js +232 -271
- package/dist/psql/io/input.js +103 -108
- package/dist/psql/io/lineEditor/buffer.js +238 -319
- package/dist/psql/io/lineEditor/complete.js +135 -213
- package/dist/psql/io/lineEditor/filename.js +139 -148
- package/dist/psql/io/lineEditor/index.js +653 -870
- package/dist/psql/io/lineEditor/keymap.js +544 -702
- package/dist/psql/io/lineEditor/vt100.js +294 -341
- package/dist/psql/io/pgpass.js +158 -187
- package/dist/psql/io/pgservice.js +146 -183
- package/dist/psql/io/psqlrc.js +328 -403
- package/dist/psql/print/aligned.js +1020 -1683
- package/dist/psql/print/asciidoc.js +180 -214
- package/dist/psql/print/crosstab.js +281 -442
- package/dist/psql/print/csv.js +48 -70
- package/dist/psql/print/html.js +195 -226
- package/dist/psql/print/json.js +75 -88
- package/dist/psql/print/latex.js +291 -364
- package/dist/psql/print/pager.js +171 -242
- package/dist/psql/print/troff.js +194 -226
- package/dist/psql/print/unaligned.js +69 -95
- package/dist/psql/print/units.js +167 -169
- package/dist/psql/scanner/slash.js +428 -483
- package/dist/psql/scanner/sql.js +445 -889
- package/dist/psql/scanner/stringutils.js +309 -379
- package/dist/psql/types/index.js +2 -7
- package/dist/psql/types/scanner.js +25 -22
- package/dist/psql/wire/connection.js +2042 -2803
- package/dist/psql/wire/copy.js +84 -100
- package/dist/psql/wire/notify.js +39 -59
- package/dist/psql/wire/pipeline.js +305 -518
- package/dist/psql/wire/protocol.js +349 -417
- package/dist/psql/wire/sasl.js +180 -265
- package/dist/psql/wire/tls.js +400 -561
- package/dist/storage_api.js +115 -129
- package/dist/test_utils/fixtures.js +94 -113
- package/dist/test_utils/oauth_server.js +10 -7
- package/dist/test_utils/project_dir.js +33 -0
- package/dist/utils/ai_gateway_notice.js +131 -162
- package/dist/utils/api_enums.js +21 -28
- package/dist/utils/auth.js +10 -4
- package/dist/utils/branch_notice.js +20 -19
- package/dist/utils/branch_picker.js +83 -89
- package/dist/utils/cli_name.js +15 -12
- package/dist/utils/compute_units.js +20 -27
- package/dist/utils/config_diff.js +127 -158
- package/dist/utils/enrichers.js +95 -148
- package/dist/utils/esbuild.js +130 -189
- package/dist/utils/flags.js +35 -47
- package/dist/utils/formats.js +8 -15
- package/dist/utils/git_diff.js +69 -80
- package/dist/utils/inspect_db.js +101 -143
- package/dist/utils/inspect_queries.js +179 -142
- package/dist/utils/middlewares.js +37 -44
- package/dist/utils/openapi.js +87 -99
- package/dist/utils/package_manager.js +312 -110
- package/dist/utils/point_in_time.js +49 -53
- package/dist/utils/psql.js +89 -106
- package/dist/utils/service_picker.js +55 -58
- package/dist/utils/string.js +5 -5
- package/dist/utils/ui.js +38 -55
- package/dist/utils/write_sync.js +26 -35
- package/dist/utils/zip.js +4 -3
- package/dist/writer.js +67 -87
- package/package.json +7 -5
package/dist/psql/print/pager.js
CHANGED
|
@@ -1,267 +1,196 @@
|
|
|
1
|
-
import { accessSync, constants
|
|
1
|
+
import { accessSync, constants } from "node:fs";
|
|
2
2
|
import { spawn } from "child_process";
|
|
3
3
|
import { basename, delimiter, isAbsolute, join } from "path";
|
|
4
|
+
//#region src/psql/print/pager.ts
|
|
4
5
|
/**
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
* Can `command` be spawned with `shell:false`? A bare name is searched on
|
|
7
|
+
* `$PATH`; a path is checked directly. Used to avoid `spawn(missingBinary,
|
|
8
|
+
* { shell:false })`, which does NOT throw synchronously (our try/catch never
|
|
9
|
+
* fires) but emits an async ENOENT — leaving writes to the dead child's stdin
|
|
10
|
+
* to vanish into a blank terminal (review item #19).
|
|
11
|
+
*/
|
|
11
12
|
const pagerCommandResolvable = (command) => {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
if (command.includes("/") ||
|
|
35
|
-
command.includes("\\") ||
|
|
36
|
-
isAbsolute(command)) {
|
|
37
|
-
return ok(command);
|
|
38
|
-
}
|
|
39
|
-
return (process.env.PATH ?? "")
|
|
40
|
-
.split(delimiter)
|
|
41
|
-
.filter((d) => d.length > 0)
|
|
42
|
-
.some((dir) => ok(join(dir, command)));
|
|
13
|
+
const ok = (p) => {
|
|
14
|
+
try {
|
|
15
|
+
accessSync(p, constants.X_OK);
|
|
16
|
+
return true;
|
|
17
|
+
} catch {
|
|
18
|
+
if (process.platform === "win32") for (const ext of [
|
|
19
|
+
"",
|
|
20
|
+
".exe",
|
|
21
|
+
".cmd",
|
|
22
|
+
".bat"
|
|
23
|
+
]) try {
|
|
24
|
+
accessSync(p + ext, constants.F_OK);
|
|
25
|
+
return true;
|
|
26
|
+
} catch {}
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
if (command.includes("/") || command.includes("\\") || isAbsolute(command)) return ok(command);
|
|
31
|
+
return (process.env.PATH ?? "").split(delimiter).filter((d) => d.length > 0).some((dir) => ok(join(dir, command)));
|
|
43
32
|
};
|
|
44
33
|
/**
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
34
|
+
* Resolve the pager command string. Mirrors upstream:
|
|
35
|
+
* PSQL_PAGER → PAGER → DEFAULT_PAGER (`less` on POSIX, none on Windows).
|
|
36
|
+
*
|
|
37
|
+
* Empty / whitespace-only env values FALL THROUGH to the next candidate. This
|
|
38
|
+
* deliberately diverges from strict upstream (where `PSQL_PAGER=''` would
|
|
39
|
+
* disable the pager outright) because in Node a spawned child cannot easily
|
|
40
|
+
* "unset" an inherited env var — tests have to override it with the empty
|
|
41
|
+
* string. Treating empty values as "unset" matches the conformance spec
|
|
42
|
+
* (`tests/psql-conformance/tap/030_pager.spec.ts`) and lets `PSQL_PAGER=''`
|
|
43
|
+
* fall through to PAGER, which is the user-friendly interpretation.
|
|
44
|
+
*
|
|
45
|
+
* Users who want to disable the pager unconditionally should set
|
|
46
|
+
* `\pset pager off` (preferred) or unset both env vars before launch.
|
|
47
|
+
*/
|
|
59
48
|
const resolvePagerCmd = (opts) => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
// DEFAULT_PAGER: `less` on POSIX; nothing on Windows.
|
|
75
|
-
if (process.platform === "win32")
|
|
76
|
-
return "";
|
|
77
|
-
return "less";
|
|
49
|
+
const env = opts.env ?? process.env;
|
|
50
|
+
const candidates = [
|
|
51
|
+
opts.pagerCmd,
|
|
52
|
+
env.PSQL_PAGER,
|
|
53
|
+
env.PAGER
|
|
54
|
+
];
|
|
55
|
+
for (const c of candidates) {
|
|
56
|
+
if (c === void 0) continue;
|
|
57
|
+
if (/^\s*$/.test(c)) continue;
|
|
58
|
+
return c;
|
|
59
|
+
}
|
|
60
|
+
if (process.platform === "win32") return "";
|
|
61
|
+
return "less";
|
|
78
62
|
};
|
|
79
63
|
const getIsTty = (opts) => {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
// Some test streams won't have isTTY.
|
|
84
|
-
const tty = stream.isTTY;
|
|
85
|
-
return Boolean(tty);
|
|
64
|
+
if (opts.isTty !== void 0) return opts.isTty;
|
|
65
|
+
const tty = (opts.stdout ?? process.stdout).isTTY;
|
|
66
|
+
return Boolean(tty);
|
|
86
67
|
};
|
|
87
68
|
const getTerminalHeight = (opts) => {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const rows = stream.rows;
|
|
92
|
-
// If we can't tell, fall back to 24 (classic VT100 default).
|
|
93
|
-
return typeof rows === "number" && rows > 0 ? rows : 24;
|
|
69
|
+
if (opts.terminalHeight !== void 0) return opts.terminalHeight;
|
|
70
|
+
const rows = (opts.stdout ?? process.stdout).rows;
|
|
71
|
+
return typeof rows === "number" && rows > 0 ? rows : 24;
|
|
94
72
|
};
|
|
95
73
|
/** Standalone helper to determine whether a pager is needed at all. */
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
// pager === 'on'
|
|
105
|
-
if (!getIsTty(opts))
|
|
106
|
-
return false;
|
|
107
|
-
if (opts.lines === undefined)
|
|
108
|
-
return false;
|
|
109
|
-
const threshold = Math.max(opts.pagerMinLines, getTerminalHeight(opts));
|
|
110
|
-
return opts.lines >= threshold;
|
|
74
|
+
const isPagerNeeded = (opts) => {
|
|
75
|
+
if (opts.pager === "off") return false;
|
|
76
|
+
if (resolvePagerCmd(opts) === "") return false;
|
|
77
|
+
if (opts.pager === "always") return true;
|
|
78
|
+
if (!getIsTty(opts)) return false;
|
|
79
|
+
if (opts.lines === void 0) return false;
|
|
80
|
+
const threshold = Math.max(opts.pagerMinLines, getTerminalHeight(opts));
|
|
81
|
+
return opts.lines >= threshold;
|
|
111
82
|
};
|
|
112
83
|
/**
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
// inside `isPagerNeeded`.
|
|
141
|
-
if (opts.pager !== "always" && !isTty)
|
|
142
|
-
return false;
|
|
143
|
-
return isPagerNeeded({
|
|
144
|
-
pager: opts.pager,
|
|
145
|
-
pagerMinLines: opts.pagerMinLines,
|
|
146
|
-
pagerCmd: opts.pagerCmd,
|
|
147
|
-
env: opts.env,
|
|
148
|
-
stdout: opts.output,
|
|
149
|
-
isTty,
|
|
150
|
-
terminalHeight: opts.terminalHeight,
|
|
151
|
-
lines: estimatedLines,
|
|
152
|
-
});
|
|
84
|
+
* Decide whether a result of `rowCount` rows by `colCount` columns should be
|
|
85
|
+
* routed through the pager when written to `output`.
|
|
86
|
+
*
|
|
87
|
+
* NOTE on `pager === 'always'`: the TTY check is INTENTIONALLY skipped in
|
|
88
|
+
* this case. Upstream's `\pset pager always` is a user-explicit "force the
|
|
89
|
+
* pager on" override; honouring it on a pipe matches the integration test
|
|
90
|
+
* harness contract (see `tests/psql-conformance/tap/030_pager.spec.ts`) where
|
|
91
|
+
* the child process has no controlling TTY but the spec still requires the
|
|
92
|
+
* configured PAGER to be invoked. For `pager === 'on'` (auto mode) we keep
|
|
93
|
+
* the TTY guard so non-interactive runs don't spuriously spawn `less`.
|
|
94
|
+
*/
|
|
95
|
+
const shouldPage = (opts) => {
|
|
96
|
+
if (opts.pager === "off") return false;
|
|
97
|
+
if (opts.redirectedOutput) return false;
|
|
98
|
+
const estimatedLines = 3 + Math.max(0, opts.rowCount) + 1;
|
|
99
|
+
const isTty = opts.isTty !== void 0 ? opts.isTty : Boolean(opts.output.isTTY);
|
|
100
|
+
if (opts.pager !== "always" && !isTty) return false;
|
|
101
|
+
return isPagerNeeded({
|
|
102
|
+
pager: opts.pager,
|
|
103
|
+
pagerMinLines: opts.pagerMinLines,
|
|
104
|
+
pagerCmd: opts.pagerCmd,
|
|
105
|
+
env: opts.env,
|
|
106
|
+
stdout: opts.output,
|
|
107
|
+
isTty,
|
|
108
|
+
terminalHeight: opts.terminalHeight,
|
|
109
|
+
lines: estimatedLines
|
|
110
|
+
});
|
|
153
111
|
};
|
|
154
112
|
const SHELL_META = /[\s|;><]/;
|
|
155
113
|
const parsePagerCmd = (cmd) => {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
114
|
+
if (SHELL_META.test(cmd)) return {
|
|
115
|
+
command: cmd,
|
|
116
|
+
args: [],
|
|
117
|
+
shell: true
|
|
118
|
+
};
|
|
119
|
+
return {
|
|
120
|
+
command: cmd,
|
|
121
|
+
args: [],
|
|
122
|
+
shell: false
|
|
123
|
+
};
|
|
162
124
|
};
|
|
163
125
|
const buildPagerEnv = (cmd, baseEnv) => {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const firstToken = cmd.trim().split(/\s+/, 1)[0] ?? "";
|
|
171
|
-
const program = basename(firstToken);
|
|
172
|
-
if (program === "less") {
|
|
173
|
-
env.LESS = "FRX";
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
return env;
|
|
126
|
+
const env = { ...baseEnv };
|
|
127
|
+
if (env.LESS === void 0) {
|
|
128
|
+
const firstToken = cmd.trim().split(/\s+/, 1)[0] ?? "";
|
|
129
|
+
if (basename(firstToken) === "less") env.LESS = "FRX";
|
|
130
|
+
}
|
|
131
|
+
return env;
|
|
177
132
|
};
|
|
178
133
|
const noOpHandle = (out) => ({
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
134
|
+
out,
|
|
135
|
+
spawned: false,
|
|
136
|
+
close: () => Promise.resolve(0)
|
|
182
137
|
});
|
|
183
138
|
/**
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
child.once("exit", (code) => {
|
|
240
|
-
settle(code);
|
|
241
|
-
});
|
|
242
|
-
child.once("error", () => {
|
|
243
|
-
// If the child errored (e.g. ENOENT), surface a non-zero exit code
|
|
244
|
-
// but don't throw — the caller's writes will have hit EPIPE which
|
|
245
|
-
// we already swallow.
|
|
246
|
-
settle(127);
|
|
247
|
-
});
|
|
248
|
-
});
|
|
249
|
-
return {
|
|
250
|
-
out: stdin,
|
|
251
|
-
spawned: true,
|
|
252
|
-
close: () => {
|
|
253
|
-
// End stdin then wait for the pager to drain & exit.
|
|
254
|
-
if (!stdin.writableEnded) {
|
|
255
|
-
try {
|
|
256
|
-
stdin.end();
|
|
257
|
-
}
|
|
258
|
-
catch (err) {
|
|
259
|
-
const e = err;
|
|
260
|
-
if (e.code !== "EPIPE")
|
|
261
|
-
throw err;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
return exitPromise;
|
|
265
|
-
},
|
|
266
|
-
};
|
|
139
|
+
* Returns a PagerHandle. Caller writes data to `out`, then calls `close()`.
|
|
140
|
+
* If no pager spawned (pager='off', not a TTY, or fewer lines than threshold),
|
|
141
|
+
* `out` is `stdout`.
|
|
142
|
+
*/
|
|
143
|
+
const openPager = (opts) => {
|
|
144
|
+
const stdout = opts.stdout ?? process.stdout;
|
|
145
|
+
if (!isPagerNeeded(opts)) return noOpHandle(stdout);
|
|
146
|
+
const cmd = resolvePagerCmd(opts);
|
|
147
|
+
if (cmd === "") return noOpHandle(stdout);
|
|
148
|
+
const { command, shell } = parsePagerCmd(cmd);
|
|
149
|
+
if (!shell && !pagerCommandResolvable(command)) return noOpHandle(stdout);
|
|
150
|
+
const baseEnv = opts.env ?? process.env;
|
|
151
|
+
const childEnv = buildPagerEnv(cmd, baseEnv);
|
|
152
|
+
let child;
|
|
153
|
+
try {
|
|
154
|
+
child = spawn(command, [], {
|
|
155
|
+
stdio: [
|
|
156
|
+
"pipe",
|
|
157
|
+
"inherit",
|
|
158
|
+
"inherit"
|
|
159
|
+
],
|
|
160
|
+
shell,
|
|
161
|
+
env: childEnv
|
|
162
|
+
});
|
|
163
|
+
} catch {
|
|
164
|
+
return noOpHandle(stdout);
|
|
165
|
+
}
|
|
166
|
+
const stdin = child.stdin;
|
|
167
|
+
if (stdin === null) return noOpHandle(stdout);
|
|
168
|
+
stdin.on("error", (err) => {
|
|
169
|
+
if (err.code !== "EPIPE") throw err;
|
|
170
|
+
});
|
|
171
|
+
const exitPromise = new Promise((resolve) => {
|
|
172
|
+
const settle = (code) => {
|
|
173
|
+
resolve(code ?? 0);
|
|
174
|
+
};
|
|
175
|
+
child.once("exit", (code) => {
|
|
176
|
+
settle(code);
|
|
177
|
+
});
|
|
178
|
+
child.once("error", () => {
|
|
179
|
+
settle(127);
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
return {
|
|
183
|
+
out: stdin,
|
|
184
|
+
spawned: true,
|
|
185
|
+
close: () => {
|
|
186
|
+
if (!stdin.writableEnded) try {
|
|
187
|
+
stdin.end();
|
|
188
|
+
} catch (err) {
|
|
189
|
+
if (err.code !== "EPIPE") throw err;
|
|
190
|
+
}
|
|
191
|
+
return exitPromise;
|
|
192
|
+
}
|
|
193
|
+
};
|
|
267
194
|
};
|
|
195
|
+
//#endregion
|
|
196
|
+
export { isPagerNeeded, openPager, shouldPage };
|