mirror of
https://github.com/anthropics/claude-plugins-official.git
synced 2026-03-16 22:23:07 +00:00
- validate-marketplace.ts: check duplicate names and required fields (name, description, source) per entry, not just valid JSON - remove .github/workflows/test-marketplace-check.js: tested a checkMarketplaceViolations function that doesn't exist in the PR, and was in workflows/ instead of scripts/
78 lines
2.1 KiB
TypeScript
78 lines
2.1 KiB
TypeScript
#!/usr/bin/env bun
|
|
/**
|
|
* Validates marketplace.json: well-formed JSON, plugins array present,
|
|
* each entry has required fields, and no duplicate plugin names.
|
|
*
|
|
* Usage:
|
|
* bun validate-marketplace.ts <path-to-marketplace.json>
|
|
*/
|
|
|
|
import { readFile } from "fs/promises";
|
|
|
|
async function main() {
|
|
const filePath = process.argv[2];
|
|
if (!filePath) {
|
|
console.error("Usage: validate-marketplace.ts <path-to-marketplace.json>");
|
|
process.exit(2);
|
|
}
|
|
|
|
const content = await readFile(filePath, "utf-8");
|
|
|
|
let parsed: unknown;
|
|
try {
|
|
parsed = JSON.parse(content);
|
|
} catch (err) {
|
|
console.error(
|
|
`ERROR: ${filePath} is not valid JSON: ${err instanceof Error ? err.message : err}`
|
|
);
|
|
process.exit(1);
|
|
}
|
|
|
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
console.error(`ERROR: ${filePath} must be a JSON object`);
|
|
process.exit(1);
|
|
}
|
|
|
|
const marketplace = parsed as Record<string, unknown>;
|
|
if (!Array.isArray(marketplace.plugins)) {
|
|
console.error(`ERROR: ${filePath} missing "plugins" array`);
|
|
process.exit(1);
|
|
}
|
|
|
|
const errors: string[] = [];
|
|
const seen = new Set<string>();
|
|
const required = ["name", "description", "source"] as const;
|
|
|
|
marketplace.plugins.forEach((p, i) => {
|
|
if (!p || typeof p !== "object") {
|
|
errors.push(`plugins[${i}]: must be an object`);
|
|
return;
|
|
}
|
|
const entry = p as Record<string, unknown>;
|
|
for (const field of required) {
|
|
if (!entry[field]) {
|
|
errors.push(`plugins[${i}] (${entry.name ?? "?"}): missing required field "${field}"`);
|
|
}
|
|
}
|
|
if (typeof entry.name === "string") {
|
|
if (seen.has(entry.name)) {
|
|
errors.push(`plugins[${i}]: duplicate plugin name "${entry.name}"`);
|
|
}
|
|
seen.add(entry.name);
|
|
}
|
|
});
|
|
|
|
if (errors.length) {
|
|
console.error(`ERROR: ${filePath} has ${errors.length} validation error(s):`);
|
|
for (const e of errors) console.error(` - ${e}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log(`OK: ${marketplace.plugins.length} plugins, no duplicates, all required fields present`);
|
|
}
|
|
|
|
main().catch((err) => {
|
|
console.error("Fatal error:", err);
|
|
process.exit(2);
|
|
});
|