@rhombus-std/config.json 0.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Thomas Butler
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,45 @@
1
+ # @rhombus-std/config.json
2
+
3
+ JSON file configuration provider for `@rhombus-std/config` —
4
+ `JsonConfigurationSource`/`JsonConfigurationProvider` plus the `addJsonFile`
5
+ sugar bolted onto `ConfigurationBuilder`.
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ npm install @rhombus-std/config @rhombus-std/config.json
11
+ ```
12
+
13
+ `@rhombus-std/config` is a peer dependency — install it alongside this package.
14
+
15
+ ## Basic usage
16
+
17
+ ```ts
18
+ import "@rhombus-std/config.json"; // unlocks .addJsonFile() on ConfigurationBuilder
19
+ import { ConfigurationBuilder } from "@rhombus-std/config";
20
+
21
+ const config = new ConfigurationBuilder()
22
+ .addJsonFile("appsettings.json")
23
+ .addJsonFile("appsettings.local.json", { optional: true })
24
+ .build();
25
+
26
+ config.get("Server:Port");
27
+ ```
28
+
29
+ `optional: true` makes a missing file resolve to an empty provider instead of
30
+ throwing. Malformed JSON in a file that _does_ exist always throws, regardless
31
+ of `optional` — it only covers file absence, not file validity.
32
+
33
+ ## The side-effect import requirement
34
+
35
+ `addJsonFile` isn't a method `ConfigurationBuilder` ships with — this package
36
+ bolts it on via TypeScript declaration merging plus a runtime prototype
37
+ patch. If your code calls `.addJsonFile()` but never names any other symbol
38
+ from `@rhombus-std/config.json` (no `JsonConfigurationSource`, no
39
+ `JsonConfigurationProvider`), a bundler or tree-shaker has nothing forcing it
40
+ to load this package's module — you must import it for its side effect
41
+ explicitly:
42
+
43
+ ```ts
44
+ import "@rhombus-std/config.json"; // unlocks .addJsonFile() on ConfigurationBuilder
45
+ ```
@@ -0,0 +1,41 @@
1
+ import { IConfigurationSource, IConfigurationBuilder, IConfigurationProvider, IndexedSection } from '@rhombus-std/config.core';
2
+ import { ConfigurationProvider } from '@rhombus-std/config';
3
+
4
+ /** Options accepted by {@link JsonConfigurationSource}'s constructor. */
5
+ interface JsonConfigurationSourceOptions {
6
+ /**
7
+ * When `true`, a missing file yields an empty provider instead of
8
+ * throwing. Malformed JSON in a file that *does* exist always throws,
9
+ * regardless of this flag -- "optional" only covers file absence, not
10
+ * file validity.
11
+ */
12
+ optional?: boolean;
13
+ }
14
+ /**
15
+ * A {@link IConfigurationSource} that reads a JSON file from disk (resolved
16
+ * relative to `process.cwd()`) and flattens it into the case-insensitive
17
+ * key/value store shared by every {@link ConfigurationProvider}.
18
+ */
19
+ declare class JsonConfigurationSource implements IConfigurationSource {
20
+ readonly path: string;
21
+ readonly optional: boolean;
22
+ constructor(path: string, opts?: JsonConfigurationSourceOptions);
23
+ build(_builder: IConfigurationBuilder): IConfigurationProvider;
24
+ }
25
+
26
+ declare class JsonConfigurationProvider extends ConfigurationProvider {
27
+ private readonly source;
28
+ constructor(source: JsonConfigurationSource);
29
+ load(): void;
30
+ private flatten;
31
+ }
32
+
33
+ declare module "@rhombus-std/config/configuration-builder" {
34
+ interface ConfigurationBuilder<T = IndexedSection> {
35
+ /** Registers a {@link JsonConfigurationSource} reading `path` (resolved against `process.cwd()`). */
36
+ addJsonFile(path: string, opts?: JsonConfigurationSourceOptions): this;
37
+ }
38
+ }
39
+
40
+ export { JsonConfigurationProvider, JsonConfigurationSource };
41
+ export type { JsonConfigurationSourceOptions };
package/dist/index.js ADDED
@@ -0,0 +1,88 @@
1
+ // src/index.ts
2
+ import { ConfigurationBuilder } from "@rhombus-std/config";
3
+
4
+ // src/json-configuration-provider.ts
5
+ import { ConfigurationProvider } from "@rhombus-std/config";
6
+ import { readFileSync } from "node:fs";
7
+ import { resolve } from "node:path";
8
+ function isFileNotFound(err) {
9
+ return typeof err === "object" && err !== null && err.code === "ENOENT";
10
+ }
11
+
12
+ class JsonConfigurationProvider extends ConfigurationProvider {
13
+ source;
14
+ constructor(source) {
15
+ super();
16
+ this.source = source;
17
+ }
18
+ load() {
19
+ this.data.clear();
20
+ const resolvedPath = resolve(process.cwd(), this.source.path);
21
+ let raw;
22
+ try {
23
+ raw = readFileSync(resolvedPath, "utf-8");
24
+ } catch (err) {
25
+ if (isFileNotFound(err)) {
26
+ if (this.source.optional) {
27
+ this.onReload();
28
+ return;
29
+ }
30
+ throw new Error(`JsonConfigurationProvider: config file not found: ${resolvedPath}`);
31
+ }
32
+ throw err;
33
+ }
34
+ let parsed;
35
+ try {
36
+ parsed = JSON.parse(raw);
37
+ } catch (err) {
38
+ throw new Error(`JsonConfigurationProvider: failed to parse JSON at ${resolvedPath}: ${err instanceof Error ? err.message : String(err)}`);
39
+ }
40
+ if (typeof parsed !== "object" || parsed === null) {
41
+ throw new Error(`JsonConfigurationProvider: root must be an object or array at ${resolvedPath}`);
42
+ }
43
+ this.flatten(parsed, "");
44
+ this.onReload();
45
+ }
46
+ flatten(value, prefix) {
47
+ if (value === null || value === undefined) {
48
+ return;
49
+ }
50
+ if (Array.isArray(value)) {
51
+ value.forEach((item, index) => {
52
+ this.flatten(item, prefix === "" ? String(index) : `${prefix}:${index}`);
53
+ });
54
+ return;
55
+ }
56
+ if (typeof value === "object") {
57
+ for (const [key, child] of Object.entries(value)) {
58
+ this.flatten(child, prefix === "" ? key : `${prefix}:${key}`);
59
+ }
60
+ return;
61
+ }
62
+ if (prefix !== "") {
63
+ this.set(prefix, String(value));
64
+ }
65
+ }
66
+ }
67
+
68
+ // src/json-configuration-source.ts
69
+ class JsonConfigurationSource {
70
+ path;
71
+ optional;
72
+ constructor(path, opts) {
73
+ this.path = path;
74
+ this.optional = opts?.optional ?? false;
75
+ }
76
+ build(_builder) {
77
+ return new JsonConfigurationProvider(this);
78
+ }
79
+ }
80
+
81
+ // src/index.ts
82
+ ConfigurationBuilder.prototype.addJsonFile = function(path, opts) {
83
+ return this.add(new JsonConfigurationSource(path, opts));
84
+ };
85
+ export {
86
+ JsonConfigurationSource,
87
+ JsonConfigurationProvider
88
+ };
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@rhombus-std/config.json",
3
+ "version": "0.0.0-alpha.0",
4
+ "description": "JSON file configuration provider for @rhombus-std/config: JsonConfigurationSource/Provider + the addJsonFile augmentation.",
5
+ "keywords": [
6
+ "configuration",
7
+ "config",
8
+ "json",
9
+ "ioc",
10
+ "typescript"
11
+ ],
12
+ "license": "MIT",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/fnioc/std.git",
16
+ "directory": "libraries/config.json"
17
+ },
18
+ "type": "module",
19
+ "main": "./dist/index.js",
20
+ "types": "./dist/index.d.ts",
21
+ "sideEffects": true,
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "import": "./dist/index.js",
26
+ "default": "./dist/index.js"
27
+ }
28
+ },
29
+ "files": [
30
+ "dist"
31
+ ],
32
+ "dependencies": {
33
+ "@rhombus-std/config.core": "0.0.0-alpha.0"
34
+ },
35
+ "peerDependencies": {
36
+ "@rhombus-std/config": "^0.0.0-alpha.0"
37
+ },
38
+ "devDependencies": {
39
+ "@rhombus-std/config": "0.0.0-alpha.0"
40
+ },
41
+ "publishConfig": {
42
+ "access": "public",
43
+ "provenance": true
44
+ },
45
+ "scripts": {
46
+ "build": "bun x tsc --noEmit -p tsconfig.json && bun build.ts",
47
+ "lint": "bun x tsc --noEmit -p tsconfig.lint.json"
48
+ }
49
+ }