Last active
April 1, 2022 14:07
-
-
Save alaindet/d6c68848656dcabd63da4c9153e6ef26 to your computer and use it in GitHub Desktop.
CLImb - CLI parser in JavaScript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// node ./test1.js --bool1 -2 --foo aa --bar=bb -f aaa -abc arg1 arg2 | |
const climb = require('./climb'); | |
const input = climb(process.argv, { | |
bool1: { | |
longName: 'bool1', | |
}, | |
bool2: { | |
longName: 'bool2', | |
shortName: '2', | |
}, | |
foo: { | |
longName: 'foo', | |
shortName: 'f', | |
withArgs: true, | |
}, | |
bar: { | |
longName: 'bar', | |
shortName: 'b', | |
withArgs: true, | |
}, | |
a: { | |
shortName: 'a', | |
withArgs: false, | |
}, | |
b: { | |
shortName: 'b', | |
withArgs: false, | |
}, | |
c: { | |
shortName: 'c', | |
withArgs: false, | |
}, | |
}); | |
console.log(input); | |
/* | |
{ | |
args: [ | |
'arg1', | |
'arg2' | |
], | |
options: { | |
bool1: true, | |
bool2: true, | |
foo: 'aaa', | |
bar: 'bb', | |
a: true, | |
b: true, | |
c: true | |
} | |
} | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// node ./myscript.js --bool1 -2 --foo aa --bar=bb -f aaa -abc arg1 arg2 | |
module.exports = (argv, optionsSchema) => { | |
const [bin, script, ...rawItems] = argv; | |
const options = {}; | |
const parsed = { | |
args: [], | |
options: {}, | |
}; | |
for (const optionName in optionsSchema) { | |
const option = { | |
name: optionName, | |
longName: optionsSchema[optionName]?.longName ?? null, | |
shortName: optionsSchema[optionName]?.shortName ?? null, | |
withArgs: optionsSchema[optionName]?.withArgs ?? false, | |
}; | |
if (option?.longName) { | |
options[option.longName] = option; | |
} | |
if (option?.shortName) { | |
options[option.shortName] = option; | |
} | |
} | |
// Split multi-flags before processing | |
// Ex.: -ab => -a -b | |
const items = []; | |
const isMultiFlag = /^\-[a-zA-Z0-9]{2,}$/; | |
for (const item of rawItems) { | |
if (!item.match(isMultiFlag)) { | |
items.push(item); | |
continue; | |
} | |
item.slice(1).split('').forEach(flag => items.push(`-${flag}`)); | |
} | |
for (let i = 0, len = items.length; i < len; i++) { | |
const item = items[i]; | |
const isOption = item.startsWith('-'); | |
if (isOption) { | |
const isLongOption = item.startsWith('--'); | |
let optName = isLongOption ? item.slice(2) : item.slice(1); | |
let value; | |
const isEqualsFormat = optName.indexOf('=') !== -1; | |
// --foo=bar | |
if (isEqualsFormat) { | |
const [newName, newValue] = optName.split('='); | |
optName = newName; | |
value = newValue; | |
} | |
const opt = options[optName]; | |
if (!opt) continue; | |
// No args, keep going | |
if (!opt.withArgs) { | |
parsed.options[opt.name] = true; | |
continue; | |
} | |
// Is it in "--foo=bar" or "-f=bar" format? | |
if (isEqualsFormat) { | |
parsed.options[opt.name] = value; | |
continue; | |
} | |
// Maybe "--foo bar" or "-f bar" format? | |
if (!items[i + 1]?.startsWith('-')) { | |
parsed.options[opt.name] = items[i + 1]; | |
i += 1; // Skip next item! | |
continue; | |
} | |
// No arg found, sorry | |
parsed.options[opt.name] = undefined; | |
continue; | |
} | |
// Argument | |
parsed.args.push(item); | |
} | |
return parsed; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment