feat: dead-config sweep, test suite foundation, widget settingsSchema validation
Some checks failed
Architecture Governance / architecture (push) Has been cancelled

Sprint G: audited every BootstrapConfig field for a real runtime consumer
(docs/DEAD-CONFIG-AUDIT.md). Wired 3 previously-dead editable fields:
footer.logoUrl, company.address.street/contacts.phone, catalog.suggestionsEnabled.
Remaining dead fields needing a business/design decision tracked in
PRODUCT_BACKLOG.md/KNOWN-ISSUES.md, not silently left.

Sprint H: 6 new spec files (test count 57 -> 83), covering ProjectEditorFacade
(undo/redo, draft persistence, publish gating), AdminAnalyticsFacade
(never-fabricate-a-number contract), and regression coverage for this
session's carousel/hero/profile-toggle fixes.

Sprint I: widget settingsSchema (declared in widget-manifest.json, never
validated) now enforced via a new lightweight schema check in
ProjectValidator, surfaced through the existing issuesByField pipeline.
Same check reused in diagnostics so editor and diagnostics can't disagree.

Verification: tsc clean, ng build clean, 83/83 tests pass, barry-cache
validate clean (2 pre-existing unrelated warnings only).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
sdarbinyan
2026-08-05 20:47:13 +04:00
parent 6f9401fa8f
commit ce63931bc2
25 changed files with 814 additions and 25 deletions

View File

@@ -1,6 +1,7 @@
import { TranslateService } from '../../../i18n/translate.service';
import { BootstrapConfig } from '../../../shared/models/config';
import { WidgetManifestFile } from '../../../widgets/contracts/widget-manifest.contract';
import { validateAgainstSchemaLite } from '../../project-editor/schema/validators/primitives';
import { DiagnosticEntry } from '../models/diagnostics.model';
const KNOWN_LAYOUTS = new Set(['default', 'sidebar-left', 'carousel-home', 'minimal']);
@@ -28,6 +29,7 @@ export class BootstrapDiagnosticsValidator {
this.validateRequiredProperties(bootstrap, entries);
this.validateUnknownWidgetTypes(bootstrap, manifest, entries);
this.validateWidgetSettingsSchema(bootstrap, manifest, entries);
this.validateDuplicateIds(bootstrap, entries);
this.validateLayouts(bootstrap, entries);
this.validateFeatureFlags(bootstrap, entries);
@@ -85,6 +87,36 @@ export class BootstrapDiagnosticsValidator {
}
}
/**
* Reuses the same shallow schema check as ProjectValidator.widgetSettingsSchemaIssues
* (`validateAgainstSchemaLite`) so the editor and the diagnostics page never
* disagree about what "valid widget settings" means - one check, two surfaces.
*/
private validateWidgetSettingsSchema(bootstrap: BootstrapConfig, manifest: WidgetManifestFile | null, entries: DiagnosticEntry[]): void {
const manifestByType = new Map((manifest?.widgets ?? []).map(widget => [widget.type, widget]));
for (const page of bootstrap.pages ?? []) {
for (const section of page.sections ?? []) {
for (const widget of section.widgets ?? []) {
const entry = manifestByType.get(widget.type);
if (!entry?.settingsSchema || !widget.props || typeof widget.props !== 'object') {
continue;
}
const errors = validateAgainstSchemaLite(widget.props, entry.settingsSchema);
if (errors.length > 0) {
entries.push({
code: 'BOOTSTRAP_WIDGET_SETTINGS_SCHEMA_MISMATCH',
severity: 'warning',
title: 'diagnostics.widgetSettingsSchemaMismatchTitle',
description: `diagnostics.widgetSettingsSchemaMismatchDescription:${widget.type}(${errors.join(', ')})`,
affectedComponent: `page:${page.key}/section:${section.id}/widget:${widget.id}`,
suggestedResolution: 'diagnostics.widgetSettingsSchemaMismatchResolution'
});
}
}
}
}
}
private validateDuplicateIds(bootstrap: BootstrapConfig, entries: DiagnosticEntry[]): void {
const pageIds = new Set<string>();