UNPKG

@beignet/core

Version:

Core framework primitives for Beignet

340 lines 13 kB
/** * Static provider package metadata declared in package.json under * `beignet.provider`. * * This metadata is for docs and tooling. It must stay side-effect-free and * does not change provider setup, ordering, or runtime port merging behavior. */ export function parseProviderPackageMetadata(input) { if (!isRecord(input)) { return { success: false, issues: [ { path: "beignet.provider", message: "must be an object", }, ], }; } const issues = []; const metadata = {}; if (input.displayName !== undefined) { if (typeof input.displayName !== "string") { issues.push({ path: "beignet.provider.displayName", message: "must be a string", }); } else { metadata.displayName = input.displayName; } } const ports = parseStringArray(input.ports, "beignet.provider.ports", issues); if (ports !== undefined) metadata.ports = ports; const env = parseStringArray(input.env, "beignet.provider.env", issues); if (env !== undefined) metadata.env = env; const requiredEnv = parseStringArray(input.requiredEnv, "beignet.provider.requiredEnv", issues); if (requiredEnv !== undefined) { metadata.requiredEnv = requiredEnv; validateRequiredEnvMembers(requiredEnv, env, "beignet.provider.requiredEnv", "beignet.provider.env", issues); } const requiredEnvAlternatives = parseStringArrayArray(input.requiredEnvAlternatives, "beignet.provider.requiredEnvAlternatives", issues); if (requiredEnvAlternatives !== undefined) { metadata.requiredEnvAlternatives = requiredEnvAlternatives; for (const alternative of requiredEnvAlternatives) { validateRequiredEnvMembers(alternative, env, "beignet.provider.requiredEnvAlternatives", "beignet.provider.env", issues); } } if (input.requiredEnv !== undefined && input.requiredEnvAlternatives !== undefined) { issues.push({ path: "beignet.provider.requiredEnvAlternatives", message: "must not be set alongside beignet.provider.requiredEnv", }); } const requiredTables = parseStringArray(input.requiredTables, "beignet.provider.requiredTables", issues); if (requiredTables !== undefined) metadata.requiredTables = requiredTables; const watchers = parseStringArray(input.watchers, "beignet.provider.watchers", issues); if (watchers !== undefined) metadata.watchers = watchers; const appPorts = parseAppPorts(input.appPorts, issues); if (appPorts !== undefined) metadata.appPorts = appPorts; const registration = parseRegistration(input.registration, issues, "beignet.provider.registration"); if (registration !== undefined) metadata.registration = registration; const variants = parseVariants(input.variants, issues); if (variants !== undefined) metadata.variants = variants; if (input.variants !== undefined) { if (input.requiredEnv !== undefined) { issues.push({ path: "beignet.provider.requiredEnv", message: "must not be set when beignet.provider.variants is present; declare requiredEnv on each variant instead", }); } if (input.requiredEnvAlternatives !== undefined) { issues.push({ path: "beignet.provider.requiredEnvAlternatives", message: "must not be set when beignet.provider.variants is present; declare requiredEnvAlternatives on each variant instead", }); } if (input.registration !== undefined) { issues.push({ path: "beignet.provider.registration", message: "must not be set when beignet.provider.variants is present; declare registration on each variant instead", }); } if (input.requiredTables !== undefined) { issues.push({ path: "beignet.provider.requiredTables", message: "must not be set when beignet.provider.variants is present; declare requiredTables on each variant instead", }); } } if (issues.length > 0) { return { success: false, issues }; } return { success: true, metadata }; } function parseStringArray(value, path, issues) { if (value === undefined) return undefined; if (!Array.isArray(value)) { issues.push({ path, message: "must be an array of strings" }); return undefined; } const parsed = []; for (const [index, entry] of value.entries()) { if (typeof entry !== "string") { issues.push({ path: `${path}[${index}]`, message: "must be a string", }); continue; } parsed.push(entry); } return parsed; } function parseStringArrayArray(value, path, issues) { if (value === undefined) return undefined; if (!Array.isArray(value)) { issues.push({ path, message: "must be an array of string arrays" }); return undefined; } if (value.length === 0) { issues.push({ path, message: "must include at least one alternative when present", }); return undefined; } const parsed = []; for (const [index, entry] of value.entries()) { const entryPath = `${path}[${index}]`; const alternative = parseStringArray(entry, entryPath, issues); if (alternative === undefined) continue; if (alternative.length === 0) { issues.push({ path: entryPath, message: "must include at least one environment variable", }); continue; } parsed.push(alternative); } return parsed; } function validateRequiredEnvMembers(requiredEnv, env, path, envPath, issues) { const envSet = new Set(env ?? []); for (const envVar of requiredEnv) { if (!envSet.has(envVar)) { issues.push({ path, message: `${envVar} must also be listed in ${envPath}`, }); } } } function parseAppPorts(value, issues) { if (value === undefined) return undefined; const path = "beignet.provider.appPorts"; if (!Array.isArray(value)) { issues.push({ path, message: "must be an array of port metadata objects" }); return undefined; } const parsed = []; for (const [index, entry] of value.entries()) { const entryPath = `${path}[${index}]`; if (!isRecord(entry)) { issues.push({ path: entryPath, message: "must be an object" }); continue; } if (typeof entry.name !== "string") { issues.push({ path: `${entryPath}.name`, message: "must be a string" }); } if (typeof entry.type !== "string") { issues.push({ path: `${entryPath}.type`, message: "must be a string" }); } if (typeof entry.name === "string" && typeof entry.type === "string") { parsed.push({ name: entry.name, type: entry.type }); } } return parsed; } function parseVariants(value, issues) { if (value === undefined) return undefined; const path = "beignet.provider.variants"; if (!Array.isArray(value)) { issues.push({ path, message: "must be an array of variant objects" }); return undefined; } if (value.length === 0) { issues.push({ path, message: "must include at least one variant when present", }); return undefined; } const parsed = []; const seenNames = new Set(); for (const [index, entry] of value.entries()) { const entryPath = `${path}[${index}]`; if (!isRecord(entry)) { issues.push({ path: entryPath, message: "must be an object" }); continue; } let name; if (typeof entry.name !== "string" || entry.name.length === 0) { issues.push({ path: `${entryPath}.name`, message: "must be a non-empty string", }); } else if (seenNames.has(entry.name)) { issues.push({ path: `${entryPath}.name`, message: `duplicates variant name "${entry.name}"`, }); } else { seenNames.add(entry.name); name = entry.name; } let displayName; if (entry.displayName !== undefined) { if (typeof entry.displayName !== "string") { issues.push({ path: `${entryPath}.displayName`, message: "must be a string", }); } else { displayName = entry.displayName; } } const env = parseStringArray(entry.env, `${entryPath}.env`, issues); const requiredEnv = parseStringArray(entry.requiredEnv, `${entryPath}.requiredEnv`, issues); if (requiredEnv !== undefined) { validateRequiredEnvMembers(requiredEnv, env, `${entryPath}.requiredEnv`, `${entryPath}.env`, issues); } const requiredEnvAlternatives = parseStringArrayArray(entry.requiredEnvAlternatives, `${entryPath}.requiredEnvAlternatives`, issues); if (requiredEnvAlternatives !== undefined) { for (const alternative of requiredEnvAlternatives) { validateRequiredEnvMembers(alternative, env, `${entryPath}.requiredEnvAlternatives`, `${entryPath}.env`, issues); } } if (entry.requiredEnv !== undefined && entry.requiredEnvAlternatives !== undefined) { issues.push({ path: `${entryPath}.requiredEnvAlternatives`, message: `must not be set alongside ${entryPath}.requiredEnv`, }); } const requiredTables = parseStringArray(entry.requiredTables, `${entryPath}.requiredTables`, issues); const registration = parseRegistration(entry.registration, issues, `${entryPath}.registration`); if (name === undefined) continue; const variant = { name }; if (displayName !== undefined) variant.displayName = displayName; if (env !== undefined) variant.env = env; if (requiredEnv !== undefined) variant.requiredEnv = requiredEnv; if (requiredEnvAlternatives !== undefined) { variant.requiredEnvAlternatives = requiredEnvAlternatives; } if (requiredTables !== undefined) variant.requiredTables = requiredTables; if (registration !== undefined) variant.registration = registration; parsed.push(variant); } return parsed; } function parseRegistration(value, issues, path) { if (value === undefined) return undefined; if (!isRecord(value)) { issues.push({ path, message: "must be an object" }); return undefined; } const registration = {}; if (value.required !== undefined) { if (typeof value.required !== "boolean") { issues.push({ path: `${path}.required`, message: "must be a boolean" }); } else { registration.required = value.required; } } if (value.severity !== undefined) { if (value.severity !== "warning" && value.severity !== "hint") { issues.push({ path: `${path}.severity`, message: 'must be "warning" or "hint"', }); } else { registration.severity = value.severity; } } if (registration.required === true && registration.severity === "hint") { issues.push({ path: `${path}.severity`, message: 'must not be "hint" when registration is required', }); } const tokens = parseStringArray(value.tokens, `${path}.tokens`, issues); if (tokens !== undefined) registration.tokens = tokens; if ((tokens?.length ?? 0) === 0) { if (registration.required === true) { issues.push({ path: `${path}.tokens`, message: "must include at least one token when registration is required", }); } else if (registration.severity !== undefined) { issues.push({ path: `${path}.tokens`, message: "must include at least one token when registration severity is set", }); } } return registration; } function isRecord(value) { return typeof value === "object" && value !== null && !Array.isArray(value); } //# sourceMappingURL=metadata.js.map