mirror of
https://github.com/davidgasquez/awesome-duckdb.git
synced 2026-11-05 18:45:43 +00:00
103 lines
2.8 KiB
JavaScript
103 lines
2.8 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import { readFileSync } from "node:fs";
|
|
|
|
const [basePath, currentPath] = process.argv.slice(2);
|
|
if (!basePath || !currentPath) {
|
|
console.error("Usage: check-readme-order.mjs BASE_README CURRENT_README");
|
|
process.exit(2);
|
|
}
|
|
|
|
const SORTED_SECTION = "Extensions / Community Extensions";
|
|
const IGNORED_SECTIONS = new Set(["Contents"]);
|
|
|
|
function headingName(markdown) {
|
|
const linkedHeading = markdown.match(/^\[([^\]]+)\]\([^)]+\)$/);
|
|
return linkedHeading ? linkedHeading[1] : markdown;
|
|
}
|
|
|
|
function parseSections(path) {
|
|
const sections = new Map();
|
|
const headings = [];
|
|
let section = null;
|
|
|
|
for (const line of readFileSync(path, "utf8").split("\n")) {
|
|
const heading = line.match(/^(#{2,6})\s+(.+?)\s*$/);
|
|
if (heading) {
|
|
const level = heading[1].length;
|
|
while (headings.length > 0 && headings.at(-1).level >= level) {
|
|
headings.pop();
|
|
}
|
|
headings.push({ level, name: headingName(heading[2]) });
|
|
section = headings.map(({ name }) => name).join(" / ");
|
|
if (!sections.has(section)) {
|
|
sections.set(section, []);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (!section || !line.startsWith("- [")) {
|
|
continue;
|
|
}
|
|
|
|
const item = line.match(/^- \[(.*?)\]\(([^)\s]+)(?:\s+[^)]*)?\)/);
|
|
if (!item) {
|
|
continue;
|
|
}
|
|
|
|
const label = item[1].replaceAll("`", "").trim();
|
|
sections.get(section).push({
|
|
sortKey: label.toLowerCase(),
|
|
url: item[2],
|
|
});
|
|
}
|
|
|
|
return sections;
|
|
}
|
|
|
|
const baseSections = parseSections(basePath);
|
|
const currentSections = parseSections(currentPath);
|
|
let orderingIsValid = true;
|
|
|
|
const sortedEntries = currentSections.get(SORTED_SECTION) ?? [];
|
|
for (let index = 1; index < sortedEntries.length; index += 1) {
|
|
if (sortedEntries[index - 1].sortKey > sortedEntries[index].sortKey) {
|
|
orderingIsValid = false;
|
|
}
|
|
}
|
|
|
|
for (const [section, currentEntries] of currentSections) {
|
|
if (section === SORTED_SECTION || IGNORED_SECTIONS.has(section)) {
|
|
continue;
|
|
}
|
|
|
|
const baseEntries = baseSections.get(section) ?? [];
|
|
if (baseEntries.length === 0) {
|
|
continue;
|
|
}
|
|
|
|
const isExisting = (entry) =>
|
|
baseEntries.some(
|
|
(baseEntry) =>
|
|
baseEntry.url === entry.url || baseEntry.sortKey === entry.sortKey,
|
|
);
|
|
|
|
let foundNewEntry = false;
|
|
for (const entry of currentEntries) {
|
|
const entryAlreadyExists = isExisting(entry);
|
|
if (entryAlreadyExists && foundNewEntry) {
|
|
orderingIsValid = false;
|
|
} else if (!entryAlreadyExists) {
|
|
foundNewEntry = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!orderingIsValid) {
|
|
const message = "Thanks for contributing! Please move your new entry to follow the ordering rules in CONTRIBUTING.md, then update this pull request.";
|
|
console.error(`::error file=${currentPath},title=README entry order::${message}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log("README entries follow the required ordering.");
|