You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
136 lines
3.9 KiB
TypeScript
136 lines
3.9 KiB
TypeScript
import { consola } from 'consola';
|
|
import { readJsonSync, writeJSONSync } from 'fs-extra';
|
|
import { markdownToTxt } from 'markdown-to-txt';
|
|
import { existsSync, readFileSync } from 'node:fs';
|
|
import { resolve } from 'node:path';
|
|
import semver from 'semver';
|
|
|
|
import { CHANGELOG_DIR, CHANGELOG_FILE } from './const';
|
|
|
|
export interface ChangelogStaticItem {
|
|
children: {
|
|
[category: string]: string[];
|
|
};
|
|
date: string;
|
|
version: string;
|
|
}
|
|
|
|
class BuildStaticChangelog {
|
|
private removeDetailsTag = (changelog: string): string => {
|
|
const detailsRegex: RegExp = /<details\b[^>]*>[\S\s]*?<\/details>/gi;
|
|
return changelog.replaceAll(detailsRegex, '');
|
|
};
|
|
|
|
private cleanVersion = (version: string): string => {
|
|
return semver.clean(version) || version;
|
|
};
|
|
|
|
private formatCategory = (category: string): string => {
|
|
const cate = category.trim().toLowerCase();
|
|
|
|
switch (cate) {
|
|
case 'bug fixes': {
|
|
return 'fixes';
|
|
}
|
|
case 'features': {
|
|
return 'features';
|
|
}
|
|
default: {
|
|
return 'improvements';
|
|
}
|
|
}
|
|
};
|
|
|
|
private formatChangelog = (changelog: string): ChangelogStaticItem[] => {
|
|
const cleanedChangelog = this.removeDetailsTag(changelog);
|
|
const input = markdownToTxt(cleanedChangelog);
|
|
const versions = input.split(/Version |Version /).slice(1);
|
|
|
|
const output: ChangelogStaticItem[] = [];
|
|
|
|
for (const version of versions) {
|
|
const lines = version.trim().split('\n');
|
|
const versionNumber = lines[0].trim();
|
|
const date = lines[2].replace('Released on ', '').trim();
|
|
|
|
const entry: ChangelogStaticItem = {
|
|
children: {},
|
|
date: date,
|
|
version: this.cleanVersion(versionNumber),
|
|
};
|
|
|
|
let currentCategory = '';
|
|
let skipSection = false;
|
|
|
|
for (let i = 3; i < lines.length; i++) {
|
|
const line = lines[i].trim();
|
|
if (line === '') continue;
|
|
|
|
if (/^\p{Emoji}/u.test(line)) {
|
|
currentCategory = this.formatCategory(line.replace(/^\p{Emoji} /u, ''));
|
|
if (!currentCategory) continue;
|
|
entry.children[currentCategory] = [];
|
|
skipSection = false;
|
|
} else if (line.startsWith('misc:') && !skipSection && currentCategory) {
|
|
entry.children[currentCategory].push(line.replace('misc:', '').trim());
|
|
}
|
|
}
|
|
|
|
// Remove empty categories
|
|
for (const category in entry.children) {
|
|
if (entry.children[category].length === 0) {
|
|
delete entry.children[category];
|
|
}
|
|
}
|
|
|
|
output.push(entry);
|
|
}
|
|
|
|
return output;
|
|
};
|
|
|
|
private mergeAndSortVersions = (oldVersions: any, newVersions: any) => {
|
|
const mergedVersions = [...oldVersions];
|
|
|
|
for (const newVersion of newVersions) {
|
|
const existingIndex = mergedVersions.findIndex(
|
|
(v) => this.cleanVersion(v.version) === this.cleanVersion(newVersion.version),
|
|
);
|
|
if (existingIndex === -1) {
|
|
const insertIndex = mergedVersions.findIndex(
|
|
(v) =>
|
|
semver.compare(this.cleanVersion(newVersion.version), this.cleanVersion(v.version)) > 0,
|
|
);
|
|
if (insertIndex === -1) {
|
|
mergedVersions.push(newVersion);
|
|
} else {
|
|
mergedVersions.splice(insertIndex, 0, newVersion);
|
|
}
|
|
}
|
|
}
|
|
|
|
return mergedVersions;
|
|
};
|
|
|
|
run() {
|
|
Object.entries(CHANGELOG_FILE).forEach(([version, path]) => {
|
|
const data = readFileSync(path, 'utf8');
|
|
const newFile = this.formatChangelog(data);
|
|
|
|
const filename = resolve(CHANGELOG_DIR, `${version}.json`);
|
|
let mergedFile = newFile;
|
|
|
|
if (existsSync(filename)) {
|
|
const oldFile = readJsonSync(filename, 'utf8');
|
|
mergedFile = this.mergeAndSortVersions(oldFile, newFile);
|
|
}
|
|
|
|
writeJSONSync(filename, mergedFile, { spaces: 2 });
|
|
|
|
consola.success(`Changelog ${version} has been built successfully!`);
|
|
});
|
|
}
|
|
}
|
|
|
|
export const buildStaticChangelog = new BuildStaticChangelog();
|