mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-03-26 17:02:27 -04:00
77 lines
2.1 KiB
JavaScript
77 lines
2.1 KiB
JavaScript
'use strict';
|
|
|
|
// Returns the minimum number of single-character edits (insert, delete, substitute)
|
|
// needed to turn string `a` into string `b`.
|
|
function levenshtein(a, b) {
|
|
const dp = Array.from({ length: a.length + 1 }, (_, i) =>
|
|
Array.from({ length: b.length + 1 }, (_, j) =>
|
|
i === 0 ? j : j === 0 ? i : 0
|
|
)
|
|
);
|
|
for (let i = 1; i <= a.length; i++) {
|
|
for (let j = 1; j <= b.length; j++) {
|
|
dp[i][j] =
|
|
a[i - 1] === b[j - 1]
|
|
? dp[i - 1][j - 1]
|
|
: 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
|
|
}
|
|
}
|
|
return dp[a.length][b.length];
|
|
}
|
|
|
|
module.exports = async ({ github, context }) => {
|
|
const title = context.payload.pull_request.title;
|
|
const ccRegex =
|
|
/^(feat|fix|refactor|docs|chore|build|ci|test|perf|revert)(\([^)]+\))?: .+/;
|
|
|
|
if (ccRegex.test(title)) return;
|
|
|
|
const types = [
|
|
'feat',
|
|
'fix',
|
|
'refactor',
|
|
'docs',
|
|
'chore',
|
|
'build',
|
|
'ci',
|
|
'test',
|
|
'perf',
|
|
'revert'
|
|
];
|
|
|
|
let newTitle = title;
|
|
|
|
// Fix 1: space between type and scope — "feat (scope):" → "feat(scope):"
|
|
newTitle = newTitle.replace(/^(\w+)\s+(\([^)]+\):)/, '$1$2');
|
|
|
|
// Fix 2: missing colon after scope — "feat(scope) desc" → "feat(scope): desc"
|
|
newTitle = newTitle.replace(/^(\w+\([^)]+\)) ([^:])/, '$1: $2');
|
|
|
|
// Fix 3: typo in type — "refator(scope):" → "refactor(scope):" (distance ≤ 2)
|
|
const typoMatch = newTitle.match(/^(\w+)(\([^)]+\))?:/);
|
|
if (typoMatch) {
|
|
const candidate = typoMatch[1];
|
|
if (!types.includes(candidate)) {
|
|
const closest = types
|
|
.map(t => ({ t, d: levenshtein(candidate, t) }))
|
|
.filter(x => x.d <= 2)
|
|
.sort((a, b) => a.d - b.d)[0];
|
|
if (closest) newTitle = newTitle.replace(candidate, closest.t);
|
|
}
|
|
}
|
|
|
|
// Catch-all: prefix with "fix: " if still not a valid CC title
|
|
if (!ccRegex.test(newTitle)) {
|
|
newTitle = `fix: ${title}`;
|
|
}
|
|
|
|
if (newTitle !== title) {
|
|
await github.rest.pulls.update({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
pull_number: context.payload.pull_request.number,
|
|
title: newTitle
|
|
});
|
|
}
|
|
};
|