Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .bumpy/decorator-error-once.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"varlock": patch
---

An error from a decorator's value (for example `@required=forEnv(prod)` when the current environment is not set) is reported once instead of twice
5 changes: 4 additions & 1 deletion packages/varlock/src/env-graph/lib/decorators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,11 @@ export abstract class DecoratorInstance {

resolvedValue?: any;
isResolved = false;
/** set when resolving threw, so a later call does not run the resolver and record the same error again */
private resolveFailed = false;

async resolve() {
if (this.isResolved) return this.resolvedValue;
if (this.isResolved || this.resolveFailed) return this.resolvedValue;

await this.process();
// decorators that skip value-resolver creation (see process()) have nothing to resolve
Expand All @@ -229,6 +231,7 @@ export abstract class DecoratorInstance {
this.resolvedValue = await this.decValueResolver.resolve();
} catch (err) {
this._errors.push(err as any);
this.resolveFailed = true;
return;
}

Expand Down
24 changes: 24 additions & 0 deletions packages/varlock/src/env-graph/test/decorator-error-once.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { describe, it, expect } from 'vitest';
import outdent from 'outdent';
import { EnvGraph } from '../index';
import { DotEnvFileDataSource } from '../lib/data-source';

describe('a decorator whose resolver throws', () => {
it('reports the error once', async () => {
const g = new EnvGraph();
await g.setRootDataSource(new DotEnvFileDataSource('.env.schema', {
overrideContents: outdent`
# @currentEnv=$APP_ENV
# @defaultRequired=false
# ---
# @type=enum(dev, prod)
APP_ENV=
# @required=forEnv(prod)
API_URL=
`,
}));
await g.finishLoad();
await g.resolveEnvValues();
expect(g.configSchema.API_URL.errors.map((e) => e.message)).toEqual(['forEnv(): current environment is not set']);
});
});
Loading