Files
Termix/scripts/validate-plugin-manifest.cjs
T

95 lines
2.3 KiB
JavaScript
Raw Normal View History

+17
2026-09-20 14:56:39 -05:00
/**
2026-10-01 16:20:16 -05:00
* Validates plugin manifests against the SDK contract.
+17
2026-09-20 14:56:39 -05:00
*
2026-10-01 16:20:16 -05:00
* node scripts/validate-plugin-manifest.cjs # every bundled manifest
* node scripts/validate-plugin-manifest.cjs path/to/manifest.json
+17
2026-09-20 14:56:39 -05:00
*
2026-10-01 16:20:16 -05:00
* The rules live in packages/plugin-sdk/src/manifest.ts, which the server
* uses too, so there is one implementation rather than a copy here that
* drifts. This file only finds the manifests and prints the result.
+17
2026-09-20 14:56:39 -05:00
*/
2026-10-01 16:20:16 -05:00
const fs = require("node:fs");
const path = require("node:path");
const { pathToFileURL } = require("node:url");
+17
2026-09-20 14:56:39 -05:00
2026-10-01 16:20:16 -05:00
const root = path.resolve(__dirname, "..");
const sdkEntry = path.join(
root,
"packages",
"plugin-sdk",
"dist",
"manifest.js",
);
+17
2026-09-20 14:56:39 -05:00
2026-10-01 16:20:16 -05:00
async function loadValidator() {
if (!fs.existsSync(sdkEntry)) {
+17
2026-09-20 14:56:39 -05:00
console.error(
2026-10-01 16:20:16 -05:00
`The plugin SDK is not built yet (${path.relative(root, sdkEntry)} is missing).\n` +
`Run: npm run build:sdk`,
+17
2026-09-20 14:56:39 -05:00
);
process.exit(1);
}
2026-10-01 16:20:16 -05:00
return import(pathToFileURL(sdkEntry).href);
}
+17
2026-09-20 14:56:39 -05:00
2026-10-01 16:20:16 -05:00
function bundledManifests() {
const pluginsDir = path.join(root, "plugins");
if (!fs.existsSync(pluginsDir)) return [];
return fs
.readdirSync(pluginsDir, { withFileTypes: true })
.filter((entry) => entry.isDirectory())
.map((entry) => path.join(pluginsDir, entry.name, "manifest.json"))
.filter((file) => fs.existsSync(file));
}
async function main() {
const { parseManifest } = await loadValidator();
const argument = process.argv[2];
const files = argument
? [path.resolve(process.cwd(), argument)]
: bundledManifests();
if (files.length === 0) {
console.log("No plugin manifests found.");
return;
+17
2026-09-20 14:56:39 -05:00
}
2026-10-01 16:20:16 -05:00
let failed = 0;
+17
2026-09-20 14:56:39 -05:00
2026-10-01 16:20:16 -05:00
for (const file of files) {
const relative = path.relative(root, file);
+17
2026-09-20 14:56:39 -05:00
2026-10-01 16:20:16 -05:00
let raw;
try {
raw = JSON.parse(fs.readFileSync(file, "utf8"));
} catch (error) {
console.error(`${relative}: not valid JSON: ${error.message}`);
failed += 1;
continue;
+17
2026-09-20 14:56:39 -05:00
}
2026-10-01 16:20:16 -05:00
const { errors } = parseManifest(raw);
if (errors.length > 0) {
console.error(`${relative}:`);
for (const error of errors) console.error(` - ${error}`);
failed += 1;
continue;
}
console.log(`ok ${relative}`);
+17
2026-09-20 14:56:39 -05:00
}
2026-10-01 16:20:16 -05:00
if (failed > 0) {
console.error(`\n${failed} manifest(s) failed validation.`);
process.exit(1);
}
+17
2026-09-20 14:56:39 -05:00
}
2026-10-01 16:20:16 -05:00
main().catch((error) => {
console.error(error);
process.exit(1);
});