Skip to content

Commit 7850644

Browse files
committed
feat: adds $if directive
1 parent 35af467 commit 7850644

File tree

3 files changed

+121
-7
lines changed

3 files changed

+121
-7
lines changed

app-config-default-extensions/index.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ module.exports = {
1616
const {
1717
unescape$Directives,
1818
tryDirective,
19+
ifDirective,
1920
envDirective,
2021
extendsDirective,
2122
extendsSelfDirective,
@@ -31,6 +32,7 @@ module.exports = {
3132
return [
3233
unescape$Directives(),
3334
tryDirective(),
35+
ifDirective(),
3436
v1Compat(),
3537
envDirective(aliases, environmentOverride, environmentSourceNames),
3638
extendsDirective(),
@@ -43,18 +45,15 @@ module.exports = {
4345
];
4446
},
4547
defaultEnvExtensions() {
46-
const {
47-
unescape$Directives,
48-
tryDirective,
49-
markAllValuesAsSecret,
50-
} = require('@app-config/extensions');
48+
const { unescape$Directives, markAllValuesAsSecret } = require('@app-config/extensions');
5149

52-
return [unescape$Directives(), tryDirective(), markAllValuesAsSecret()];
50+
return [unescape$Directives(), markAllValuesAsSecret()];
5351
},
5452
defaultMetaExtensions() {
5553
const {
5654
unescape$Directives,
5755
tryDirective,
56+
ifDirective,
5857
extendsDirective,
5958
extendsSelfDirective,
6059
overrideDirective,
@@ -63,6 +62,7 @@ module.exports = {
6362
return [
6463
unescape$Directives(),
6564
tryDirective(),
65+
ifDirective(),
6666
extendsDirective(),
6767
extendsSelfDirective(),
6868
overrideDirective(),

app-config-extensions/src/index.test.ts

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { FileSource } from '@app-config/node';
44
import { forKey } from '@app-config/extension-utils';
55
import {
66
tryDirective,
7+
ifDirective,
78
envDirective,
89
extendsDirective,
910
extendsSelfDirective,
@@ -94,6 +95,95 @@ describe('$try directive', () => {
9495
});
9596
});
9697

98+
describe('$if directive', () => {
99+
it('uses main value', async () => {
100+
const source = new LiteralSource({
101+
$if: {
102+
$check: true,
103+
$then: 'foobar',
104+
$else: 'barfoo',
105+
},
106+
});
107+
108+
expect(await source.readToJSON([ifDirective()])).toEqual('foobar');
109+
});
110+
111+
it('uses fallback value', async () => {
112+
const source = new LiteralSource({
113+
$if: {
114+
$check: false,
115+
$then: 'foobar',
116+
$else: 'barfoo',
117+
},
118+
});
119+
120+
expect(await source.readToJSON([ifDirective()])).toEqual('barfoo');
121+
});
122+
123+
it('doesnt evaluate the else branch', async () => {
124+
const failDirective = forKey('$fail', () => () => {
125+
throw new Error();
126+
});
127+
128+
const source = new LiteralSource({
129+
$if: {
130+
$check: true,
131+
$then: 'barfoo',
132+
$else: {
133+
$fail: true,
134+
},
135+
},
136+
});
137+
138+
expect(await source.readToJSON([ifDirective()])).toEqual('barfoo');
139+
});
140+
141+
it('doesnt evaluate the other branch', async () => {
142+
const failDirective = forKey('$fail', () => () => {
143+
throw new Error();
144+
});
145+
146+
const source = new LiteralSource({
147+
$if: {
148+
$check: false,
149+
$then: {
150+
$fail: true,
151+
},
152+
$else: 'barfoo',
153+
},
154+
});
155+
156+
expect(await source.readToJSON([ifDirective()])).toEqual('barfoo');
157+
});
158+
159+
it('disallows missing property', async () => {
160+
const source = new LiteralSource({
161+
$if: {
162+
$check: false,
163+
$else: 'barfoo',
164+
},
165+
});
166+
167+
await expect(source.readToJSON([ifDirective()])).rejects.toThrow();
168+
});
169+
170+
it('parses $check', async () => {
171+
const source = new LiteralSource({
172+
$if: {
173+
$check: {
174+
$env: {
175+
default: true,
176+
},
177+
},
178+
$then: 'foobar',
179+
$else: 'barfoo',
180+
},
181+
});
182+
183+
expect(await source.readToJSON([ifDirective(), envDirective()])).toEqual('foobar');
184+
});
185+
});
186+
97187
describe('$extends directive', () => {
98188
it('fails if file is missing', async () => {
99189
const source = new LiteralSource({

app-config-extensions/src/index.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ export function tryDirective(): ParsingExtension {
5252
.addProperty('$fallback', SchemaBuilder.fromJsonSchema({}))
5353
.addBoolean('$unsafe', {}, false),
5454
(value) => async (parse) => {
55-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
5655
const { $value, $fallback, $unsafe } = value;
5756

5857
try {
@@ -70,6 +69,31 @@ export function tryDirective(): ParsingExtension {
7069
);
7170
}
7271

72+
/** Checks a condition, uses then/else */
73+
export function ifDirective(): ParsingExtension {
74+
return forKey(
75+
'$if',
76+
validateOptions(
77+
(SchemaBuilder) =>
78+
SchemaBuilder.emptySchema()
79+
.addProperty('$check', SchemaBuilder.fromJsonSchema({}))
80+
.addProperty('$then', SchemaBuilder.fromJsonSchema({}))
81+
.addProperty('$else', SchemaBuilder.fromJsonSchema({})),
82+
(value) => async (parse) => {
83+
const { $check, $then, $else } = value;
84+
const condition = (await parse($check)).toJSON();
85+
86+
if (condition) {
87+
return parse($then, { shouldFlatten: true });
88+
} else {
89+
return parse($else, { shouldFlatten: true });
90+
}
91+
},
92+
{ lazy: true },
93+
),
94+
);
95+
}
96+
7397
/** Uses another file as overriding values, layering them on top of current file */
7498
export function overrideDirective(): ParsingExtension {
7599
return fileReferenceDirective('$override', { shouldOverride: true });

0 commit comments

Comments
 (0)