Skip to content

Commit 7e62083

Browse files
committed
feat(#136): adds named wrapper on 3rd party parsing extensions
1 parent 271c1de commit 7e62083

File tree

8 files changed

+149
-131
lines changed

8 files changed

+149
-131
lines changed

app-config-encryption/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
},
3232
"dependencies": {
3333
"@app-config/core": "^2.4.6",
34+
"@app-config/extension-utils": "^2.4.6",
3435
"@app-config/logging": "^2.4.6",
3536
"@app-config/meta": "^2.4.6",
3637
"@app-config/node": "^2.4.6",

app-config-encryption/src/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { ParsingExtension } from '@app-config/core';
2+
import { named } from '@app-config/extension-utils';
23
import { DecryptedSymmetricKey, decryptValue } from './encryption';
34

45
export * from './encryption';
@@ -7,7 +8,7 @@ export * from './secret-agent-tls';
78

89
/** Decrypts inline encrypted values */
910
export default function encryptedDirective(symmetricKey?: DecryptedSymmetricKey): ParsingExtension {
10-
return (value) => {
11+
return named('encryption', (value) => {
1112
if (typeof value === 'string' && value.startsWith('enc:')) {
1213
return async (parse) => {
1314
const decrypted = await decryptValue(value, symmetricKey);
@@ -17,5 +18,5 @@ export default function encryptedDirective(symmetricKey?: DecryptedSymmetricKey)
1718
}
1819

1920
return false;
20-
};
21+
});
2122
}

app-config-exec/src/index.ts

Lines changed: 56 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Json } from '@app-config/utils';
22
import { ParsingExtension, parseRawString, guessFileType, AppConfigError } from '@app-config/core';
3-
import { forKey, validateOptions } from '@app-config/extension-utils';
3+
import { named, forKey, validateOptions } from '@app-config/extension-utils';
44
import { resolveFilepath } from '@app-config/node';
55
import { exec } from 'child_process';
66
import { promisify } from 'util';
@@ -19,66 +19,69 @@ class ExecError extends AppConfigError {
1919
}
2020

2121
function execParsingExtension(): ParsingExtension {
22-
return forKey(
22+
return named(
2323
'$exec',
24-
validateOptions(
25-
(SchemaBuilder) =>
26-
SchemaBuilder.oneOf(
27-
SchemaBuilder.stringSchema(),
28-
SchemaBuilder.emptySchema()
29-
.addString('command')
30-
.addBoolean('failOnStderr', {}, false)
31-
.addBoolean('parseOutput', {}, false)
32-
.addBoolean('trimWhitespace', {}, false),
33-
),
34-
(value) => async (parse, _, context) => {
35-
let options;
36-
37-
if (typeof value === 'string') {
38-
options = { command: value };
39-
} else {
40-
options = value;
41-
}
42-
43-
const {
44-
command,
45-
failOnStderr = false,
46-
parseOutput = false,
47-
trimWhitespace = true,
48-
} = options;
49-
50-
try {
51-
const dir = resolveFilepath(context, '.');
52-
const { stdout, stderr } = await execAsync(command, { cwd: dir });
53-
54-
if (failOnStderr && stderr) {
55-
throw new ExecError(`$exec command "${command}" produced stderr: ${stderr}`);
24+
forKey(
25+
'$exec',
26+
validateOptions(
27+
(SchemaBuilder) =>
28+
SchemaBuilder.oneOf(
29+
SchemaBuilder.stringSchema(),
30+
SchemaBuilder.emptySchema()
31+
.addString('command')
32+
.addBoolean('failOnStderr', {}, false)
33+
.addBoolean('parseOutput', {}, false)
34+
.addBoolean('trimWhitespace', {}, false),
35+
),
36+
(value) => async (parse, _, context) => {
37+
let options;
38+
39+
if (typeof value === 'string') {
40+
options = { command: value };
41+
} else {
42+
options = value;
5643
}
5744

58-
let result: Json = stdout;
45+
const {
46+
command,
47+
failOnStderr = false,
48+
parseOutput = false,
49+
trimWhitespace = true,
50+
} = options;
5951

60-
if (trimWhitespace) {
61-
result = stdout.trim();
62-
}
52+
try {
53+
const dir = resolveFilepath(context, '.');
54+
const { stdout, stderr } = await execAsync(command, { cwd: dir });
6355

64-
if (parseOutput) {
65-
const fileType = await guessFileType(stdout);
66-
result = await parseRawString(stdout, fileType);
67-
}
56+
if (failOnStderr && stderr) {
57+
throw new ExecError(`$exec command "${command}" produced stderr: ${stderr}`);
58+
}
6859

69-
return parse(result, { shouldFlatten: true });
70-
} catch (err: unknown) {
71-
if (!isError(err)) {
72-
throw err;
73-
}
60+
let result: Json = stdout;
7461

75-
if (err instanceof ExecError) {
76-
throw err;
77-
}
62+
if (trimWhitespace) {
63+
result = stdout.trim();
64+
}
7865

79-
throw new ExecError(`$exec command "${command}" failed with error:\n${err.message}`);
80-
}
81-
},
66+
if (parseOutput) {
67+
const fileType = await guessFileType(stdout);
68+
result = await parseRawString(stdout, fileType);
69+
}
70+
71+
return parse(result, { shouldFlatten: true });
72+
} catch (err: unknown) {
73+
if (!isError(err)) {
74+
throw err;
75+
}
76+
77+
if (err instanceof ExecError) {
78+
throw err;
79+
}
80+
81+
throw new ExecError(`$exec command "${command}" failed with error:\n${err.message}`);
82+
}
83+
},
84+
),
8285
),
8386
);
8487
}

app-config-git/src/index.ts

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,51 @@
11
import simpleGit from 'simple-git';
22
import { ParsingExtension, AppConfigError, Fallbackable } from '@app-config/core';
3-
import { forKey, validateOptions } from '@app-config/extension-utils';
3+
import { named, forKey, validateOptions } from '@app-config/extension-utils';
44

55
class GitError extends Fallbackable {}
66

77
/** Access to the git branch and commit ref */
88
export default function gitRefDirectives(
99
getStatus: typeof gitStatus = gitStatus,
1010
): ParsingExtension {
11-
return forKey(
11+
return named(
1212
'$git',
13-
validateOptions(
14-
(SchemaBuilder) => SchemaBuilder.stringSchema(),
15-
(value) => async (parse) => {
16-
switch (value) {
17-
case 'commit':
18-
return getStatus().then(({ commitRef }) => parse(commitRef, { shouldFlatten: true }));
13+
forKey(
14+
'$git',
15+
validateOptions(
16+
(SchemaBuilder) => SchemaBuilder.stringSchema(),
17+
(value) => async (parse) => {
18+
switch (value) {
19+
case 'commit':
20+
return getStatus().then(({ commitRef }) => parse(commitRef, { shouldFlatten: true }));
1921

20-
case 'commitShort':
21-
return getStatus().then(({ commitRef }) =>
22-
parse(commitRef.slice(0, 7), { shouldFlatten: true }),
23-
);
22+
case 'commitShort':
23+
return getStatus().then(({ commitRef }) =>
24+
parse(commitRef.slice(0, 7), { shouldFlatten: true }),
25+
);
2426

25-
case 'branch':
26-
case 'branchName':
27-
return getStatus().then(({ branchName }) => {
28-
if (!branchName) {
29-
throw new AppConfigError(
30-
'The $git directive tried to retrieve branchname, but it appears no branch is checked out',
31-
);
32-
}
27+
case 'branch':
28+
case 'branchName':
29+
return getStatus().then(({ branchName }) => {
30+
if (!branchName) {
31+
throw new AppConfigError(
32+
'The $git directive tried to retrieve branchname, but it appears no branch is checked out',
33+
);
34+
}
3335

34-
return parse(branchName, { shouldFlatten: true });
35-
});
36+
return parse(branchName, { shouldFlatten: true });
37+
});
3638

37-
case 'tag':
38-
return getStatus().then(({ tag }) => {
39-
return parse(tag ?? null, { shouldFlatten: true });
40-
});
39+
case 'tag':
40+
return getStatus().then(({ tag }) => {
41+
return parse(tag ?? null, { shouldFlatten: true });
42+
});
4143

42-
default:
43-
throw new AppConfigError('$git directive was not passed a valid option');
44-
}
45-
},
44+
default:
45+
throw new AppConfigError('$git directive was not passed a valid option');
46+
}
47+
},
48+
),
4649
),
4750
);
4851
}

app-config-js/src/index.ts

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,38 @@
11
import { ParsingExtension } from '@app-config/core';
2-
import { forKey, validateOptions } from '@app-config/extension-utils';
2+
import { named, forKey, validateOptions } from '@app-config/extension-utils';
33
import { resolveFilepath } from '@app-config/node';
44

55
/* eslint-disable @typescript-eslint/no-unsafe-call */
66
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
77
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
88

99
export default function jsModuleDirective(): ParsingExtension {
10-
return forKey(
10+
return named(
1111
'$jsModule',
12-
validateOptions(
13-
(SchemaBuilder) => SchemaBuilder.stringSchema(),
14-
(value) => async (parse, _, context) => {
15-
const resolvedPath = resolveFilepath(context, value);
12+
forKey(
13+
'$jsModule',
14+
validateOptions(
15+
(SchemaBuilder) => SchemaBuilder.stringSchema(),
16+
(value) => async (parse, _, context) => {
17+
const resolvedPath = resolveFilepath(context, value);
1618

17-
let loaded: any = await import(resolvedPath);
19+
let loaded: any = await import(resolvedPath);
1820

19-
if (!loaded) {
20-
return parse(loaded, { shouldFlatten: true });
21-
}
21+
if (!loaded) {
22+
return parse(loaded, { shouldFlatten: true });
23+
}
2224

23-
if ('default' in loaded) {
24-
loaded = loaded.default;
25-
}
25+
if ('default' in loaded) {
26+
loaded = loaded.default;
27+
}
2628

27-
if (typeof loaded === 'function') {
28-
loaded = loaded();
29-
}
29+
if (typeof loaded === 'function') {
30+
loaded = loaded();
31+
}
3032

31-
return parse(loaded, { shouldFlatten: true });
32-
},
33+
return parse(loaded, { shouldFlatten: true });
34+
},
35+
),
3336
),
3437
);
3538
}

app-config-v1-compat/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
},
3232
"dependencies": {
3333
"@app-config/core": "^2.4.6",
34+
"@app-config/extension-utils": "^2.4.6",
3435
"@app-config/logging": "^2.4.6",
3536
"@app-config/node": "^2.4.6",
3637
"@app-config/utils": "^2.4.6",

app-config-v1-compat/src/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import { join, dirname, extname } from 'path';
22
import { pathExists } from 'fs-extra';
33
import { isObject } from '@app-config/utils';
4+
import { named } from '@app-config/extension-utils';
45
import { ParsingExtension, Root } from '@app-config/core';
56
import { FileSource } from '@app-config/node';
67
import { logger } from '@app-config/logging';
78

89
/** V1 app-config compatibility */
910
export default function v1Compat(): ParsingExtension {
10-
return (value, [_, key], context) => {
11+
return named('v1-compat', (value, [_, key], context) => {
1112
// only apply in top-level app-config property
1213
if (context[context.length - 1]?.[0] !== Root) {
1314
return false;
@@ -97,5 +98,5 @@ export default function v1Compat(): ParsingExtension {
9798
}
9899

99100
return false;
100-
};
101+
});
101102
}

0 commit comments

Comments
 (0)