Gatsby utils that help creating plugins
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Comprehensive plugin options validation system using Joi schemas with async support, detailed error reporting, and Gatsby-specific extensions.
Validates plugin options against a Joi schema with comprehensive error handling and warning support.
/**
* Validates plugin options against a Joi schema
* @param pluginSchema - Joi object schema for validation
* @param pluginOptions - Plugin options to validate
* @param options - Validation configuration options
* @returns Promise with validated value and warnings
*/
function validateOptionsSchema(
pluginSchema: ObjectSchema,
pluginOptions: IPluginInfoOptions,
options: {
validateExternalRules?: boolean;
returnWarnings?: boolean;
} = {
validateExternalRules: true,
returnWarnings: true
}
): Promise<{
value: IPluginInfoOptions;
warning: {
message: string;
details: Array<{
message: string;
path: Array<string>;
type: string;
context: Array<Record<string, unknown>>;
}>;
};
}>;Usage Examples:
import { validateOptionsSchema, Joi } from "gatsby-plugin-utils";
// Define schema
const pluginSchema = Joi.object({
apiKey: Joi.string().required().description("API key for service"),
timeout: Joi.number().min(1000).default(5000).description("Request timeout in ms"),
retries: Joi.number().min(0).max(5).default(3).description("Number of retry attempts"),
enableCache: Joi.boolean().default(true).description("Enable response caching"),
endpoints: Joi.object({
graphql: Joi.string().uri().required(),
rest: Joi.string().uri().optional()
}).required()
});
// Validate options
async function validateMyPluginOptions(pluginOptions) {
try {
const result = await validateOptionsSchema(pluginSchema, pluginOptions, {
validateExternalRules: true,
returnWarnings: true
});
console.log("Validated options:", result.value);
if (result.warning?.details?.length > 0) {
console.warn("Validation warnings:", result.warning.details);
}
return result.value;
} catch (error) {
console.error("Validation failed:", error.details);
throw error;
}
}
// Example plugin options
const pluginOptions = {
apiKey: "sk-1234567890",
timeout: 3000,
endpoints: {
graphql: "https://api.example.com/graphql"
}
};
const validatedOptions = await validateMyPluginOptions(pluginOptions);Utility for testing plugin options schemas in test environments with comprehensive result reporting.
/**
* Tests plugin options schema for validation behavior
* @param pluginSchemaFunction - Function that returns Joi schema
* @param pluginOptions - Options to test against schema
* @returns Promise with detailed test results
*/
function testPluginOptionsSchema(
pluginSchemaFunction: (args: { Joi: PluginOptionsSchemaJoi }) => ObjectSchema,
pluginOptions: IPluginInfoOptions
): Promise<{
errors: Array<string>;
warnings: Array<string>;
isValid: boolean;
hasWarnings: boolean;
}>;Usage Examples:
import { testPluginOptionsSchema } from "gatsby-plugin-utils";
// Test schema function
const pluginSchema = ({ Joi }) =>
Joi.object({
name: Joi.string().required(),
version: Joi.string().pattern(/^\d+\.\d+\.\d+$/),
features: Joi.array().items(Joi.string()).default([])
});
// Test cases
describe("Plugin Options Schema", () => {
it("should validate correct options", async () => {
const { isValid, errors, warnings } = await testPluginOptionsSchema(
pluginSchema,
{
name: "my-plugin",
version: "1.0.0",
features: ["feature-a", "feature-b"]
}
);
expect(isValid).toBe(true);
expect(errors).toHaveLength(0);
});
it("should fail with missing required field", async () => {
const { isValid, errors } = await testPluginOptionsSchema(
pluginSchema,
{
version: "1.0.0"
}
);
expect(isValid).toBe(false);
expect(errors).toContain('"name" is required');
});
it("should warn about unknown fields", async () => {
const { isValid, hasWarnings, warnings } = await testPluginOptionsSchema(
pluginSchema,
{
name: "my-plugin",
version: "1.0.0",
unknownField: "value"
}
);
expect(isValid).toBe(true);
expect(hasWarnings).toBe(true);
expect(warnings).toContain('"unknownField" is not allowed');
});
});interface ValidationOptions {
/**
* Whether to validate external rules (default: true)
*/
validateExternalRules?: boolean;
/**
* Whether to return warnings alongside validation results (default: true)
*/
returnWarnings?: boolean;
}The validation system provides detailed error information for debugging:
try {
await validateOptionsSchema(schema, options);
} catch (validationError) {
// validationError.details contains array of specific validation failures
validationError.details.forEach(detail => {
console.log(`Field: ${detail.path.join('.')}`);
console.log(`Error: ${detail.message}`);
console.log(`Type: ${detail.type}`);
});
}The validation system includes Gatsby-specific Joi extensions:
// Extended Joi with subPlugins validation
const Joi = require("gatsby-plugin-utils").Joi;
const schemaWithSubPlugins = Joi.object({
plugins: Joi.subPlugins().description("Array of sub-plugins")
});
// Validates arrays of plugin references:
// ["plugin-name"] or [{ resolve: "plugin-name", options: {...} }]// gatsby-node.js
const { validateOptionsSchema } = require("gatsby-plugin-utils");
exports.pluginOptionsSchema = ({ Joi }) => {
return Joi.object({
apiToken: Joi.string().required().description("API authentication token"),
apiUrl: Joi.string().uri().default("https://api.example.com"),
cacheTimeout: Joi.number().min(0).default(300000)
});
};
exports.onPreInit = async ({ reporter }, pluginOptions) => {
try {
const schema = exports.pluginOptionsSchema({ Joi: require("gatsby-plugin-utils").Joi });
await validateOptionsSchema(schema, pluginOptions);
reporter.info("Plugin options validated successfully");
} catch (error) {
reporter.panic("Invalid plugin options", error);
}
};