Skip to content

Commit 23a96c8

Browse files
committed
feat: adds @app-config/extension-utils package, simplifying extension logic
1 parent 61b704f commit 23a96c8

File tree

12 files changed

+378
-218
lines changed

12 files changed

+378
-218
lines changed

.github/workflows/publishing.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ jobs:
4646
token: ${{ secrets.NPM_TOKEN }}
4747
access: public
4848
package: ./app-config-encryption/package.json
49+
- uses: JS-DevTools/npm-publish@v1
50+
with:
51+
token: ${{ secrets.NPM_TOKEN }}
52+
access: public
53+
package: ./app-config-extension-utils/package.json
4954
- uses: JS-DevTools/npm-publish@v1
5055
with:
5156
token: ${{ secrets.NPM_TOKEN }}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = require('@lcdev/eslint-config/cwd')(__dirname);

app-config-extension-utils/README.md

Whitespace-only changes.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{
2+
"name": "@app-config/extension-utils",
3+
"description": "Utilities for writing @app-config parsing extensions",
4+
"version": "2.1.5",
5+
"license": "MPL-2.0",
6+
"author": {
7+
"name": "Launchcode",
8+
"email": "[email protected]",
9+
"url": "https://lc.dev"
10+
},
11+
"repository": {
12+
"type": "git",
13+
"url": "https://github.com/launchcodedev/app-config.git"
14+
},
15+
"main": "dist/index.js",
16+
"module": "dist/es/index.js",
17+
"types": "dist/index.d.ts",
18+
"files": [
19+
"/dist",
20+
"!**/*.tsbuildinfo",
21+
"!**/*.test.*"
22+
],
23+
"scripts": {
24+
"build": "tsc -b",
25+
"build:es": "tsc -b tsconfig.es.json",
26+
"clean": "rm -rf dist *.tsbuildinfo",
27+
"lint": "eslint src",
28+
"fix": "eslint --fix src",
29+
"test": "jest",
30+
"prepublishOnly": "yarn clean && yarn build && yarn build:es"
31+
},
32+
"dependencies": {
33+
"@app-config/core": "^2.1.5"
34+
},
35+
"devDependencies": {},
36+
"prettier": "@lcdev/prettier",
37+
"jest": {
38+
"preset": "@lcdev/jest"
39+
}
40+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { LiteralSource } from '@app-config/core';
2+
import { forKey, composeExtensions } from './index';
3+
4+
const foo = forKey('$foo', () => (parse) => parse('foo!'));
5+
const bar = forKey('$bar', () => (parse) => parse('bar!'));
6+
const plusOne = forKey(['+1', '$plusOne'], (value) => (parse) =>
7+
parse((value as number) + 1, { shouldFlatten: true }),
8+
);
9+
10+
describe('forKey', () => {
11+
it('only applies for keys given', async () => {
12+
const source = {
13+
a: {
14+
b: {
15+
$plusOne: 33,
16+
},
17+
c: {
18+
'+1': 1,
19+
},
20+
d: {
21+
$foo: 'bar',
22+
},
23+
},
24+
};
25+
26+
expect(await new LiteralSource(source).readToJSON([foo, bar, plusOne])).toEqual({
27+
a: {
28+
b: 34,
29+
c: 2,
30+
d: {
31+
$foo: 'foo!',
32+
},
33+
},
34+
});
35+
});
36+
});
37+
38+
describe('composeExtensions', () => {
39+
it('combines two extensions', async () => {
40+
const source = {
41+
$foo: 1,
42+
$bar: 2,
43+
};
44+
45+
expect(await new LiteralSource(source).readToJSON([foo, bar])).toEqual({
46+
$foo: 'foo!',
47+
$bar: 'bar!',
48+
});
49+
50+
const combined = composeExtensions([foo, bar]);
51+
52+
expect(await new LiteralSource(source).readToJSON([combined])).toEqual({
53+
$foo: 'foo!',
54+
$bar: 'bar!',
55+
});
56+
});
57+
58+
it('combines two extensions, and applies them in nested properties', async () => {
59+
const source = {
60+
$foo: 1,
61+
a: {
62+
b: {
63+
$bar: 2,
64+
},
65+
},
66+
};
67+
68+
expect(await new LiteralSource(source).readToJSON([foo, bar])).toEqual({
69+
$foo: 'foo!',
70+
a: {
71+
b: {
72+
$bar: 'bar!',
73+
},
74+
},
75+
});
76+
77+
const combined = composeExtensions([foo, bar]);
78+
79+
expect(await new LiteralSource(source).readToJSON([combined])).toEqual({
80+
$foo: 'foo!',
81+
a: {
82+
b: {
83+
$bar: 'bar!',
84+
},
85+
},
86+
});
87+
});
88+
});
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import type { ParsingExtension, ParsingExtensionKey } from '@app-config/core';
2+
import { parseValue, Root } from '@app-config/core';
3+
4+
export function forKey(
5+
key: string | string[],
6+
parsingExtension: ParsingExtension,
7+
): ParsingExtension {
8+
const shouldApply = ([_, k]: ParsingExtensionKey) => {
9+
if (typeof k !== 'string') return false;
10+
11+
if (Array.isArray(key)) {
12+
return key.includes(k);
13+
}
14+
15+
return key === k;
16+
};
17+
18+
return (value, ctxKey, ctx) => {
19+
if (shouldApply(ctxKey)) {
20+
return parsingExtension(value, ctxKey, ctx);
21+
}
22+
23+
return false;
24+
};
25+
}
26+
27+
export function composeExtensions(extensions: ParsingExtension[]): ParsingExtension {
28+
return (value, [k]) => {
29+
if (k !== Root) return false;
30+
31+
return (_, __, source) => parseValue(value, source, extensions, { shouldFlatten: true });
32+
};
33+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"extends": "./tsconfig.json",
3+
"compilerOptions": {
4+
"target": "es2020",
5+
"module": "es2020",
6+
"outDir": "./dist/es"
7+
}
8+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"extends": "@lcdev/tsconfig",
3+
"compilerOptions": {
4+
"rootDir": "./src",
5+
"outDir": "./dist"
6+
},
7+
"include": ["src"],
8+
"exclude": ["node_modules"],
9+
"references": [
10+
{ "path": "../app-config-core" }
11+
]
12+
}

app-config-extensions/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.1.5",
34+
"@app-config/extension-utils": "^2.1.5",
3435
"@app-config/logging": "^2.1.5",
3536
"@app-config/node": "^2.1.5",
3637
"@app-config/utils": "^2.1.5"

0 commit comments

Comments
 (0)