diff --git a/README.md b/README.md index 814839bb..f5b81a22 100644 --- a/README.md +++ b/README.md @@ -475,7 +475,8 @@ $ npx nanoid --size 10 L3til0JS4z ``` -Custom alphabet can be specified with `--alphabet` (or `-a`) option (note that in this case `--size` is required): +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 diff --git a/README.ru.md b/README.ru.md index 75e1ecf4..12c85a9e 100644 --- a/README.ru.md +++ b/README.ru.md @@ -463,7 +463,8 @@ $ npx nanoid --size 10 L3til0JS4z ``` -Изменить алфавит можно при помощи аргумента `--alphabet` (ли `-a`) (обратите внимание, что в этом случае `--size` обязателен): +Изменить алфавит можно при помощи аргумента `--alphabet` (ли `-a`) +(в этом случае `--size` обязателен): ```sh $ npx nanoid --alphabet abc --size 15 diff --git a/bin/nanoid.cjs b/bin/nanoid.cjs index 16ab4934..535a714b 100755 --- a/bin/nanoid.cjs +++ b/bin/nanoid.cjs @@ -1,46 +1,58 @@ #!/usr/bin/env node let { nanoid, customAlphabet } = require('..') -let { parseArgs } = require('./utils') -let parsedArgs = parseArgs(process.argv) +function print(msg) { + process.stdout.write(msg + '\n') +} + +function error(msg) { + process.stderr.write(msg + '\n') + process.exit(1) +} -if (parsedArgs.help) { - process.stdout.write(` - Usage - $ nanoid [options] +if (process.argv.includes('--help') || process.argv.includes('-h')) { + print(` + Usage + $ nanoid [options] - Options - -s, --size Generated ID size - -a, --alphabet Alphabet to use - -h, --help Show this help + Options + -s, --size Generated ID size + -a, --alphabet Alphabet to use + -h, --help Show this help - Examples - $ nano --s=15 - S9sBF77U6sDB8Yg + Examples + $ nano --s 15 + S9sBF77U6sDB8Yg - $ nano --size=10 --alphabet=abc - bcabababca -`) + $ 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) +let alphabet, size +for (let i = 2; i < process.argv.length; i++) { + let arg = process.argv[i] + if (arg === '--size' || arg === '-s') { + size = Number(process.argv[i + 1]) + i += 1 + if (Number.isNaN(size) || size <= 0) { + error('Size must be positive integer') + } + } else if (arg === '--alphabet' || arg === '-a') { + alphabet = process.argv[i + 1] + i += 1 + } else { + error('Unknown argument ' + arg) + } } if (alphabet) { if (typeof size === 'undefined') { - process.stderr.write('You must also specify size option, when using custom alphabet\n') - process.exit(1) + error('You must also specify size option, when using custom alphabet') } - process.stdout.write(customAlphabet(alphabet, size)()) + let customNanoid = customAlphabet(alphabet, size) + print(customNanoid()) } else { - process.stdout.write(nanoid(size)) + print(nanoid(size)) } - -process.stdout.write('\n') diff --git a/bin/nanoid.test.js b/bin/nanoid.test.js deleted file mode 100644 index 005af89b..00000000 --- a/bin/nanoid.test.js +++ /dev/null @@ -1,74 +0,0 @@ -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) - -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$/) -}) - -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() diff --git a/bin/utils/index.js b/bin/utils/index.js deleted file mode 100644 index 914cdad2..00000000 --- a/bin/utils/index.js +++ /dev/null @@ -1,44 +0,0 @@ -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 } diff --git a/test/bin.test.js b/test/bin.test.js new file mode 100644 index 00000000..c1dc1a19 --- /dev/null +++ b/test/bin.test.js @@ -0,0 +1,70 @@ +let { is, match } = require('uvu/assert') +let { promisify } = require('util') +let { test } = require('uvu') +let { join } = require('path') +let child = require('child_process') + +let exec = promisify(child.exec) + +const BIN = join(__dirname, '..', 'bin', 'nanoid.cjs') + +test('prints unique ID', async () => { + let { stdout, stderr } = await exec('node ' + BIN) + is(stderr, '') + match(stdout, /^[\w-]{21}\n$/) +}) + +test('uses size', async () => { + let { stdout, stderr } = await exec('node ' + BIN + ' --size 10') + is(stderr, '') + match(stdout, /^[\w-]{10}\n$/) +}) + +test('uses alphabet', async () => { + let { stdout, stderr } = await exec( + 'node ' + BIN + ' --alphabet abc --size 15' + ) + is(stderr, '') + match(stdout, /^[abc]{15}\n$/) +}) + +test('shows an error on unknown argument', async () => { + try { + await exec('node ' + BIN + ' -test') + } catch (e) { + match(e, /Unknown argument -test/) + } +}) + +test('shows an error if size is not a number', async () => { + try { + await exec('node ' + BIN + ' -s abc') + } catch (e) { + match(e, /Size must be positive integer/) + } +}) + +test('shows an error on no size with custom alphabet', async () => { + try { + await exec('node ' + BIN + ' --alphabet abc') + } catch (e) { + match(e, /You must also specify size option, when using custom alphabet/) + } +}) + +test('requires error if size is a negative number', async () => { + try { + await exec('node ' + BIN + ' --size "-1"') + } catch (e) { + match(e, /Size must be positive integer/) + } +}) + +test('displays help', async () => { + let { stdout, stderr } = await exec('node ' + BIN + ' --help') + is(stderr, '') + match(stdout, /Usage/) + match(stdout, /\$ nanoid \[options]/) +}) + +test.run()