Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 30 additions & 12 deletions scripts/validate-plugins.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,23 @@ import addFormats from "ajv-formats";
const __dirname = dirname(fileURLToPath(import.meta.url));
const root = resolve(__dirname, "..");

function loadJSON(path) {
return JSON.parse(readFileSync(path, "utf-8"));
function safeLoadJSON(path) {
try {
return { data: JSON.parse(readFileSync(path, "utf-8")), error: null };
} catch (err) {
return { data: null, error: err.message };
}
Comment on lines +15 to +17
}

const marketplaceSchema = loadJSON(
const marketplaceSchema = safeLoadJSON(
resolve(root, "schemas/marketplace.schema.json")
);
const pluginSchema = loadJSON(resolve(root, "schemas/plugin.schema.json"));
).data;
const pluginSchema = safeLoadJSON(
resolve(root, "schemas/plugin.schema.json")
).data;
Comment on lines +20 to +25

const ajv = new Ajv({ allErrors: true });
addFormats(ajv);
(addFormats.default || addFormats)(ajv);

const validateMarketplace = ajv.compile(marketplaceSchema);
const validatePlugin = ajv.compile(pluginSchema);
Expand All @@ -39,17 +45,22 @@ if (!existsSync(marketplacePath)) {
process.exit(1);
}

const marketplace = loadJSON(marketplacePath);
const { data: marketplace, error: marketplaceJsonError } = safeLoadJSON(marketplacePath);

if (marketplaceJsonError) {
fail(`marketplace.json is invalid JSON: ${marketplaceJsonError}`);
process.exit(1);
}
Comment on lines +50 to +53

if (!validateMarketplace(marketplace)) {
fail("marketplace.json schema validation failed:");
for (const err of validateMarketplace.errors) {
for (const err of validateMarketplace.errors ?? []) {
console.error(` ${err.instancePath || "/"}: ${err.message}`);
}
}

// 2. Validate each plugin
for (const entry of marketplace.plugins ?? []) {
for (const entry of marketplace?.plugins ?? []) {
const pluginDir = resolve(root, entry.source);
const pluginJsonPath = resolve(pluginDir, ".cursor-plugin/plugin.json");

Expand All @@ -69,13 +80,20 @@ for (const entry of marketplace.plugins ?? []) {
continue;
}

const pluginJson = loadJSON(pluginJsonPath);
const { data: pluginJson, error: pluginJsonError } = safeLoadJSON(pluginJsonPath);

if (pluginJsonError) {
fail(
`Plugin "${entry.name}": malformed JSON in ${entry.source}/.cursor-plugin/plugin.json (${pluginJsonError})`
);
continue;
}

if (!validatePlugin(pluginJson)) {
fail(
`Plugin "${entry.name}": plugin.json schema validation failed (${entry.source}/.cursor-plugin/plugin.json):`
);
for (const err of validatePlugin.errors) {
for (const err of validatePlugin.errors ?? []) {
const detail =
err.keyword === "additionalProperties"
? `${err.message}: "${err.params.additionalProperty}"`
Expand All @@ -85,7 +103,7 @@ for (const entry of marketplace.plugins ?? []) {
}

// Check that marketplace name matches plugin name
if (pluginJson.name && pluginJson.name !== entry.name) {
if (pluginJson?.name && pluginJson.name !== entry.name) {
fail(
`Plugin "${entry.name}": marketplace name does not match plugin.json name "${pluginJson.name}"`
);
Expand Down