Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/manual/conventional-commits.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ Here is the full syntax for a commit message:
[optional footer]
```

The standad says that description is meant to start with a _lowercase letter_, so this is applied throughout this project.
The standard says that description is meant to start with a _lowercase letter_, so this is applied throughout this project.

This project focuses only on the first part:

```
<TYPE>(SCOPE): MESSAGE
<TYPE>(SCOPE): FILE_CHANGE_DESCRIPTION
```


Expand Down
95 changes: 75 additions & 20 deletions src/prepareCommitMsg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
* This module ties together logic from modules in the `generate` module. So it is best kept outside
* that.
*
* The "message" is the full commit message. The "file change description" is the description
* portion, which describes how the files changed.
*
* This module doesn't interact with the git CLI or the extension. It just deals with text.
*/
import { lookupDiffIndexAction } from "./generate/action";
Expand All @@ -13,6 +16,36 @@ import { parseDiffIndex } from "./git/parseOutput";
import { CONVENTIONAL_TYPE } from "./lib/constants";
import { equal } from "./lib/utils";

/**
* Join two strings together with a space, or just one string if only one is set.
*
* Trimming on the outside is necessary, in case only one item is set.
* Don't both trimming the items before joining them, as this project doesn't need that for where
* this is used.
*/
export function _cleanJoin(first: string, second: string) {
return [first, second].join(" ").trim();
}

/**
* Separate a message into a Conventional Commit prefix, if any, and the description.
*
* Require a colon to exist to detect prefix. i.e. 'ci' will be considered a description, but 'ci:'
* will be considered a prefix. This keeps the check simpler as we don't have to match against every
* type and we don' have to check if we are part of a word e.g. 'circus'.
*/
export function _splitMsg(msg: string) {
const [prefix, fileChangeDesc] = msg.includes(":")
? msg.split(":")
: ["", msg];

const [customPrefix, typePrefix] = prefix.includes(" ")
? prefix.split(" ", 2)
: ["", prefix];

return { customPrefix, typePrefix, fileChangeDesc: fileChangeDesc.trim() };
}

/**
* Determine what the prefix should be for a file change, using Conventional Commit standard.
*/
Expand All @@ -31,9 +64,9 @@ export function _msgOne(line: string) {
// Don't unpack as {x, y, from, to}
// const fileChanges = parseDiffIndex(line)
const prefix = _prefixFromChanges(line),
fileChangeMsg = oneChange(line);
fileChangeDesc = oneChange(line);

return { prefix, fileChangeMsg };
return { prefix, fileChangeDesc };
}

/**
Expand Down Expand Up @@ -67,7 +100,7 @@ export function _msgMulti(lines: string[]) {
const conventions = lines.map(_prefixFromChanges);
const convention = collapse(conventions);

return { prefix: convention, fileChangeMsg: namedFiles(lines) };
return { prefix: convention, fileChangeDesc: namedFiles(lines) };
}

/**
Expand All @@ -87,42 +120,64 @@ export function _msgFromChanges(diffIndexLines: string[]) {
/**
* Output a readable conventional commit message.
*/
export function _formatMsg(prefix: CONVENTIONAL_TYPE, fileChangeMsg: string) {
export function _formatMsg(prefix: CONVENTIONAL_TYPE, fileChangeDesc: string) {
if (prefix === CONVENTIONAL_TYPE.UNKNOWN) {
return fileChangeMsg;
return fileChangeDesc;
}
return `${prefix}: ${fileChangeMsg}`;
return `${prefix}: ${fileChangeDesc}`;
}

/**
* Generate a new commit message and format it as a string.
*/
export function _newMsg(lines: string[]) {
const { prefix, fileChangeMsg } = _msgFromChanges(lines);
const { prefix, fileChangeDesc } = _msgFromChanges(lines);

return _formatMsg(prefix, fileChangeMsg);
return _formatMsg(prefix, fileChangeDesc);
}

/**
* Format commit message using old and new messages.
*
* For now, assume old message is a commit message template prefix and can always go in front,
* removing any existing twice on either side for flexibility.
*
* Dev note - must make sure prefix and fileChangeMsg come in separately here, not as a combined
* message.
* The point is to always use the new message and prefix, but respect the old message. If there is
* no new prefix type set, use the old one, and if that is not set then just a simple message will
* do.
*
* TODO: Check if the old message is already a PREFIX form or a PREFIX FILECHANGE form. This changes
* the new message form.
* @param prefix The Conventional Commit prefix to use, as generated by the extension based on
* changed files.
* @param fileChangeDesc A description of changes, also generated.
* @param oldMsg What exists in the commit message box when the extension is run, whether typed or
* generated previously.
*/
export function _combineOldAndNew(
prefix: CONVENTIONAL_TYPE,
fileChangeMsg: string,
fileChangeDesc: string,
oldMsg?: string
) {
const newMsg = _formatMsg(prefix, fileChangeMsg);
if (!oldMsg) {
return _formatMsg(prefix, fileChangeDesc);
}

const {
customPrefix: oldCustomPrefix,
typePrefix: oldTypePrefix,
fileChangeDesc: oldFileChangeDesc,
} = _splitMsg(oldMsg);

const fileChangeDescResult = _cleanJoin(oldFileChangeDesc, fileChangeDesc);

if (prefix !== CONVENTIONAL_TYPE.UNKNOWN) {
return `${_cleanJoin(oldCustomPrefix, prefix)}: ${fileChangeDescResult}`;
}

if (oldTypePrefix) {
return `${_cleanJoin(
oldCustomPrefix,
oldTypePrefix
)}: ${fileChangeDescResult}`;
}

return oldMsg ? `${oldMsg.trim()} ${newMsg}` : newMsg;
return fileChangeDescResult;
}

/**
Expand All @@ -137,9 +192,9 @@ function generateMsgWithOld(fileChanges: string[], oldMsg: string) {
"Either `oldMsg` must not be empty, or use `generateNewMsg` instead."
);
}
const { prefix, fileChangeMsg } = _msgFromChanges(fileChanges);
const { prefix, fileChangeDesc } = _msgFromChanges(fileChanges);

return _combineOldAndNew(prefix, fileChangeMsg, oldMsg);
return _combineOldAndNew(prefix, fileChangeDesc, oldMsg);
}

/**
Expand Down
Loading