From ee80f3f0f9ed3f90b8c510ac5d02b63a28bd77a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Tue, 14 Apr 2026 14:07:23 +0200 Subject: [PATCH] Improve schema validation errors and clean up review fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Use superRefine in jsonSchemaSchema to preserve the detailed error message from validateMetaSchema instead of swallowing it - Revert CatalogModelSources to silent dedup with uniqBy since user layers intentionally take precedence over the default model - Clean up unnecessary `as void` cast in ModelHolder iterator cleanup Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Fredrik Adelöw --- .../catalog-model/src/model/jsonSchema/zod.ts | 15 ++++++++----- .../src/model/sources/CatalogModelSources.ts | 22 +++++-------------- .../catalog-backend/src/model/ModelHolder.ts | 2 +- 3 files changed, 16 insertions(+), 23 deletions(-) diff --git a/packages/catalog-model/src/model/jsonSchema/zod.ts b/packages/catalog-model/src/model/jsonSchema/zod.ts index ea82263cac..61135f1b04 100644 --- a/packages/catalog-model/src/model/jsonSchema/zod.ts +++ b/packages/catalog-model/src/model/jsonSchema/zod.ts @@ -25,13 +25,16 @@ export const jsonObjectSchema = z message: 'Invalid JSON schema', }); -export const jsonSchemaSchema = z.record(z.string(), z.unknown()).refine( - (x): x is JsonObject => { +export const jsonSchemaSchema = z + .record(z.string(), z.unknown()) + .superRefine((x, ctx): x is JsonObject => { try { return validateMetaSchema(x); - } catch { + } catch (error) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: error instanceof Error ? error.message : 'Invalid JSON schema', + }); return false; } - }, - { message: 'Invalid JSON schema' }, -); + }); diff --git a/packages/catalog-model/src/model/sources/CatalogModelSources.ts b/packages/catalog-model/src/model/sources/CatalogModelSources.ts index 6c021be5e4..114e4ae376 100644 --- a/packages/catalog-model/src/model/sources/CatalogModelSources.ts +++ b/packages/catalog-model/src/model/sources/CatalogModelSources.ts @@ -19,6 +19,7 @@ import { defaultCatalogEntityModel } from '../defaultCatalogEntityModel'; import { StaticCatalogModelSource } from './StaticCatalogModelSource'; import { CatalogModelSource } from './types'; import { CatalogModelLayer } from '../types'; +import uniqBy from 'lodash/uniqBy'; /** * A helper for creating common catalog model sources. @@ -35,24 +36,13 @@ export class CatalogModelSources { /** * Provides a static catalog model on top of the default one (which is - * included automatically). + * included automatically). User-provided layers take precedence over the + * default model when layer IDs overlap. */ static static(layers: CatalogModelLayer[]): CatalogModelSource { - const allLayers = [...layers, defaultCatalogEntityModel]; - const seen = new Set(); - const deduped: CatalogModelLayer[] = []; - for (const layer of allLayers) { - if (seen.has(layer.layerId)) { - // eslint-disable-next-line no-console - console.warn( - `Duplicate catalog model layer ID "${layer.layerId}" detected; only the first occurrence will be used`, - ); - } else { - seen.add(layer.layerId); - deduped.push(layer); - } - } - return new StaticCatalogModelSource(deduped); + return new StaticCatalogModelSource( + uniqBy([...layers, defaultCatalogEntityModel], 'layerId'), + ); } private constructor() { diff --git a/plugins/catalog-backend/src/model/ModelHolder.ts b/plugins/catalog-backend/src/model/ModelHolder.ts index 146ef59f85..96b2de46dc 100644 --- a/plugins/catalog-backend/src/model/ModelHolder.ts +++ b/plugins/catalog-backend/src/model/ModelHolder.ts @@ -68,7 +68,7 @@ export class ModelHolder { } return ls; } finally { - await iter.return(undefined as void); + await iter.return(undefined); } }), );