@beignet/core
Version:
Core framework primitives for Beignet
340 lines • 13 kB
JavaScript
/**
* 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