Repository navigation
Expand file tree
/
Copy pathindex.js
More file actions
143 lines (128 loc) · 3.62 KB
/
Copy pathindex.js
File metadata and controls
143 lines (128 loc) · 3.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
'use strict'
const fs = require('fs')
const readPkg = require('read-pkg-up')
const truncate = require('cli-truncate')
const wrap = require('wrap-ansi')
const pad = require('pad')
const fuse = require('fuse.js')
const homeDir = require('home-dir')
const types = require('./lib/types')
const defaultConfig = {
types,
symbol: false
}
function getEmojiChoices({ types, symbol }) {
const maxNameLength = types.reduce(
(maxLength, type) => (type.name.length > maxLength ? type.name.length : maxLength
), 0)
return types.map(choice => ({
name: `${pad(choice.name, maxNameLength)} ${choice.emoji} ${choice.description}`,
value: symbol ? choice.emoji : choice.code,
code: choice.code
}))
}
function loadConfig() {
const getConfig = (obj) => obj && obj.config && obj.config['cz-emoji']
return readPkg()
.then(({ pkg }) => {
const config = getConfig(pkg)
if (config) return config
return new Promise((resolve, reject) => {
fs.readFile(homeDir('.czrc'), 'utf8', (err, content) => {
if (err) reject(err)
const czrc = JSON.parse(content) || null
resolve(getConfig(czrc))
})
})
})
.then(config => (
Object.assign({}, defaultConfig, config)
))
.catch(() => (defaultConfig))
}
/**
* Create inquier.js questions object trying to read `types` and `scopes` from the current project
* `package.json` falling back to nice default :)
*
* @param {Object} config Result of the `loadConfig` returned promise
* @return {Array} Return an array of `inquier.js` questions
* @private
*/
function createQuestions(config) {
const choices = getEmojiChoices(config)
const fuzzy = new fuse(choices, {
shouldSort: true,
threshold: 0.4,
location: 0,
distance: 100,
maxPatternLength: 32,
minMatchCharLength: 1,
keys: ["name", "code"]
})
return [
{
type: 'autocomplete',
name: 'type',
message: "Select the type of change you're committing:",
source: (answersSoFar, query) => {
return Promise.resolve(query ? fuzzy.search(query) : choices)
}
},
{
type: config.scopes ? 'list' : 'input',
name: 'scope',
message: 'Specify a scope:',
choices: config.scopes && [{ name: '[none]', value: '' }].concat(config.scopes)
},
{
type: 'input',
name: 'subject',
message: 'Write a short description:'
},
{
type: 'input',
name: 'issues',
message: 'List any issue closed (#1, ...):'
},
{
type: 'input',
name: 'body',
message: 'Provide a longer description:'
}
]
}
/**
* Format the git commit message from given answers.
*
* @param {Object} answers Answers provide by `inquier.js`
* @return {String} Formated git commit message
*/
function format(answers) {
// parentheses are only needed when a scope is present
const scope = answers.scope ? '(' + answers.scope.trim() + ') ' : ''
// build head line and limit it to 100
const head = truncate(answers.type + ' ' + scope + answers.subject.trim(), 100)
// wrap body at 100
const body = wrap(answers.body, 100)
const footer = (answers.issues.match(/#\d+/g) || [])
.map(issue => `Closes ${issue}`)
.join('\n')
return [head, body, footer]
.join('\n\n')
.trim()
}
/**
* Export an object containing a `prompter` method. This object is used by `commitizen`.
*
* @type {Object}
*/
module.exports = {
prompter: function(cz, commit) {
cz.prompt.registerPrompt('autocomplete', require('inquirer-autocomplete-prompt'))
loadConfig()
.then(createQuestions)
.then(cz.prompt)
.then(format)
.then(commit)
}
}