2026-02-26 11:19:47 +01:00
|
|
|
#!/usr/bin/env node
|
|
|
|
|
// Copyright (C) 2026 Whiterun LLC,
|
|
|
|
|
// This software is licensed under the GNU Lesser General Public License (LGPL), version 3.0 or later.
|
|
|
|
|
// A copy of the license can be found in the LICENSE file or at https://www.gnu.org/licenses/lgpl-3.0.html
|
|
|
|
|
|
|
|
|
|
import { readFileSync, readdirSync, statSync } from "node:fs";
|
|
|
|
|
import { join, dirname, relative } from "node:path";
|
|
|
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
|
|
|
|
|
|
const OUR_DIR = dirname(fileURLToPath(import.meta.url));
|
|
|
|
|
const ROOT = join(OUR_DIR, "..");
|
|
|
|
|
|
|
|
|
|
const REQUIRED_LINES = [
|
|
|
|
|
"This software is licensed under the GNU Lesser General Public License (LGPL), version 3.0 or later.",
|
|
|
|
|
"A copy of the license can be found in the LICENSE file or at https://www.gnu.org/licenses/lgpl-3.0.html",
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// Matches: "Copyright (C) 2026 Whiterun LLC" or "Copyright (C) 2024-2026 Whiterun LLC"
|
|
|
|
|
const COPYRIGHT_PATTERN = /Copyright \(C\) (\d{4}-)?\d{4} Whiterun LLC/;
|
|
|
|
|
|
2026-03-18 16:13:38 +01:00
|
|
|
const EXTENSIONS = [".ts", ".tsx", ".mjs"];
|
2026-02-26 11:19:47 +01:00
|
|
|
const DIRECTORIES = ["packages", "linters"];
|
|
|
|
|
|
|
|
|
|
function walk(dir) {
|
|
|
|
|
const results = [];
|
|
|
|
|
for (const entry of readdirSync(dir)) {
|
|
|
|
|
const full = join(dir, entry);
|
|
|
|
|
const stat = statSync(full);
|
|
|
|
|
if (stat.isDirectory()) {
|
|
|
|
|
if (entry === "node_modules" || entry === "dist") continue;
|
|
|
|
|
results.push(...walk(full));
|
|
|
|
|
} else if (EXTENSIONS.some((ext) => entry.endsWith(ext))) {
|
|
|
|
|
results.push(full);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return results;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let missing = 0;
|
|
|
|
|
|
|
|
|
|
for (const directory of DIRECTORIES) {
|
|
|
|
|
const dirPath = join(ROOT, directory);
|
|
|
|
|
for (const filePath of walk(dirPath)) {
|
|
|
|
|
const content = readFileSync(filePath, "utf-8");
|
|
|
|
|
const hasRequired = REQUIRED_LINES.every((line) => content.includes(line));
|
|
|
|
|
const hasCopyright = COPYRIGHT_PATTERN.test(content);
|
|
|
|
|
if (!hasRequired || !hasCopyright) {
|
|
|
|
|
console.log(`${relative(ROOT, filePath)}: Missing`);
|
|
|
|
|
missing++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (missing) {
|
|
|
|
|
console.log(`${missing} file(s) are missing copyright headers`);
|
|
|
|
|
process.exit(1);
|
|
|
|
|
} else {
|
|
|
|
|
console.log("OK");
|
|
|
|
|
}
|