diff --git a/scripts/lib/resolve-catalog.test.ts b/scripts/lib/resolve-catalog.test.ts new file mode 100644 index 00000000000..ae9a2291157 --- /dev/null +++ b/scripts/lib/resolve-catalog.test.ts @@ -0,0 +1,20 @@ +import { assert, it } from "@effect/vitest"; + +import { CatalogDependencyResolutionError, resolveCatalogDependencies } from "./resolve-catalog.ts"; + +it("reports unresolved catalog dependencies with lookup context", () => { + try { + resolveCatalogDependencies({ effect: "catalog:runtime" }, {}, "apps/server"); + assert.fail("Expected catalog resolution to fail."); + } catch (error) { + assert.instanceOf(error, CatalogDependencyResolutionError); + assert.equal(error.workspacePackage, "apps/server"); + assert.equal(error.dependencyName, "effect"); + assert.equal(error.catalogSpec, "catalog:runtime"); + assert.equal(error.catalogKey, "runtime"); + assert.equal( + error.message, + "Unable to resolve 'catalog:runtime' for apps/server dependency 'effect'. Expected key 'runtime' in root workspace catalog.", + ); + } +}); diff --git a/scripts/lib/resolve-catalog.ts b/scripts/lib/resolve-catalog.ts index 597bd06c24f..eb9d4cc78c8 100644 --- a/scripts/lib/resolve-catalog.ts +++ b/scripts/lib/resolve-catalog.ts @@ -1,3 +1,19 @@ +import * as Schema from "effect/Schema"; + +export class CatalogDependencyResolutionError extends Schema.TaggedErrorClass()( + "CatalogDependencyResolutionError", + { + workspacePackage: Schema.String, + dependencyName: Schema.String, + catalogSpec: Schema.String, + catalogKey: Schema.String, + }, +) { + override get message(): string { + return `Unable to resolve '${this.catalogSpec}' for ${this.workspacePackage} dependency '${this.dependencyName}'. Expected key '${this.catalogKey}' in root workspace catalog.`; + } +} + /** * Resolve `catalog:` dependency specs using the workspace catalog. * @@ -7,7 +23,7 @@ export function resolveCatalogDependencies( dependencies: Record, catalog: Record, - label: string, + workspacePackage: string, ): Record { return Object.fromEntries( Object.entries(dependencies).map(([name, spec]) => { @@ -20,9 +36,12 @@ export function resolveCatalogDependencies( const resolved = catalog[lookupKey]; if (typeof resolved !== "string" || resolved.length === 0) { - throw new Error( - `Unable to resolve '${spec}' for ${label} dependency '${name}'. Expected key '${lookupKey}' in root workspace catalog.`, - ); + throw new CatalogDependencyResolutionError({ + workspacePackage, + dependencyName: name, + catalogSpec: spec, + catalogKey: lookupKey, + }); } return [name, resolved];