UNPKG

cz-ghostwriter

Version:
167 lines (166 loc) 7.42 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.run = void 0; const chalk = require("chalk"); const child_process_1 = require("child_process"); const fs_1 = require("fs"); const path_1 = require("path"); const wordWrap = require("word-wrap"); const configuration_1 = require("./configuration"); const maxLineLength = 120; const getLongestString = (array) => { if (array.length === 0) { return ''; } let longest = array[0]; let longestLength = longest.length; for (let idx = 0; idx < array.length; idx += 1) { const element = array[idx]; const elementLength = element.length; if (elementLength > longestLength) { longest = element; longestLength = elementLength; } } return longest; }; const getSubjectMaxLength = (scope, type) => { return maxLineLength - (type.length + 2 + (scope ? scope.length + 2 : 0)); }; const sanitizeSubject = (subject) => { let sanitizedSubject = subject.trim(); const lowerCasedFirstCharacter = sanitizedSubject.charAt(0).toLowerCase(); if (lowerCasedFirstCharacter !== sanitizedSubject.charAt(0)) { sanitizedSubject = lowerCasedFirstCharacter + sanitizedSubject.slice(1, sanitizedSubject.length); } while (sanitizedSubject.endsWith('.')) { sanitizedSubject = sanitizedSubject.slice(0, sanitizedSubject.length - 1); } return sanitizedSubject; }; const skipWhenUsingMergeMessage = ({ useMergeMessage }) => !useMergeMessage; const run = () => { var _a, _b, _c; const config = (0, configuration_1.getConfiguration)(); const typeLength = getLongestString(config.types.map(({ type }) => type)).length + 1; const typeChoices = config.types.map(({ description, type }) => { const prefix = `${type}:`.padEnd(typeLength); return { name: `${prefix} ${description}`, value: type }; }); const scopeLength = getLongestString((_b = (_a = config.scopes) === null || _a === void 0 ? void 0 : _a.map(({ type }) => type)) !== null && _b !== void 0 ? _b : []).length + 1; const scopeChoices = (_c = config.scopes) === null || _c === void 0 ? void 0 : _c.map(({ description, type }) => { const prefix = `${type}:`.padEnd(scopeLength); return { name: `${prefix} ${description}`, value: type }; }); const scopePrompt = scopeChoices ? { choices: scopeChoices, message: 'What is the scope of this commit? (press enter to skip)\n', name: 'scope', type: 'list', when: skipWhenUsingMergeMessage, } : { filter: (scope) => scope.trim().toLowerCase(), message: 'What is the scope of this commit? (press enter to skip)\n', name: 'scope', type: 'input', when: skipWhenUsingMergeMessage, }; const mergeMsgPath = (0, path_1.resolve)((0, child_process_1.execSync)('git rev-parse --git-dir').toString().trim(), 'MERGE_MSG'); const isMerging = (0, fs_1.existsSync)(mergeMsgPath); const defaultMergeMsg = isMerging ? (0, fs_1.readFileSync)(mergeMsgPath).toString().trim() : ''; const hasDefaultMergeMsg = defaultMergeMsg.length > 0; return { prompter: (cz, commit) => { cz.prompt([ { message: 'An ongoing merge was detected. Would you like to use the default merge commit message?', name: 'useMergeMessage', type: 'confirm', when: hasDefaultMergeMsg, }, { choices: typeChoices, message: 'What type of change are you committing?', name: 'type', when: skipWhenUsingMergeMessage, type: 'list', }, scopePrompt, { filter: sanitizeSubject, message: (answers) => { return `Write a short, imperative tense description of the commit (max: ${getSubjectMaxLength(answers.scope, answers.type)} chars):\n`; }, name: 'subject', transformer: (subject, answers) => { const color = subject.length <= getSubjectMaxLength(answers.scope, answers.type) ? chalk.green : chalk.red; return color(`(${subject.length}) ${subject}`); }, type: 'input', validate: (subject, answers) => { const sanitizedSubject = sanitizeSubject(subject); if (sanitizedSubject.length === 0) { return 'A subject is required'; } const subjectMaxLength = getSubjectMaxLength(answers.scope, answers.type); if (sanitizedSubject.length <= subjectMaxLength) { return true; } return `The subject length must be less than or equal to ${subjectMaxLength} characters. The current length is ${subject.length} characters.`; }, when: skipWhenUsingMergeMessage, }, { filter: (breaking) => breaking.trim(), message: 'If any, describe the breaking change(s) contained within the commit: (press enter to skip)\n', name: 'breaking', type: 'input', when: skipWhenUsingMergeMessage, }, { filter: (issues) => issues.trim(), message: `If any, enter the issues, separated by a space, that are related to this commit: (press enter to skip)\n`, name: 'issues', type: 'input', when: skipWhenUsingMergeMessage, }, ]).then((answers) => { const useMergeMessage = Boolean(answers.useMergeMessage); if (useMergeMessage) { commit(wordWrap(defaultMergeMsg, { indent: '', trim: true, width: maxLineLength, })); return; } let message = `${answers.type}`; if (answers.scope && answers.scope !== '*') { message += `(${answers.scope})`; } message += `: ${answers.subject}`; if (answers.breaking) { message += `\n\nBREAKING CHANGE: ${answers.breaking}`; } if (answers.issues) { const issues = answers.issues .split(' ') .map((issue) => (issue.charAt(0) === '#' ? issue : `#${issue}`)) .join(' '); message += `\n\n${config.issueReferencesPrefix} ${issues}`; } commit(wordWrap(message, { indent: '', trim: true, width: maxLineLength, })); }); }, }; }; exports.run = run;