Skip to content

Commit 5913ce5

Browse files
authored
Merge pull request #117 from launchcodedev/app-config-js
Adds $jsModule parsing extension package (@app-config/js)
2 parents 510ecb9 + 610e794 commit 5913ce5

File tree

10 files changed

+222
-0
lines changed

10 files changed

+222
-0
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ jobs:
4141
./app-config-generate/coverage/coverage-final.json,
4242
./app-config-git/coverage/coverage-final.json,
4343
./app-config-inject/coverage/coverage-final.json,
44+
./app-config-js/coverage/coverage-final.json,
4445
./app-config-logging/coverage/coverage-final.json,
4546
./app-config-main/coverage/coverage-final.json,
4647
./app-config-meta/coverage/coverage-final.json,

.github/workflows/publishing.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ jobs:
7676
token: ${{ secrets.NPM_TOKEN }}
7777
access: public
7878
package: ./app-config-inject/package.json
79+
- uses: JS-DevTools/npm-publish@v1
80+
with:
81+
token: ${{ secrets.NPM_TOKEN }}
82+
access: public
83+
package: ./app-config-js/package.json
7984
- uses: JS-DevTools/npm-publish@v1
8085
with:
8186
token: ${{ secrets.NPM_TOKEN }}

app-config-js/.eslintrc.js

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-js/README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
## App Config JS Module Loader
2+
3+
This is a parsing extension to load arbitrary JavaScript code.
4+
5+
Add to meta file:
6+
7+
```yaml
8+
parsingExtensions:
9+
- @app-config/js
10+
```
11+
12+
Use it:
13+
14+
```yaml
15+
foo:
16+
$jsModule: './another-file.js'
17+
```
18+
19+
The API of this module is documented via TypeScript definitions.
20+
21+
Read the [Introduction](https://app-config.dev/guide/intro/) or
22+
[Quick Start](https://app-config.dev/guide/intro/quick-start/) guides on our website.

app-config-js/package.json

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{
2+
"name": "@app-config/js",
3+
"description": "Loads a JavaScript module to inject configuration",
4+
"version": "2.2.0",
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.2.0",
34+
"@app-config/extension-utils": "^2.2.0",
35+
"@app-config/node": "^2.2.0"
36+
},
37+
"devDependencies": {
38+
"@app-config/test-utils": "^2.2.0"
39+
},
40+
"prettier": "@lcdev/prettier",
41+
"jest": {
42+
"preset": "@lcdev/jest"
43+
}
44+
}

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

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { LiteralSource } from '@app-config/core';
2+
import { FileSource } from '@app-config/node';
3+
import { withTempFiles } from '@app-config/test-utils';
4+
import jsModuleDirective from './index';
5+
6+
describe('$jsModule directive', () => {
7+
it('loads function node export', () =>
8+
withTempFiles(
9+
{
10+
'foo.js': `
11+
module.exports = () => 'bar';
12+
`,
13+
},
14+
async (inDir) => {
15+
const source = new LiteralSource({
16+
$jsModule: inDir('foo.js'),
17+
});
18+
19+
expect(await source.readToJSON([jsModuleDirective()])).toEqual('bar');
20+
},
21+
));
22+
23+
it('loads default function node export', () =>
24+
withTempFiles(
25+
{
26+
'foo.js': `
27+
module.exports.__esModule = true;
28+
module.exports.default = () => 'bar';
29+
`,
30+
},
31+
async (inDir) => {
32+
const source = new LiteralSource({
33+
$jsModule: inDir('foo.js'),
34+
});
35+
36+
expect(await source.readToJSON([jsModuleDirective()])).toEqual('bar');
37+
},
38+
));
39+
40+
it('loads object node export', () =>
41+
withTempFiles(
42+
{
43+
'foo.js': `
44+
module.exports = 'bar';
45+
`,
46+
},
47+
async (inDir) => {
48+
const source = new LiteralSource({
49+
$jsModule: inDir('foo.js'),
50+
});
51+
52+
expect(await source.readToJSON([jsModuleDirective()])).toEqual('bar');
53+
},
54+
));
55+
56+
it('loads default object node export', () =>
57+
withTempFiles(
58+
{
59+
'foo.js': `
60+
module.exports.__esModule = true;
61+
module.exports.default = 'bar';
62+
`,
63+
},
64+
async (inDir) => {
65+
const source = new LiteralSource({
66+
$jsModule: inDir('foo.js'),
67+
});
68+
69+
expect(await source.readToJSON([jsModuleDirective()])).toEqual('bar');
70+
},
71+
));
72+
73+
it('loads file relative to app-config', () =>
74+
withTempFiles(
75+
{
76+
'config.yml': `
77+
$jsModule: ./foo.js
78+
`,
79+
'foo.js': `
80+
module.exports.__esModule = true;
81+
module.exports.default = 'bar';
82+
`,
83+
},
84+
async (inDir) => {
85+
const source = new FileSource(inDir('config.yml'));
86+
87+
expect(await source.readToJSON([jsModuleDirective()])).toEqual('bar');
88+
},
89+
));
90+
});

app-config-js/src/index.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { ParsingExtension } from '@app-config/core';
2+
import { forKey, validateOptions } from '@app-config/extension-utils';
3+
import { resolveFilepath } from '@app-config/node';
4+
5+
/* eslint-disable @typescript-eslint/no-unsafe-call */
6+
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
7+
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
8+
9+
export default function jsModuleDirective(): ParsingExtension {
10+
return forKey(
11+
'$jsModule',
12+
validateOptions(
13+
(SchemaBuilder) => SchemaBuilder.stringSchema(),
14+
(value) => async (parse, _, context) => {
15+
const resolvedPath = resolveFilepath(context, value);
16+
17+
let loaded: any = await import(resolvedPath);
18+
19+
if (!loaded) {
20+
return parse(loaded, { shouldFlatten: true });
21+
}
22+
23+
if ('default' in loaded) {
24+
loaded = loaded.default;
25+
}
26+
27+
if (typeof loaded === 'function') {
28+
loaded = loaded();
29+
}
30+
31+
return parse(loaded, { shouldFlatten: true });
32+
},
33+
),
34+
);
35+
}

app-config-js/tsconfig.es.json

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+
}

app-config-js/tsconfig.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
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-test-utils" },
11+
{ "path": "../app-config-core" },
12+
{ "path": "../app-config-node" },
13+
{ "path": "../app-config-extension-utils" }
14+
]
15+
}

new-version.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ new_version app-config-extensions
4949
new_version app-config-generate
5050
new_version app-config-git
5151
new_version app-config-inject
52+
new_version app-config-js
5253
new_version app-config-logging
5354
new_version app-config-main
5455
new_version app-config-meta

0 commit comments

Comments
 (0)