Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

read

Package Overview
Dependencies
Maintainers
1
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

read - npm Package Compare versions

Comparing version 0.1.1 to 1.0.0

r.js

17

example/example.js

@@ -5,15 +5,10 @@ var read = require("../lib/read.js")

read({prompt: "Password: ", default: "test-pass", silent: true }, function (er, pass) {
read({prompt: "Enter 4 characters: ", num: 4 }, function (er, four) {
read({prompt: "Password again: ", default: "test-pass", silent: true }, function (er, pass2) {
console.error({user: user,
pass: pass,
verify: pass2,
four:four,
passMatch: (pass === pass2)})
console.error("If the program doesn't end right now,\n"
+"then you may be experiencing this bug:\n"
+"https://github.com/joyent/node/issues/2257")
})
read({prompt: "Password again: ", default: "test-pass", silent: true }, function (er, pass2) {
console.error({user: user,
pass: pass,
verify: pass2,
passMatch: (pass === pass2)})
console.error("the program should exit now")
})
})
})
module.exports = read
var buffer = ""
, tty = require("tty")
, StringDecoder = require("string_decoder").StringDecoder
, stdin
, stdout
var readline = require('readline')
var Mute = require('mute-stream')
function raw (stdin, mode) {
if (stdin.setRawMode && stdin.isTTY) {
stdin.setRawMode(mode)
return
function read (opts, cb) {
if (opts.num) {
throw new Error('read() no longer accepts a char number limit')
}
// old style
try {
tty.setRawMode(mode)
} catch (e) {}
}
var input = opts.input || process.stdin
var output = opts.output || process.stdout
var m = new Mute()
m.pipe(output)
output = m
var def = opts.default || ''
var terminal = !!(opts.terminal || output.isTTY)
var rlOpts = { input: input, output: output, terminal: terminal }
var rl = readline.createInterface(rlOpts)
var prompt = (opts.prompt || '').trim() + ' '
var silent = opts.silent
var editDef = false
var timeout = opts.timeout
function read (opts, cb) {
if (!cb) cb = opts, opts = {}
var p = opts.prompt || ""
, def = opts.default
, silent = opts.silent
, timeout = opts.timeout
, num = opts.num || null
stdin = opts.stdin || process.stdin
stdout = opts.stdout || process.stdout
if (p && def) p += "("+(silent ? "<default hidden>" : def)+") "
// switching into raw mode is a little bit painful.
// avoid if possible.
var r = silent || num ? rawRead : normalRead
if (r === rawRead && !stdin.isTTY) r = normalRead
if (timeout) {
cb = (function (cb) {
var called = false
var t = setTimeout(function () {
raw(false)
stdout.write("\n")
if (def) done(null, def)
else done(new Error("timeout"))
}, timeout)
function done (er, data) {
clearTimeout(t)
if (called) return
// stop reading!
stdin.pause()
called = true
cb(er, data)
}
return done
})(cb)
if (def) {
if (silent) {
prompt += '(<default hidden>) '
} else if (opts.edit) {
editDef = true
} else {
prompt += '(' + def + ') '
}
}
if (p && !stdout.write(p)) {
stdout.on("drain", function D () {
stdout.removeListener("drain", D)
r(def, timeout, silent, num, cb)
})
if (silent) {
output.unmute()
rl.setPrompt(prompt)
rl.prompt()
output.mute()
} else {
process.nextTick(function () {
r(def, timeout, silent, num, cb)
})
rl.setPrompt(prompt)
rl.prompt()
if (editDef) {
rl.line = def
rl.cursor = def.length
rl._refreshLine()
}
}
}
function normalRead (def, timeout, silent, num, cb) {
var val = ""
, decoder = new StringDecoder("utf8")
var called = false
rl.on('line', onLine)
rl.on('error', onError)
if (stdin === process.stdin) {
stdin = process.openStdin()
}
stdin.resume()
stdin.on("error", cb)
stdin.on("data", function D (chunk) {
// get the characters that are completed.
val += buffer + decoder.write(chunk)
buffer = ""
// \r has no place here.
val = val.replace(/\r/g, "")
if (val.indexOf("\n") !== -1) {
// pluck off any delims at the beginning.
if (val !== "\n") {
var i, l
for (i = 0, l = val.length; i < l; i ++) {
if (val.charAt(i) !== "\n") break
}
if (i !== 0) val = val.substr(i)
}
// hack. if we get the number of chars, just pretend there was a delim
if (num > 0 && val.length >= num) {
val = val.substr(0, num) + "\n" + val.substr(num)
}
// buffer whatever might have come *after* the delimter
var delimIndex = val.indexOf("\n")
if (delimIndex !== -1) {
buffer = val.substr(delimIndex)
val = val.substr(0, delimIndex)
} else {
buffer = ""
}
stdin.pause()
stdin.removeListener("data", D)
stdin.removeListener("error", cb)
// read(1) trims
val = val.trim() || def
cb(null, val)
}
rl.on('SIGINT', function () {
rl.close()
onError(new Error('canceled'))
})
}
function rawRead (def, timeout, silent, num, cb) {
var val = ""
, decoder = new StringDecoder
var timer
if (timeout) {
timer = setTimeout(function () {
onError(new Error('timed out'))
}, timeout)
}
if (stdin === process.stdin) {
stdin = process.openStdin()
function done () {
called = true
rl.close()
clearTimeout(timer)
output.mute()
}
raw(stdin, true)
stdin.resume()
stdin.on("error", cb)
stdin.on("data", function D (c) {
// \r is my enemy.
var s = decoder.write(c).replace(/\r/g, "\n")
var i = 0
function onError (er) {
if (called) return
done()
return cb(er)
}
LOOP: while (c = s.charAt(i++)) switch (c) {
case "\u007f": // backspace
val = val.substr(0, val.length - 1)
if (!silent) stdout.write('\b \b')
break
case "\u0004": // EOF
case "\n":
raw(stdin, false)
stdin.removeListener("data", D)
stdin.removeListener("error", cb)
val = val.trim() || def
stdout.write("\n")
stdin.pause()
return cb(null, val)
case "\u0003": case "\0": // ^C or other signal abort
raw(stdin, false)
stdin.removeListener("data", D)
stdin.removeListener("error", cb)
stdin.pause()
return cb(new Error("cancelled"))
default: // just a normal char
val += buffer + c
buffer = ""
if (!silent) stdout.write(c)
// explicitly process a delim if we have enough chars
// and stop the processing.
if (num && val.length >= num) D("\n")
break LOOP
function onLine (line) {
if (called) return
if (silent && terminal) {
output.unmute()
output.write('\r\n')
}
})
done()
var isDefault = !!(editDef && line === def)
if (def && !line) {
isDefault = true
line = def
}
// truncate the \n at the end.
line = line.replace(/\r?\n$/, '')
cb(null, line, isDefault)
}
}
{
"name": "read",
"version": "0.1.1",
"version": "1.0.0",
"main": "lib/read.js",
"dependencies": {},
"dependencies": {
"mute-stream": "0"
},
"devDependencies": {

@@ -10,3 +12,3 @@ "tap": "*"

"engines": {
"node": ">=0.6"
"node": ">=0.8"
},

@@ -13,0 +15,0 @@ "author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",

@@ -0,3 +1,8 @@

## read
For reading user input from stdin.
Similar to the `readline` builtin's `question()` method, but with a
few more features.
## USAGE

@@ -11,3 +16,3 @@

The callback gets called with either the user input, or the default
specified, or an error, in the traditional `callback(error, result)`
specified, or an error, as `callback(error, result, isDefault)`
node style.

@@ -21,26 +26,14 @@

* `silent` Don't echo the output as the user types it.
* `num` Max number of chars to read from terminal.
* `timeout` Number of ms to wait for user input before giving up.
* `default` The default value if the user enters nothing.
* `edit` Allow the user to edit the default value.
* `terminal` Treat the output as a TTY, whether it is or not.
* `stdin` Readable stream to get input data from. (default `process.stdin`)
* `stdout` Writeable stream to write prompts to. (default: `process.stdout`)
If silent is true, or num is set, and the input is a TTY,
then read will set raw mode, and read character by character.
If silent is true, and the input is a TTY, then read will set raw
mode, and read character by character.
At this time, backspace and arrow keys are not supported very well.
It's probably not too hard to add support for this, perhaps using node's
built-in readline module.
## CONTRIBUTING
Patches welcome.
## BUGS
In node 0.6.0 through 0.6.5, you must explicitly call
`process.stdin.destroy()` or `process.exit()` when you know that your
program is done reading, or else it will keep the event loop running
forever.
See: <https://github.com/joyent/node/issues/2257>

@@ -13,2 +13,3 @@ var tap = require('tap')

var output = ''
var write = child.stdin.write.bind(child.stdin)
child.stdout.on('data', function (c) {

@@ -18,9 +19,9 @@ console.error('data %s', c)

if (output.match(/Username: \(test-user\) $/)) {
child.stdin.write('a user\n')
process.nextTick(write.bind(null, 'a user\n'))
} else if (output.match(/Password: \(<default hidden>\) $/)) {
child.stdin.write('a password\n')
} else if (output.match(/characters: $/)) {
child.stdin.write('asdf\n')
process.nextTick(write.bind(null, 'a password\n'))
} else if (output.match(/Password again: \(<default hidden>\) $/)) {
child.stdin.write('a password\n')
process.nextTick(write.bind(null, 'a password\n'))
} else {
console.error('prompts done, output=%j', output)
}

@@ -32,2 +33,3 @@ })

result += c
console.error('result %j', c.toString())
})

@@ -37,4 +39,4 @@

result = JSON.parse(result)
t.same(result, {"user":"a user","pass":"a password","verify":"a password","four":"asdf","passMatch":true})
t.equal(output, 'Username: (test-user) Password: (<default hidden>) Enter 4 characters: Password again: (<default hidden>) ')
t.same(result, {"user":"a user","pass":"a password","verify":"a password","passMatch":true})
t.equal(output, 'Username: (test-user) Password: (<default hidden>) Password again: (<default hidden>) ')
t.end()

@@ -47,10 +49,7 @@ })

read({prompt: "Password: ", default: "test-pass", silent: true }, function (er, pass) {
read({prompt: "Enter 4 characters: ", num: 4 }, function (er, four) {
read({prompt: "Password again: ", default: "test-pass", silent: true }, function (er, pass2) {
console.error(JSON.stringify({user: user,
pass: pass,
verify: pass2,
four:four,
passMatch: (pass === pass2)}))
})
read({prompt: "Password again: ", default: "test-pass", silent: true }, function (er, pass2) {
console.error(JSON.stringify({user: user,
pass: pass,
verify: pass2,
passMatch: (pass === pass2)}))
})

@@ -57,0 +56,0 @@ })

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc