Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allows passing size or custom alphabet via cli as args #334

Merged
merged 2 commits into from Jan 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 11 additions & 2 deletions README.md
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
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
@@ -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
@@ -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
@@ -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 }