cz-cc
Version:
Commitizen adaptor that follows the Conventional Commits specification (with support for semantic emoji ✨)
238 lines (234 loc) • 13.1 kB
JavaScript
;
/*!
Copyright 2021 Yusipeng Xuan
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
Object.defineProperty(exports, "__esModule", { value: true });
var commitizen_1 = require("commitizen");
var inquirer_autocomplete_prompt_1 = __importDefault(require("inquirer-autocomplete-prompt"));
var chalk_1 = __importDefault(require("chalk"));
var word_wrap_1 = __importDefault(require("word-wrap"));
var config_1 = __importDefault(require("./config"));
var _q = process.env, CZ_TYPE = _q.CZ_TYPE, CZ_SCOPE = _q.CZ_SCOPE, CZ_SUBJECT = _q.CZ_SUBJECT, CZ_BODY = _q.CZ_BODY, CZ_ISSUES = _q.CZ_ISSUES, DISABLE_SCOPE_LOWERCASE = _q.DISABLE_SCOPE_LOWERCASE, DISABLE_SUBJECT_LOWERCASE = _q.DISABLE_SUBJECT_LOWERCASE, CZ_MAX_HEADER_WIDTH = _q.CZ_MAX_HEADER_WIDTH, CZ_MIN_SUBJECT_LENGTH = _q.CZ_MIN_SUBJECT_LENGTH, CZ_MAX_LINE_WIDTH = _q.CZ_MAX_LINE_WIDTH;
var config = (_a = commitizen_1.configLoader.load()) !== null && _a !== void 0 ? _a : {};
var options = {
useEmoji: (_b = config.useEmoji) !== null && _b !== void 0 ? _b : config_1.default.useEmoji,
useExclamationMark: (_c = config.useExclamationMark) !== null && _c !== void 0 ? _c : config_1.default.useExclamationMark,
questions: (_d = config.questions) !== null && _d !== void 0 ? _d : config_1.default.questions,
defaultTypes: (_e = config.defaultTypes) !== null && _e !== void 0 ? _e : config_1.default.defaultTypes,
scopes: (_f = config.scopes) !== null && _f !== void 0 ? _f : config_1.default.scopes,
types: (_g = config.types) !== null && _g !== void 0 ? _g : config_1.default.types,
defaultType: CZ_TYPE !== null && CZ_TYPE !== void 0 ? CZ_TYPE : config.defaultType,
defaultScope: CZ_SCOPE !== null && CZ_SCOPE !== void 0 ? CZ_SCOPE : config.defaultScope,
defaultSubject: CZ_SUBJECT !== null && CZ_SUBJECT !== void 0 ? CZ_SUBJECT : config.defaultSubject,
defaultBody: CZ_BODY !== null && CZ_BODY !== void 0 ? CZ_BODY : config.defaultBody,
defaultIssues: CZ_ISSUES !== null && CZ_ISSUES !== void 0 ? CZ_ISSUES : config.defaultIssues,
disableScopeLowerCase: DISABLE_SCOPE_LOWERCASE !== null && DISABLE_SCOPE_LOWERCASE !== void 0 ? DISABLE_SCOPE_LOWERCASE : config.disableScopeLowerCase,
disableSubjectLowerCase: DISABLE_SUBJECT_LOWERCASE !== null && DISABLE_SUBJECT_LOWERCASE !== void 0 ? DISABLE_SUBJECT_LOWERCASE : config.disableSubjectLowerCase,
maxHeaderWidth: CZ_MAX_HEADER_WIDTH ? parseInt(CZ_MAX_HEADER_WIDTH) : (_j = (_h = config.maxHeaderLength) !== null && _h !== void 0 ? _h : config.maxHeaderWidth) !== null && _j !== void 0 ? _j : config_1.default.maxHeaderLength,
minSubjectLength: CZ_MIN_SUBJECT_LENGTH ? parseInt(CZ_MIN_SUBJECT_LENGTH) : (_k = config.minSubjectLength) !== null && _k !== void 0 ? _k : config_1.default.minSubjectLength,
maxLineWidth: CZ_MAX_LINE_WIDTH ? parseInt(CZ_MAX_LINE_WIDTH) : (_m = (_l = config.maxLineLength) !== null && _l !== void 0 ? _l : config.maxLineWidth) !== null && _m !== void 0 ? _m : config_1.default.maxLineLength
};
var getTypeListWidth = function (typeList) {
var longestLength = 0;
typeList.forEach(function (str) {
if (str.length > longestLength)
longestLength = str.length;
});
return longestLength + 2;
};
var getMaxSubjectLength = function (type, scope) {
return options.maxHeaderWidth - type.length - 2 - (scope ? scope.length + 2 : 0) - (options.useEmoji ? 2 : 0);
};
var processSubject = function (text) {
var trimmedSubject = text.replace(/(^[\s]+|[\s\.]+$)/g, '');
if (!trimmedSubject)
return '';
return options.disableSubjectLowerCase ? trimmedSubject : "" + trimmedSubject[0].toLowerCase() + trimmedSubject.slice(1);
};
var questions = [
{
when: options.questions.includes('type'),
type: 'autocomplete',
name: 'type',
message: "Select the type of change that you are committing:",
source: function (_, input) { return Object.entries(options.types)
.filter(function (_a) {
var _b = __read(_a, 1), key = _b[0];
return input ? key.includes(input) : Array.isArray(options.defaultTypes) ? options.defaultTypes.includes(key) : true;
})
.map(function (_a) {
var _b = __read(_a, 2), key = _b[0], _c = _b[1], emoji = _c.emoji, value = _c.value, description = _c.description;
return ({
name: (key + ':').padEnd(getTypeListWidth(Object.keys(options.types))) + " " + (options.useEmoji ? emoji + ' ' : '') + description,
value: key,
short: "" + value + (options.useEmoji ? ' ' + emoji : '')
});
}); },
default: options.defaultType
},
((_o = options.scopes) === null || _o === void 0 ? void 0 : _o.length) > 0 ? {
type: 'autocomplete',
name: 'scope',
message: "Select the scope of change that you are committing:",
source: function (_, input) { var _a; return input ? (_a = options.scopes) === null || _a === void 0 ? void 0 : _a.filter(function (key) { return key.includes(input); }) : options.scopes; },
default: options.defaultScope,
when: options.questions.includes('scope'),
} : {
type: 'input',
name: 'scope',
message: "What is the scope of this change (e.g. component or file name): " + chalk_1.default.gray('[press enter to skip]') + "\n",
default: options.defaultScope,
filter: function (scope) { return options.disableScopeLowerCase ? scope === null || scope === void 0 ? void 0 : scope.trim() : scope === null || scope === void 0 ? void 0 : scope.trim().toLowerCase(); },
when: options.questions.includes('scope'),
transformer: function (scope) { return " " + chalk_1.default.cyan(scope); }
},
{
type: 'input',
name: 'subject',
message: 'Write a short, imperative tense description of the change:',
default: options.defaultSubject,
validate: function (subject, answers) {
var processedSubject = processSubject(subject);
if (processedSubject.length === 0)
return chalk_1.default.red('[ERROR] subject is required');
if (processedSubject.length < options.minSubjectLength)
return chalk_1.default.red("[ERROR] subject length must be greater than or equal to " + options.minSubjectLength + " characters");
var maxSubjectLength = getMaxSubjectLength(answers.type, answers.scope);
if (processedSubject.length > maxSubjectLength)
return chalk_1.default.red("[ERROR] subject length must be less than or equal to " + maxSubjectLength + " characters");
return true;
},
transformer: function (subject, answers) {
var minSubjectLength = options.minSubjectLength;
var subjectLength = subject.length;
var maxSubjectLength = getMaxSubjectLength(answers.type, answers.scope);
var tooltip;
if (subjectLength < minSubjectLength)
tooltip = minSubjectLength - subjectLength + " more chars needed";
else if (subjectLength > maxSubjectLength)
tooltip = subjectLength - maxSubjectLength + " chars over the limit";
else
tooltip = maxSubjectLength - subjectLength + " more chars allowed";
var tooltipColor = (subjectLength >= minSubjectLength && subjectLength <= maxSubjectLength) ? chalk_1.default.gray : chalk_1.default.red;
var subjectColor = (subjectLength >= minSubjectLength && subjectLength <= maxSubjectLength) ? chalk_1.default.cyan : chalk_1.default.red;
return tooltipColor.bold('[' + tooltip + ']') + "\n " + subjectColor(subject);
},
filter: function (subject) { return processSubject(subject); },
when: options.questions.includes('subject'),
},
{
type: 'input',
name: 'body',
message: "Provide a longer description of the change: " + chalk_1.default.gray('[press enter to skip]') + "\n",
default: options.defaultBody,
when: options.questions.includes('body'),
transformer: function (body) { return " " + chalk_1.default.cyan(body); }
},
{
type: 'list',
name: 'isBreaking',
message: 'Are there any breaking changes?',
choices: [{ name: 'NO', value: false }, { name: 'YES', value: true }],
default: function (answers) { return answers.type === 'break'; },
when: options.questions.includes('breaking'),
},
{
type: 'input',
name: 'breakingBody',
message: 'A BREAKING CHANGE commit requires a body. Please enter a longer description of the commit itself:\n',
validate: function (breakingBody) {
var bodyLength = breakingBody.trim().length;
if (bodyLength === 0)
return chalk_1.default.red('[ERROR] body is required for BREAKING CHANGE');
return true;
},
when: function (answers) { return answers.isBreaking && !answers.body; },
transformer: function (body) { return " " + chalk_1.default.cyan(body); }
},
{
type: 'input',
name: 'breaking',
message: 'Describe the breaking changes:\n',
when: function (answers) { return answers.isBreaking; },
transformer: function (footer) { return " " + chalk_1.default.cyan(footer); }
},
{
type: 'list',
name: 'isIssueAffected',
message: 'Does this change affect any open issues?',
choices: [{ name: 'NO', value: false }, { name: 'YES', value: true }],
default: options.defaultIssues,
when: options.questions.includes('issues'),
},
{
type: 'input',
name: 'issuesBody',
message: 'If issues are closed, the commit requires a body. Please enter a longer description of the commit itself:\n',
when: function (answers) { return answers.isIssueAffected && !answers.body && !answers.breakingBody; },
transformer: function (body) { return " " + chalk_1.default.cyan(body); }
},
{
type: 'input',
name: 'issues',
message: 'Add issue references (e.g. "fix #123", "refer #123".):\n',
default: (_p = options.defaultIssues) !== null && _p !== void 0 ? _p : undefined,
when: function (answers) { return answers.isIssueAffected; },
transformer: function (body) { return " " + chalk_1.default.cyan(body); },
}
];
var prompter = function (cz, commit) {
cz.registerPrompt('autocomplete', inquirer_autocomplete_prompt_1.default);
cz.prompt(questions)
.then(function (_a) {
var type = _a.type, scope = _a.scope, subject = _a.subject, body = _a.body, breaking = _a.breaking, breakingBody = _a.breakingBody, issues = _a.issues, issuesBody = _a.issuesBody;
var message = [];
var wrapOptions = {
width: options.maxLineWidth,
indent: '',
trim: true,
};
var _b = options.types[type], typeValue = _b.value, emoji = _b.emoji;
message.push("" + typeValue + (scope ? '(' + scope + ')' : '') + ((breaking && options.useExclamationMark) ? '!' : '') + ": " + (options.useEmoji ? emoji + ' ' : '') + subject);
if (body)
message.push(word_wrap_1.default(body, wrapOptions));
else if (breakingBody)
message.push(word_wrap_1.default(breakingBody, wrapOptions));
else if (issuesBody)
message.push(word_wrap_1.default(issuesBody, wrapOptions));
if (breaking)
message.push(word_wrap_1.default("BREAKING CHANGE: " + breaking.trim().replace(/^BREAKING CHANGE: /g, ''), wrapOptions));
if (issues)
message.push(word_wrap_1.default(issues, wrapOptions));
commit(message.join('\n\n'));
});
};
exports.default = prompter;