'use strict' const glob = require('glob') const CUSTOM = [''] const BOOLEAN = false const options = { start: { '--port': CUSTOM, '--auto-watch': BOOLEAN, '--no-auto-watch': BOOLEAN, '--log-level': ['disable', 'debug', 'info', 'warn', 'error'], '--colors': BOOLEAN, '--no-colors': BOOLEAN, '--reporters': ['dots', 'progress'], '--no-reporters': BOOLEAN, '--browsers': ['Chrome', 'ChromeHeadless', 'ChromeCanary', 'Firefox', 'PhantomJS', 'Safari', 'Opera'], '--no-browsers': BOOLEAN, '--single-run': BOOLEAN, '--no-single-run': BOOLEAN, '--help': BOOLEAN }, init: { '--log-level': ['disable', 'debug', 'info', 'warn', 'error'], '--colors': BOOLEAN, '--no-colors': BOOLEAN, '--help': BOOLEAN }, run: { '--no-refresh': BOOLEAN, '--port': CUSTOM, '--help': BOOLEAN } } function opositeWord (word) { if (word.startsWith('-')) { return word.startsWith('--no-') ? `--${word.slice(5)}` : `--no-${word.slice(2)}` } else { return null } } function sendCompletion (possibleWords, env) { const regexp = new RegExp('^' + env.last) possibleWords .filter((word) => regexp.test(word) && !env.words.includes(word) && !env.words.includes(opositeWord(word))) .forEach((word) => { console.log(word) }) } function sendCompletionFiles (env) { glob(env.last + '*', { mark: true, nocase: true }, (err, files) => { if (err) return console.error(err) if (files.length === 1 && files[0].endsWith('/')) { sendCompletionFiles({ last: files[0] }) } else { console.log(files.join('\n')) } }) } function complete (env) { if (env.count === 1) { return sendCompletion(env.words[0].startsWith('-') ? ['--help', '--version'] : Object.keys(options), env) } else if (env.count === 2 && !env.words[1].startsWith('-')) { return sendCompletionFiles(env) } const cmdOptions = options[env.words[0]] if (cmdOptions) { if (cmdOptions[env.prev] === CUSTOM && env.last) { console.log(env.last) } else { return sendCompletion(cmdOptions[env.prev] || Object.keys(cmdOptions), env) } } } function completion () { if (process.argv[3] === '--') { return complete({ words: process.argv.slice(5), count: parseInt(process.env.COMP_CWORD, 10), last: process.argv[process.argv.length - 1], prev: process.argv[process.argv.length - 2] }) } // just print out the karma-completion.sh const fs = require('graceful-fs') const path = require('path') fs.readFile(path.resolve(__dirname, '../scripts/karma-completion.sh'), 'utf8', function (err, data) { if (err) return console.error(err) process.stdout.write(data) process.stdout.on('error', function (error) { // Darwin is a real dick sometimes. // // This is necessary because the "source" or "." program in // bash on OS X closes its file argument before reading // from it, meaning that you get exactly 1 write, which will // work most of the time, and will always raise an EPIPE. // // Really, one should not be tossing away EPIPE errors, or any // errors, so casually. But, without this, `. <(karma completion)` // can never ever work on OS X. if (error.errno === 'EPIPE') { error = null } }) }) } // PUBLIC API exports.completion = completion // for testing exports.opositeWord = opositeWord exports.sendCompletion = sendCompletion exports.complete = complete