Skip to content

Commit

Permalink
Allows passing size or custom alphabet via cli as args (#334)
Browse files Browse the repository at this point in the history
* Allows passing size or custom alphabet via cli as args

* Increase test coverage, make work with Node 12
  • Loading branch information
vitalybaev authored Jan 16, 2022
1 parent 246d5f8 commit 32b9bda
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 10 deletions.
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -468,10 +468,19 @@ npx: installed 1 in 0.63s
LZfXLFzPPR4NNrgjlWDxn
```

If you want to change alphabet or ID size, you should use [`nanoid-cli`].
Size of generated ID can be specified with `--size` (or `-s`) option:

[`nanoid-cli`]: https://github.com/twhitbeck/nanoid-cli
```sh
$ npx nanoid --size 10
L3til0JS4z
```

Custom alphabet can be specified with `--alphabet` (or `-a`) option (note that in this case `--size` is required):

```sh
$ npx nanoid --alphabet abc --size 15
bccbcabaabaccab
```

### Other Programming Languages

Expand Down
13 changes: 11 additions & 2 deletions README.ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -456,10 +456,19 @@ npx: installed 1 in 0.63s
LZfXLFzPPR4NNrgjlWDxn
```

Для смены алфавита или длины ID есть отдельный проект [`nanoid-cli`].
Длину генерируемых ID можно передать в аргументе `--size` (или `-s`):

[`nanoid-cli`]: https://github.com/twhitbeck/nanoid-cli
```sh
$ npx nanoid --size 10
L3til0JS4z
```

Изменить алфавит можно при помощи аргумента `--alphabet` (ли `-a`) (обратите внимание, что в этом случае `--size` обязателен):

```sh
$ npx nanoid --alphabet abc --size 15
bccbcabaabaccab
```

### Другие языки программирования

Expand Down
45 changes: 43 additions & 2 deletions bin/nanoid.cjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,46 @@
#!/usr/bin/env node

let { nanoid } = require('..')
let { nanoid, customAlphabet } = require('..')
let { parseArgs } = require('./utils')

process.stdout.write(nanoid() + '\n')
let parsedArgs = parseArgs(process.argv)

if (parsedArgs.help) {
process.stdout.write(`
Usage
$ nanoid [options]
Options
-s, --size Generated ID size
-a, --alphabet Alphabet to use
-h, --help Show this help
Examples
$ nano --s=15
S9sBF77U6sDB8Yg
$ nano --size=10 --alphabet=abc
bcabababca
`)
process.exit()
}

let alphabet = parsedArgs.alphabet || parsedArgs.a
let size = parsedArgs.size || parsedArgs.s ? Number(parsedArgs.size || parsedArgs.s) : undefined

if (typeof size !== 'undefined' && (Number.isNaN(size) || size <= 0)) {
process.stderr.write('Size must be positive integer\n')
process.exit(1)
}

if (alphabet) {
if (typeof size === 'undefined') {
process.stderr.write('You must also specify size option, when using custom alphabet\n')
process.exit(1)
}
process.stdout.write(customAlphabet(alphabet, size)())
} else {
process.stdout.write(nanoid(size))
}

process.stdout.write('\n')
67 changes: 63 additions & 4 deletions bin/nanoid.test.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,74 @@
let { test } = require('uvu')
let { is, match } = require('uvu/assert')
let { suite } = require('uvu')
let { is, match, equal } = require('uvu/assert')
let { promisify } = require('util')
let { join } = require('path')
let child = require('child_process')

let { parseArgs } = require('./utils')

let exec = promisify(child.exec)

test('prints unique ID', async () => {
const nanoIdSuit = suite('nanoid')

nanoIdSuit('prints unique ID', async () => {
let { stdout, stderr } = await exec('node ' + join(__dirname, 'nanoid.cjs'))
is(stderr, '')
match(stdout, /^[\w-]{21}\n$/)
})

test.run()
nanoIdSuit('uses size', async () => {
let { stdout, stderr } = await exec('node ' + join(__dirname, 'nanoid.cjs') + ' --size=10')
is(stderr, '')
match(stdout, /^[\w-]{10}\n$/)
})

nanoIdSuit('uses alphabet', async () => {
let { stdout, stderr } = await exec('node ' + join(__dirname, 'nanoid.cjs') + ' --alphabet=abc --size=15')
is(stderr, '')
match(stdout, /^[abc]{15}\n$/)
})

nanoIdSuit('show an error if size is not a number', async () => {
try {
await exec('node ' + join(__dirname, 'nanoid.cjs') + ' --s abc')
} catch (e) {
match(e, /Size must be positive integer/)
}
})

nanoIdSuit('shows an error if size is not provided when using custom alphabet', async () => {
try {
await exec('node ' + join(__dirname, 'nanoid.cjs') + ' --alphabet abc')
} catch (e) {
match(e, /You must also specify size option, when using custom alphabet/)
}
})

nanoIdSuit('requires error if size is a negative number', async () => {
try {
await exec('node ' + join(__dirname, 'nanoid.cjs') + ' --size "-1"')
} catch (e) {
match(e, /Size must be positive integer/)
}
})

nanoIdSuit('displays help', async () => {
let { stdout, stderr } = await exec('node ' + join(__dirname, 'nanoid.cjs') + ' --help')
is(stderr, '')
match(stdout, /Usage/)
match(stdout, /\$ nanoid \[options]/)
})

nanoIdSuit.run()

const parseArgsSuite = suite('parseArgs')

parseArgsSuite('parses args', () => {
equal(parseArgs(['node', 'nanoid.cjs', '--help']), { help: true })
equal(parseArgs(['node', 'nanoid.cjs', '--help', '--size=30']), { help: true, size: '30' })
equal(parseArgs(['node', 'nanoid.cjs', '--help', '-s', '30']), { help: true, s: '30' })
equal(parseArgs(['node', 'nanoid.cjs', '--help', '-size', '30']), { help: true, size: '30' })
equal(parseArgs(['node', 'nanoid.cjs', '--help', '-size', '30', '-alphabet', 'abc']), { help: true, size: '30', alphabet: 'abc' })
})

parseArgsSuite.run()
44 changes: 44 additions & 0 deletions bin/utils/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
let cleanArgName = (arg) => arg.startsWith('--') ? arg.slice(2) : arg.slice(1)

let parseArgs = (argv) => {
argv.splice(0, 2)

let parsedArgs = {}

let currentArg = null
argv.forEach((arg) => {
if (arg.includes('=')) {
if (currentArg) {
parsedArgs[currentArg] = true
currentArg = null
}
let argSplit = arg.split('=')
parsedArgs[cleanArgName(argSplit[0])] = argSplit[1]

return
}

if (arg.startsWith('-') || arg.startsWith('--')) {
if (currentArg) {
parsedArgs[currentArg] = true
currentArg = null
}

currentArg = cleanArgName(arg)
return
}

if (currentArg) {
parsedArgs[currentArg] = arg
currentArg = null
}
})

if (currentArg) {
parsedArgs[currentArg] = true
}

return parsedArgs
}

module.exports = { parseArgs }

0 comments on commit 32b9bda

Please sign in to comment.