<|start_filename|>index.js<|end_filename|>
#!/usr/bin/env node
const fs = require('fs')
const cp = require('child_process')
const path = require('path')
const { forceStdinTty } = require('force-stdin-tty')
const { prompt } = require('enquirer')
const c = require('ansi-colors')
const pkg = require('./package.json')

const msgPath = path.resolve(process.cwd(), process.argv[process.argv.length - 1])
const scopesRc = path.resolve(process.cwd(), '.commitscopesrc')

const scopes = []

let type, scope, headerPrefix, maxTitleLength

process.stdout.write(c.bold('\n👮 Welcome to Komit\n') + c.dim(`v${pkg.version}\n\n`))

let overwroteStdin = false
try {
	overwroteStdin = forceStdinTty()
} catch {
	process.stdout.write(c.bold.red("⚠️  Komit couldn't access your stdin stream.\n"))
	process.exit(1)
}

try {
	fs.readFileSync(scopesRc, {
		encoding: 'utf8'
	}).split('\n').forEach(line => {
		if (line.startsWith('#') || line.trim().length === 0) return
		scopes.push(line.toLowerCase().trim().replace(/ /g, '-'))
	})
} catch(error) {
	// ignore
}

function scopeSuggest(input, choices) {
	let newPrompt = true
	const list = choices.filter(ch => {
		if (ch.name === 'new' || ch.name === '(unscoped)') return false

		const test = ch.message.toLowerCase()
		if (test === input.toLowerCase().trim().replace(/ /g, '-')) {
			newPrompt = false
		}

		return test.includes(input.toLowerCase().trim().replace(/ /g, '-'))
	})

	if (newPrompt && input) {
		list.push({
			name: 'new',
			normalized: true,
			message: `🏷️ New scope: ${input.toLowerCase().trim().replace(/ /g, '-')}`,
			value: input.toLowerCase().trim().replace(/ /g, '-')
		})
	}

	if (input.length === 0) {
		list.unshift({
			name: '(unscoped)',
			normalized: true,
			message: '(unscoped)',
			value: '(unscoped)'
		})
	}

	return list
}

prompt([
	{
		type: 'autocomplete',
		name: 'type',
		message: 'Commit type:',
		choices: [
			'build',
			'ci',
			'chore',
			'docs',
			'feat',
			'fix',
			'perf',
			'refactor',
			'revert',
			'style',
			'test'
		],
		result: result => {
			type = result
			return result
		}
	},
	{
		type: 'autocomplete',
		name: 'scope',
		message: 'Scope:',
		choices: [
			'(unscoped)',
			...scopes
		],
		suggest: scopeSuggest,
		result: result => {
			scope = result
			headerPrefix = `${type}${(scope !== '(unscoped)') ? `(${scope})` : ''}: `
			maxTitleLength = 100 - headerPrefix.length
			return result
		}
	},
	{
		type: 'input',
		name: 'title',
		message: 'Title:',
		validate: title => {
			if (title.length === 0) {
				return 'Commit title cannot be empty!'
			}
			if (title.length > maxTitleLength) {
				return `Title is too long (${title.length}/${maxTitleLength}) characters)`
			}
			if (title[0].charCodeAt(0) !== title[0].toLowerCase().charCodeAt(0)) {
				return 'Title must start in lowercase'
			}
			if (title[title.length - 1] === '.') {
				return 'Title cannot end with a full stop "."'
			}
			return true
		}
	}
]).then(answer => {
	if (answer.scope !== '(unscoped)' && !scopes.includes(answer.scope)) {
		scopes.push(answer.scope)
		fs.writeFileSync(scopesRc, scopes.join('\n'))
		process.stdout.write(c.dim('Updated commit scopes file at .commitscopesrc, adding file to commit.\n'))
		cp.execSync(`git add ${scopesRc}`, {
			cwd: process.cwd()
		})
	}

	const commitHeader = `${headerPrefix}${answer.title}`
	process.stdout.write(
		'\n' +
		c.bold.green(type) +
		(scope !== '(unscoped)' ? `(${c.italic.blue(scope)}): ` : ': ') +
		c.bold.underline(answer.title) +
		'\n'
	)

	fs.writeFileSync(msgPath, commitHeader)

	if (overwroteStdin) {
		process.stdin.destroy()
	}

	process.exit(0)
}).catch(error => {

	if (overwroteStdin) {
		process.stdin.destroy()
	}

	if (error !== '') {
		process.stdout.write(c.bold.red(`${error}\n`))
		process.exit(1)
	} else {
		process.stdout.write('\nGot SIGINT, bypassing prompts...\n')
		process.exit(0)
	}
})


<|start_filename|>package.json<|end_filename|>
{
  "name": "komit",
  "version": "1.0.5",
  "description": "An interactive prompt for conventional commit messages that doesn't get in your way. Designed to run as a git hook.",
  "main": "index.js",
  "bin": "./index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "husky": {
    "hooks": {
      "prepare-commit-msg": "node index.js $HUSKY_GIT_PARAMS",
      "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
    }
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/GitSquared/komit.git"
  },
  "keywords": [
    "git",
    "commit",
    "commitlint",
    "terminal",
    "conventional-commit"
  ],
  "author": "<NAME> <<EMAIL>> (https://gaby.dev)",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/GitSquared/komit/issues"
  },
  "homepage": "https://github.com/GitSquared/komit#readme",
  "dependencies": {
    "ansi-colors": "^4.1.1",
    "enquirer": "^2.3.6",
    "force-stdin-tty": "0.0.1"
  },
  "devDependencies": {
    "@commitlint/cli": "^9.1.1",
    "@commitlint/config-conventional": "^9.1.1",
    "husky": "^4.2.5"
  }
}
