npq 3.11.5 → 3.12.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/bin/npq-hero.js +11 -1
- package/bin/npq.js +11 -1
- package/lib/cli.js +4 -1
- package/lib/helpers/cliPrompt.js +109 -21
- package/package.json +2 -1
package/bin/npq-hero.js
CHANGED
|
@@ -100,8 +100,18 @@ marshall
|
|
|
100
100
|
}
|
|
101
101
|
})
|
|
102
102
|
.catch((error) => {
|
|
103
|
+
// Ensure errorCode is always a number
|
|
104
|
+
let errorCode = -1
|
|
105
|
+
if (typeof error.code === 'number') {
|
|
106
|
+
errorCode = error.code
|
|
107
|
+
} else if (error.code === 'ABORT_ERR') {
|
|
108
|
+
errorCode = 1
|
|
109
|
+
} else if (error.code === 'USER_ABORT') {
|
|
110
|
+
errorCode = error.exitCode || 1
|
|
111
|
+
}
|
|
112
|
+
|
|
103
113
|
CliParser.exit({
|
|
104
|
-
errorCode
|
|
114
|
+
errorCode,
|
|
105
115
|
message: error.message || 'An error occurred',
|
|
106
116
|
spinner
|
|
107
117
|
})
|
package/bin/npq.js
CHANGED
|
@@ -126,8 +126,18 @@ Promise.resolve()
|
|
|
126
126
|
}
|
|
127
127
|
})
|
|
128
128
|
.catch((error) => {
|
|
129
|
+
// Ensure errorCode is always a number
|
|
130
|
+
let errorCode = -1
|
|
131
|
+
if (typeof error.code === 'number') {
|
|
132
|
+
errorCode = error.code
|
|
133
|
+
} else if (error.code === 'ABORT_ERR') {
|
|
134
|
+
errorCode = 1
|
|
135
|
+
} else if (error.code === 'USER_ABORT') {
|
|
136
|
+
errorCode = error.exitCode || 1
|
|
137
|
+
}
|
|
138
|
+
|
|
129
139
|
CliParser.exit({
|
|
130
|
-
errorCode
|
|
140
|
+
errorCode,
|
|
131
141
|
message: error.message || 'An error occurred',
|
|
132
142
|
spinner
|
|
133
143
|
})
|
package/lib/cli.js
CHANGED
|
@@ -11,10 +11,13 @@ class CliParser {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
if (message) {
|
|
14
|
+
console.error('\n')
|
|
14
15
|
console.error(message)
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
// Ensure errorCode is always a number
|
|
19
|
+
const exitCode = typeof errorCode === 'number' ? errorCode : -1
|
|
20
|
+
process.exit(exitCode)
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
static _extractPackagesFromPositionals(positionals, earlyExitNoInstall = false) {
|
package/lib/helpers/cliPrompt.js
CHANGED
|
@@ -54,41 +54,129 @@ async function prompt(options = {}) {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
return { [name]: result }
|
|
57
|
+
} catch (error) {
|
|
58
|
+
// Handle Ctrl+C gracefully - user cancelled the operation
|
|
59
|
+
if (error.code === 'ABORT_ERR') {
|
|
60
|
+
// Throw a specific error that can be caught and handled by the caller
|
|
61
|
+
const abortError = new Error('Operation aborted by user')
|
|
62
|
+
abortError.code = 'USER_ABORT'
|
|
63
|
+
abortError.exitCode = 1
|
|
64
|
+
throw abortError
|
|
65
|
+
}
|
|
66
|
+
throw error
|
|
57
67
|
} finally {
|
|
58
68
|
rl.close()
|
|
59
69
|
}
|
|
60
70
|
}
|
|
61
71
|
|
|
62
72
|
async function autoContinue({ name, message, timeInSeconds = 5 } = {}) {
|
|
63
|
-
|
|
64
|
-
|
|
73
|
+
let aborted = false
|
|
74
|
+
let userProceeded = false
|
|
75
|
+
|
|
76
|
+
// Setup stdin to capture keypresses during countdown
|
|
77
|
+
if (process.stdin.isTTY) {
|
|
78
|
+
process.stdin.setRawMode(true)
|
|
79
|
+
process.stdin.resume()
|
|
80
|
+
|
|
81
|
+
// Handle keypresses during countdown
|
|
82
|
+
const onKeypress = (chunk) => {
|
|
83
|
+
// Check for Ctrl+C (ASCII 3)
|
|
84
|
+
if (chunk && chunk.length === 1 && chunk[0] === 3) {
|
|
85
|
+
aborted = true
|
|
86
|
+
}
|
|
87
|
+
// Check for 'y' or 'Y' (ASCII 121 or 89)
|
|
88
|
+
else if (chunk && chunk.length === 1 && (chunk[0] === 121 || chunk[0] === 89)) {
|
|
89
|
+
userProceeded = true
|
|
90
|
+
}
|
|
91
|
+
// Ignore all other keypresses during countdown
|
|
92
|
+
}
|
|
65
93
|
|
|
66
|
-
|
|
67
|
-
for (let i = timeInSeconds - 1; i > 0; i--) {
|
|
68
|
-
await setTimeout(1000)
|
|
94
|
+
process.stdin.on('data', onKeypress)
|
|
69
95
|
|
|
70
|
-
//
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
96
|
+
// Cleanup function
|
|
97
|
+
const cleanup = () => {
|
|
98
|
+
process.stdin.removeListener('data', onKeypress)
|
|
99
|
+
if (process.stdin.isTTY) {
|
|
100
|
+
process.stdin.setRawMode(false)
|
|
101
|
+
process.stdin.pause()
|
|
102
|
+
}
|
|
103
|
+
}
|
|
74
104
|
|
|
75
|
-
|
|
76
|
-
|
|
105
|
+
try {
|
|
106
|
+
// Show countdown message with instruction in parentheses
|
|
107
|
+
process.stdout.write(`${message}${timeInSeconds} (press 'y' to proceed)`)
|
|
77
108
|
|
|
78
|
-
|
|
79
|
-
const padding = ' '.repeat(Math.max(0, prevLength - currentLength))
|
|
80
|
-
const moveBack = '\b'.repeat(Math.max(0, prevLength - currentLength))
|
|
109
|
+
let currentNumber = timeInSeconds
|
|
81
110
|
|
|
82
|
-
|
|
83
|
-
|
|
111
|
+
// Count down from timeInSeconds-1 to 1
|
|
112
|
+
for (let i = timeInSeconds - 1; i > 0 && !aborted && !userProceeded; i--) {
|
|
113
|
+
await setTimeout(1000)
|
|
114
|
+
|
|
115
|
+
if (aborted || userProceeded) break
|
|
116
|
+
|
|
117
|
+
// Update the countdown number using backspace
|
|
118
|
+
// We need to backspace over both the number AND the instruction text
|
|
119
|
+
const instructionText = " (press 'y' to proceed)"
|
|
120
|
+
const totalTextLength = currentNumber.toString().length + instructionText.length
|
|
121
|
+
|
|
122
|
+
// Backspace over everything, write new number and instruction
|
|
123
|
+
const backspaces = '\b'.repeat(totalTextLength)
|
|
124
|
+
process.stdout.write(`${backspaces}${i}${instructionText}`)
|
|
125
|
+
|
|
126
|
+
currentNumber = i
|
|
127
|
+
}
|
|
84
128
|
|
|
85
|
-
|
|
86
|
-
|
|
129
|
+
if (!aborted && !userProceeded) {
|
|
130
|
+
// Wait for the final second
|
|
131
|
+
await setTimeout(1000)
|
|
132
|
+
}
|
|
87
133
|
|
|
88
|
-
|
|
89
|
-
|
|
134
|
+
// Move to a clean new line for any follow-up output
|
|
135
|
+
if (!aborted) {
|
|
136
|
+
console.log('') // Just move to next line
|
|
137
|
+
}
|
|
90
138
|
|
|
91
|
-
|
|
139
|
+
cleanup()
|
|
140
|
+
|
|
141
|
+
if (aborted) {
|
|
142
|
+
const abortError = new Error('Operation aborted by user')
|
|
143
|
+
abortError.code = 'USER_ABORT'
|
|
144
|
+
abortError.exitCode = 1
|
|
145
|
+
throw abortError
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return { [name]: true }
|
|
149
|
+
} catch (error) {
|
|
150
|
+
cleanup()
|
|
151
|
+
throw error
|
|
152
|
+
}
|
|
153
|
+
} else {
|
|
154
|
+
// Fallback for non-TTY environments (tests, etc.)
|
|
155
|
+
// Show countdown message with instruction
|
|
156
|
+
process.stdout.write(`${message}${timeInSeconds} (press 'y' to proceed)`)
|
|
157
|
+
|
|
158
|
+
// Count down from timeInSeconds-1 to 1
|
|
159
|
+
for (let i = timeInSeconds - 1; i > 0; i--) {
|
|
160
|
+
await setTimeout(1000)
|
|
161
|
+
|
|
162
|
+
// Update similar to TTY version - backspace over number and instruction
|
|
163
|
+
const instructionText = " (press 'y' to proceed)"
|
|
164
|
+
const prevNumber = i + 1
|
|
165
|
+
const totalTextLength = prevNumber.toString().length + instructionText.length
|
|
166
|
+
|
|
167
|
+
// Backspace over everything, write new number and instruction
|
|
168
|
+
const backspaces = '\b'.repeat(totalTextLength)
|
|
169
|
+
process.stdout.write(`${backspaces}${i}${instructionText}`)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Wait for the final second
|
|
173
|
+
await setTimeout(1000)
|
|
174
|
+
|
|
175
|
+
// Move to next line after countdown completes
|
|
176
|
+
console.log('')
|
|
177
|
+
|
|
178
|
+
return { [name]: true }
|
|
179
|
+
}
|
|
92
180
|
}
|
|
93
181
|
|
|
94
182
|
module.exports = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "npq",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.12.0",
|
|
4
4
|
"description": "marshall your npm/npm package installs with high quality and class 🎖",
|
|
5
5
|
"bin": {
|
|
6
6
|
"npq": "./bin/npq.js",
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"fastest-levenshtein": "^1.0.16",
|
|
47
|
+
"lodash": "^4.17.21",
|
|
47
48
|
"npm-package-arg": "^13.0.0",
|
|
48
49
|
"pacote": "^21.0.0",
|
|
49
50
|
"semver": "^7.7.2"
|