knowhub
Version:
Synchronize AI coding–agent knowledge files (rules, templates, guidelines) across your project.
115 lines • 4.63 kB
JavaScript
import { stat } from "node:fs/promises";
import { resolve } from "node:path";
import { ValidationError, handleNodeError } from "./errors.js";
import { pluginRegistry } from "./plugins/index.js";
const UrlProtocol = {
Http: "http://",
Https: "https://",
};
export function validateResourceSource(resource, resourcePath) {
if (typeof resource.plugin !== "string" || resource.plugin.length === 0) {
throw new ValidationError('Resource must have a "plugin" field with a non-empty string', `${resourcePath}.plugin`);
}
if (!pluginRegistry.has(resource.plugin)) {
const availablePlugins = pluginRegistry.listAvailable();
throw new ValidationError(`Unknown plugin "${resource.plugin}". Available plugins: ${availablePlugins.join(", ")}`, `${resourcePath}.plugin`);
}
if (resource.pluginConfig === undefined) {
throw new ValidationError('Resource must have a "pluginConfig" field', `${resourcePath}.pluginConfig`);
}
}
export function validateOverwrite(overwrite, resourcePath) {
if (overwrite === undefined) {
return true;
}
if (typeof overwrite !== "boolean") {
throw new ValidationError("overwrite must be a boolean", `${resourcePath}.overwrite`);
}
return overwrite;
}
export function validateOutputs(outputs, resourcePath) {
if (!outputs) {
throw new ValidationError('Resource must have "outputs"', `${resourcePath}.outputs`);
}
if (typeof outputs === "string") {
if (outputs.length === 0) {
throw new ValidationError("Output path cannot be empty", `${resourcePath}.outputs`);
}
return [outputs];
}
if (Array.isArray(outputs)) {
if (outputs.length === 0) {
throw new ValidationError("outputs array cannot be empty", `${resourcePath}.outputs`);
}
const validatedOutputs = [];
for (let i = 0; i < outputs.length; i++) {
const output = outputs[i];
if (typeof output !== "string" || output.length === 0) {
throw new ValidationError("Each output must be a non-empty string", `${resourcePath}.outputs[${i}]`);
}
validatedOutputs.push(output);
}
return validatedOutputs;
}
throw new ValidationError("outputs must be a string or array of strings", `${resourcePath}.outputs`);
}
export function validateUrlFormat(url) {
if (!url.startsWith(UrlProtocol.Http) && !url.startsWith(UrlProtocol.Https)) {
throw new ValidationError(`URL must start with ${UrlProtocol.Http} or ${UrlProtocol.Https}, got: ${url}`);
}
try {
new URL(url);
}
catch (error) {
throw new ValidationError(`Invalid URL format: ${url}`);
}
}
export function validateConfigStructure(config, configPath) {
if (!config || typeof config !== "object") {
throw new ValidationError("Configuration must be an object", configPath);
}
const configObj = config;
if (!Array.isArray(configObj.resources)) {
throw new ValidationError('Configuration must have a "resources" array', configPath);
}
if (configObj.resources.length === 0) {
throw new ValidationError("Configuration must have at least one resource", configPath);
}
}
export function validateResourceStructure(resource, resourcePath) {
if (!resource || typeof resource !== "object" || Array.isArray(resource)) {
throw new ValidationError("Resource must be an object", resourcePath);
}
}
export async function validateResource(resource, resourcePath = "resource") {
validateResourceStructure(resource, resourcePath);
validateResourceSource(resource, resourcePath);
const overwrite = validateOverwrite(resource.overwrite, resourcePath);
const outputs = validateOutputs(resource.outputs, resourcePath);
const plugin = pluginRegistry.resolve(resource.plugin);
if (plugin.validate) {
try {
await plugin.validate(resource.pluginConfig);
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
throw new ValidationError(`Plugin validation failed: ${errorMessage}`, `${resourcePath}.pluginConfig`);
}
}
return {
plugin: resource.plugin,
pluginConfig: resource.pluginConfig,
overwrite,
outputs,
};
}
export async function validateLocalPath(path) {
try {
const absolutePath = resolve(path);
await stat(absolutePath);
}
catch (error) {
handleNodeError(error, path, "validate");
}
}
//# sourceMappingURL=validators.js.map