* docs: prepare Vendoo 1.41.2 git-ignore boundary hotfix * fix: track native source modules with root-anchored runtime ignores
48 lines
3.0 KiB
JavaScript
48 lines
3.0 KiB
JavaScript
import { PlatformError } from './errors.mjs';
|
|
|
|
const MODULE_ID = /^vendoo\.[a-z][a-z0-9-]*$/;
|
|
const SEMVER = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
|
|
const CAPABILITY = /^[a-z][a-z0-9-]*(?:\.[a-z][a-z0-9-]*)+$/;
|
|
const TYPES = new Set(['core', 'feature', 'adapter', 'extension-host']);
|
|
const STATUSES = new Set(['native', 'legacy-bridge', 'disabled']);
|
|
|
|
function uniqueStrings(values, label, pattern = CAPABILITY) {
|
|
if (!Array.isArray(values)) throw new PlatformError(`${label} muss ein Array sein.`, { code: 'MODULE_MANIFEST_INVALID' });
|
|
const normalized = values.map(value => String(value || '').trim());
|
|
if (normalized.some(value => !pattern.test(value))) {
|
|
throw new PlatformError(`${label} enthält einen ungültigen Eintrag.`, { code: 'MODULE_MANIFEST_INVALID' });
|
|
}
|
|
if (new Set(normalized).size !== normalized.length) {
|
|
throw new PlatformError(`${label} enthält Duplikate.`, { code: 'MODULE_MANIFEST_INVALID' });
|
|
}
|
|
return normalized;
|
|
}
|
|
|
|
export function validateModuleManifest(manifest) {
|
|
if (!manifest || typeof manifest !== 'object' || Array.isArray(manifest)) {
|
|
throw new PlatformError('Modulmanifest fehlt oder ist ungültig.', { code: 'MODULE_MANIFEST_INVALID' });
|
|
}
|
|
const normalized = {
|
|
schemaVersion: Number(manifest.schemaVersion || 1),
|
|
id: String(manifest.id || '').trim(),
|
|
name: String(manifest.name || '').trim(),
|
|
version: String(manifest.version || '').trim(),
|
|
type: String(manifest.type || '').trim(),
|
|
status: String(manifest.status || 'native').trim(),
|
|
description: String(manifest.description || '').trim(),
|
|
requires: Object.freeze(uniqueStrings(manifest.requires || [], 'requires', MODULE_ID)),
|
|
permissions: Object.freeze(uniqueStrings(manifest.permissions || [], 'permissions')),
|
|
provides: Object.freeze(uniqueStrings(manifest.provides || [], 'provides')),
|
|
consumes: Object.freeze(uniqueStrings(manifest.consumes || [], 'consumes')),
|
|
owns: Object.freeze(uniqueStrings(manifest.owns || [], 'owns')),
|
|
};
|
|
if (normalized.schemaVersion !== 1) throw new PlatformError('Nicht unterstützte Manifestversion.', { code: 'MODULE_MANIFEST_VERSION' });
|
|
if (!MODULE_ID.test(normalized.id)) throw new PlatformError(`Ungültige Modul-ID: ${normalized.id}`, { code: 'MODULE_ID_INVALID' });
|
|
if (!normalized.name) throw new PlatformError(`Modulname fehlt: ${normalized.id}`, { code: 'MODULE_NAME_REQUIRED' });
|
|
if (!SEMVER.test(normalized.version)) throw new PlatformError(`Ungültige Modulversion: ${normalized.id}`, { code: 'MODULE_VERSION_INVALID' });
|
|
if (!TYPES.has(normalized.type)) throw new PlatformError(`Ungültiger Modultyp: ${normalized.id}`, { code: 'MODULE_TYPE_INVALID' });
|
|
if (!STATUSES.has(normalized.status)) throw new PlatformError(`Ungültiger Modulstatus: ${normalized.id}`, { code: 'MODULE_STATUS_INVALID' });
|
|
if (normalized.requires.includes(normalized.id)) throw new PlatformError(`Modul darf sich nicht selbst benötigen: ${normalized.id}`, { code: 'MODULE_SELF_DEPENDENCY' });
|
|
return Object.freeze(normalized);
|
|
}
|