@abdokouta/react-config 1.0.0 → 1.0.2

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.
Files changed (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +2 -1
  3. package/config/config.config.ts +9 -9
  4. package/dist/{index.d.mts → index.d.cts} +34 -2
  5. package/dist/index.d.ts +34 -2
  6. package/dist/index.js +28 -11
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.mjs +28 -11
  9. package/dist/index.mjs.map +1 -1
  10. package/package.json +55 -25
  11. package/.examples/01-basic-usage.ts +0 -289
  12. package/.examples/02-env-helper.ts +0 -282
  13. package/.examples/README.md +0 -285
  14. package/.prettierrc.js +0 -1
  15. package/__tests__/config.module.test.ts +0 -244
  16. package/__tests__/drivers/env.driver.test.ts +0 -259
  17. package/__tests__/services/config.service.test.ts +0 -328
  18. package/__tests__/setup.d.ts +0 -11
  19. package/__tests__/vitest.setup.ts +0 -30
  20. package/eslint.config.js +0 -13
  21. package/src/config.module.ts +0 -154
  22. package/src/constants/index.ts +0 -5
  23. package/src/constants/tokens.constant.ts +0 -38
  24. package/src/drivers/env.driver.ts +0 -194
  25. package/src/drivers/file.driver.ts +0 -81
  26. package/src/drivers/index.ts +0 -6
  27. package/src/index.ts +0 -92
  28. package/src/interfaces/config-driver.interface.ts +0 -30
  29. package/src/interfaces/config-module-options.interface.ts +0 -84
  30. package/src/interfaces/config-service.interface.ts +0 -71
  31. package/src/interfaces/index.ts +0 -8
  32. package/src/interfaces/vite-config-plugin-options.interface.ts +0 -56
  33. package/src/plugins/index.ts +0 -5
  34. package/src/plugins/vite.plugin.ts +0 -115
  35. package/src/services/config.service.ts +0 -172
  36. package/src/services/index.ts +0 -5
  37. package/src/utils/get-nested-value.util.ts +0 -56
  38. package/src/utils/index.ts +0 -6
  39. package/src/utils/load-config-file.util.ts +0 -37
  40. package/src/utils/scan-config-files.util.ts +0 -40
  41. package/tsconfig.json +0 -28
  42. package/tsup.config.ts +0 -105
  43. package/vitest.config.ts +0 -66
@@ -1,328 +0,0 @@
1
- /**
2
- * @fileoverview Tests for ConfigService
3
- *
4
- * This test suite verifies the ConfigService functionality including:
5
- * - Getting configuration values
6
- * - Type-safe getters (getString, getNumber, getBoolean)
7
- * - Throwing methods (getOrThrow, getStringOrThrow)
8
- * - Default value handling
9
- * - Nested key access
10
- *
11
- * @module @abdokouta/config
12
- * @category Tests
13
- */
14
-
15
- import { describe, it, expect, beforeEach, vi } from "vitest";
16
- import { ConfigService } from "@/services/config.service";
17
- import type { ConfigDriver } from "@/interfaces/config-driver.interface";
18
-
19
- describe("ConfigService", () => {
20
- let mockDriver: ConfigDriver;
21
- let configService: ConfigService;
22
-
23
- beforeEach(() => {
24
- // Arrange: Create mock driver
25
- mockDriver = {
26
- load: vi.fn().mockReturnValue({
27
- app: {
28
- name: "Test App",
29
- port: 3000,
30
- debug: true,
31
- },
32
- database: {
33
- host: "localhost",
34
- port: 5432,
35
- name: "testdb",
36
- },
37
- api: {
38
- key: "test-key-123",
39
- timeout: 5000,
40
- },
41
- }),
42
- get: vi.fn((key: string, defaultValue?: any) => {
43
- const data: any = {
44
- "app.name": "Test App",
45
- "app.port": 3000,
46
- "app.debug": true,
47
- "database.host": "localhost",
48
- "database.port": 5432,
49
- "api.key": "test-key-123",
50
- };
51
- return data[key] ?? defaultValue;
52
- }),
53
- has: vi.fn((key: string) => {
54
- const keys = ["app.name", "app.port", "app.debug", "database.host", "database.port", "api.key"];
55
- return keys.includes(key);
56
- }),
57
- all: vi.fn().mockReturnValue({
58
- app: { name: "Test App", port: 3000, debug: true },
59
- database: { host: "localhost", port: 5432, name: "testdb" },
60
- }),
61
- };
62
-
63
- configService = new ConfigService(mockDriver);
64
- });
65
-
66
- describe("get", () => {
67
- it("should get existing configuration value", () => {
68
- // Act: Get config value
69
- const appName = configService.get("app.name");
70
-
71
- // Assert: Value is returned
72
- expect(appName).toBe("Test App");
73
- expect(mockDriver.get).toHaveBeenCalledWith("app.name", undefined);
74
- });
75
-
76
- it("should return default value when key doesn't exist", () => {
77
- // Arrange: Mock missing key
78
- mockDriver.get = vi.fn((key, defaultValue) => defaultValue);
79
-
80
- // Act: Get with default
81
- const value = configService.get("missing.key", "default");
82
-
83
- // Assert: Default is returned
84
- expect(value).toBe("default");
85
- });
86
-
87
- it("should return undefined when key doesn't exist and no default", () => {
88
- // Arrange: Mock missing key
89
- mockDriver.get = vi.fn(() => undefined);
90
-
91
- // Act: Get without default
92
- const value = configService.get("missing.key");
93
-
94
- // Assert: Undefined is returned
95
- expect(value).toBeUndefined();
96
- });
97
-
98
- it("should handle nested keys", () => {
99
- // Act: Get nested value
100
- const dbHost = configService.get("database.host");
101
-
102
- // Assert: Nested value is returned
103
- expect(dbHost).toBe("localhost");
104
- });
105
-
106
- it("should handle numeric values", () => {
107
- // Act: Get numeric value
108
- const port = configService.get<number>("app.port");
109
-
110
- // Assert: Number is returned
111
- expect(port).toBe(3000);
112
- expect(typeof port).toBe("number");
113
- });
114
-
115
- it("should handle boolean values", () => {
116
- // Act: Get boolean value
117
- const debug = configService.get<boolean>("app.debug");
118
-
119
- // Assert: Boolean is returned
120
- expect(debug).toBe(true);
121
- expect(typeof debug).toBe("boolean");
122
- });
123
- });
124
-
125
- describe("getOrThrow", () => {
126
- it("should return value when key exists", () => {
127
- // Act: Get existing key
128
- const appName = configService.getOrThrow("app.name");
129
-
130
- // Assert: Value is returned
131
- expect(appName).toBe("Test App");
132
- });
133
-
134
- it("should throw error when key doesn't exist", () => {
135
- // Arrange: Mock missing key
136
- mockDriver.get = vi.fn(() => undefined);
137
-
138
- // Act & Assert: Should throw
139
- expect(() => {
140
- configService.getOrThrow("missing.key");
141
- }).toThrow();
142
- });
143
-
144
- it("should throw with descriptive error message", () => {
145
- // Arrange: Mock missing key
146
- mockDriver.get = vi.fn(() => undefined);
147
-
148
- // Act & Assert: Should throw with message
149
- expect(() => {
150
- configService.getOrThrow("missing.key");
151
- }).toThrow(/missing\.key/);
152
- });
153
- });
154
-
155
- describe("getString", () => {
156
- it("should return string value", () => {
157
- // Act: Get string
158
- const appName = configService.getString("app.name");
159
-
160
- // Assert: String is returned
161
- expect(appName).toBe("Test App");
162
- expect(typeof appName).toBe("string");
163
- });
164
-
165
- it("should return default string when key doesn't exist", () => {
166
- // Arrange: Mock missing key
167
- mockDriver.get = vi.fn((key, defaultValue) => defaultValue);
168
-
169
- // Act: Get with default
170
- const value = configService.getString("missing.key", "default");
171
-
172
- // Assert: Default is returned
173
- expect(value).toBe("default");
174
- });
175
-
176
- it("should return undefined when no default provided", () => {
177
- // Arrange: Mock missing key
178
- mockDriver.get = vi.fn(() => undefined);
179
-
180
- // Act: Get without default
181
- const value = configService.getString("missing.key");
182
-
183
- // Assert: Undefined is returned
184
- expect(value).toBeUndefined();
185
- });
186
- });
187
-
188
- describe("getStringOrThrow", () => {
189
- it("should return string value when key exists", () => {
190
- // Act: Get existing string
191
- const apiKey = configService.getStringOrThrow("api.key");
192
-
193
- // Assert: String is returned
194
- expect(apiKey).toBe("test-key-123");
195
- expect(typeof apiKey).toBe("string");
196
- });
197
-
198
- it("should throw when key doesn't exist", () => {
199
- // Arrange: Mock missing key
200
- mockDriver.get = vi.fn(() => undefined);
201
-
202
- // Act & Assert: Should throw
203
- expect(() => {
204
- configService.getStringOrThrow("missing.key");
205
- }).toThrow();
206
- });
207
- });
208
-
209
- describe("getNumber", () => {
210
- it("should return number value", () => {
211
- // Act: Get number
212
- const port = configService.getNumber("app.port");
213
-
214
- // Assert: Number is returned
215
- expect(port).toBe(3000);
216
- expect(typeof port).toBe("number");
217
- });
218
-
219
- it("should return default number when key doesn't exist", () => {
220
- // Arrange: Mock missing key
221
- mockDriver.get = vi.fn((key, defaultValue) => defaultValue);
222
-
223
- // Act: Get with default
224
- const value = configService.getNumber("missing.key", 8080);
225
-
226
- // Assert: Default is returned
227
- expect(value).toBe(8080);
228
- });
229
-
230
- it("should parse string numbers", () => {
231
- // Arrange: Mock string number
232
- mockDriver.get = vi.fn(() => "5432");
233
-
234
- // Act: Get as number
235
- const port = configService.getNumber("database.port");
236
-
237
- // Assert: Parsed number is returned
238
- expect(port).toBe(5432);
239
- expect(typeof port).toBe("number");
240
- });
241
- });
242
-
243
- describe("getBoolean", () => {
244
- it("should return boolean value", () => {
245
- // Act: Get boolean
246
- const debug = configService.getBoolean("app.debug");
247
-
248
- // Assert: Boolean is returned
249
- expect(debug).toBe(true);
250
- expect(typeof debug).toBe("boolean");
251
- });
252
-
253
- it("should parse string booleans", () => {
254
- // Arrange: Mock string boolean
255
- mockDriver.get = vi.fn((key) => {
256
- if (key === "feature.enabled") return "true";
257
- if (key === "feature.disabled") return "false";
258
- return undefined;
259
- });
260
-
261
- // Act: Get as boolean
262
- const enabled = configService.getBoolean("feature.enabled");
263
- const disabled = configService.getBoolean("feature.disabled");
264
-
265
- // Assert: Parsed booleans are returned
266
- expect(enabled).toBe(true);
267
- expect(disabled).toBe(false);
268
- });
269
-
270
- it("should handle truthy/falsy values", () => {
271
- // Arrange: Mock various values
272
- mockDriver.get = vi.fn((key) => {
273
- if (key === "one") return 1;
274
- if (key === "zero") return 0;
275
- if (key === "yes") return "yes";
276
- if (key === "no") return "no";
277
- return undefined;
278
- });
279
-
280
- // Act: Get as booleans
281
- const one = configService.getBoolean("one");
282
- const zero = configService.getBoolean("zero");
283
- const yes = configService.getBoolean("yes");
284
- const no = configService.getBoolean("no");
285
-
286
- // Assert: Values are converted to boolean
287
- expect(one).toBe(true);
288
- expect(zero).toBe(false);
289
- expect(yes).toBe(true);
290
- expect(no).toBe(false);
291
- });
292
- });
293
-
294
- describe("Edge Cases", () => {
295
- it("should handle null values", () => {
296
- // Arrange: Mock null value
297
- mockDriver.get = vi.fn(() => null);
298
-
299
- // Act: Get null value
300
- const value = configService.get("null.key");
301
-
302
- // Assert: Null is returned
303
- expect(value).toBeNull();
304
- });
305
-
306
- it("should handle empty string values", () => {
307
- // Arrange: Mock empty string
308
- mockDriver.get = vi.fn(() => "");
309
-
310
- // Act: Get empty string
311
- const value = configService.getString("empty.key");
312
-
313
- // Assert: Empty string is returned
314
- expect(value).toBe("");
315
- });
316
-
317
- it("should handle zero values", () => {
318
- // Arrange: Mock zero
319
- mockDriver.get = vi.fn(() => 0);
320
-
321
- // Act: Get zero
322
- const value = configService.getNumber("zero.key");
323
-
324
- // Assert: Zero is returned
325
- expect(value).toBe(0);
326
- });
327
- });
328
- });
@@ -1,11 +0,0 @@
1
- /**
2
- * @fileoverview Type declarations for Vitest test environment
3
- *
4
- * This file extends Vitest's type definitions to include custom matchers
5
- * and global test utilities.
6
- *
7
- * @module @abdokouta/config
8
- * @category Configuration
9
- */
10
-
11
- import "vitest/globals";
@@ -1,30 +0,0 @@
1
- /**
2
- * @fileoverview Vitest setup file for @abdokouta/config package
3
- *
4
- * This file configures the testing environment before running tests.
5
- * It sets up container mocking for dependency injection tests.
6
- *
7
- * Setup Features:
8
- * - Container mocking for DI tests
9
- *
10
- * @module @abdokouta/config
11
- * @category Configuration
12
- */
13
-
14
- import { vi } from "vitest";
15
-
16
- /**
17
- * Mock @abdokouta/react-di decorators
18
- *
19
- * This ensures that decorator metadata doesn't interfere with tests
20
- * and allows us to test module behavior in isolation.
21
- */
22
- vi.mock("@abdokouta/react-di", async () => {
23
- const actual = await vi.importActual("@abdokouta/react-di");
24
- return {
25
- ...actual,
26
- Injectable: () => (target: any) => target,
27
- Inject: () => (target: any, propertyKey: string, parameterIndex: number) => {},
28
- Module: (metadata: any) => (target: any) => target,
29
- };
30
- });
package/eslint.config.js DELETED
@@ -1,13 +0,0 @@
1
- import nesvelConfig from '@nesvel/eslint-config';
2
-
3
- export default [
4
- ...nesvelConfig,
5
- {
6
- ignores: ['dist/**', 'node_modules/**', '*.config.js', '*.config.ts'],
7
- },
8
- {
9
- rules: {
10
- // Add any package-specific rule overrides here
11
- },
12
- },
13
- ];
@@ -1,154 +0,0 @@
1
- import { Module, DynamicModule } from '@abdokouta/react-di';
2
-
3
- import { EnvDriver } from './drivers/env.driver';
4
- import { FileDriver } from './drivers/file.driver';
5
- import { ConfigService } from './services/config.service';
6
- import type { ConfigDriver } from './interfaces/config-driver.interface';
7
- import type { ConfigModuleOptions } from './interfaces/config-module-options.interface';
8
- import { CONFIG_DRIVER, CONFIG_OPTIONS, CONFIG_SERVICE } from './constants/tokens.constant';
9
-
10
- /**
11
- * Configuration Module
12
- *
13
- * Provides configuration management with multiple drivers.
14
- * Similar to NestJS ConfigModule.
15
- *
16
- * @example
17
- * ```typescript
18
- * // Using environment variables (default)
19
- * @Module({
20
- * imports: [
21
- * ConfigModule.forRoot({
22
- * envFilePath: '.env',
23
- * isGlobal: true,
24
- * }),
25
- * ],
26
- * })
27
- * export class AppModule {}
28
- * ```
29
- *
30
- * @example
31
- * ```typescript
32
- * // Using file-based configuration
33
- * @Module({
34
- * imports: [
35
- * ConfigModule.forRoot({
36
- * driver: 'file',
37
- * filePattern: 'config/**\/*.config.ts',
38
- * isGlobal: true,
39
- * }),
40
- * ],
41
- * })
42
- * export class AppModule {}
43
- * ```
44
- */
45
- @Module({})
46
- export class ConfigModule {
47
- /**
48
- * Register configuration module with options
49
- *
50
- * @param options - Configuration options
51
- * @returns Dynamic module
52
- */
53
- static forRoot(options: ConfigModuleOptions = {}): DynamicModule {
54
- const driver = this.createDriver(options);
55
-
56
- const isGlobal = options.isGlobal ?? false;
57
-
58
- const providers = [
59
- {
60
- provide: CONFIG_OPTIONS,
61
- useValue: options,
62
- isGlobal,
63
- },
64
- {
65
- provide: CONFIG_DRIVER,
66
- useValue: driver,
67
- isGlobal,
68
- },
69
- ConfigService,
70
- {
71
- provide: CONFIG_SERVICE,
72
- useExisting: ConfigService,
73
- isGlobal,
74
- },
75
- ];
76
-
77
- return {
78
- module: ConfigModule,
79
- providers: providers as any,
80
- exports: [ConfigService],
81
- };
82
- }
83
-
84
- /**
85
- * Register configuration module asynchronously
86
- *
87
- * @param options - Async configuration options
88
- * @returns Dynamic module
89
- */
90
- static async forRootAsync(
91
- options: ConfigModuleOptions & {
92
- useFactory?: () => Promise<ConfigModuleOptions> | ConfigModuleOptions;
93
- }
94
- ): Promise<DynamicModule> {
95
- const resolvedOptions = options.useFactory
96
- ? await options.useFactory()
97
- : options;
98
-
99
- return this.forRoot(resolvedOptions);
100
- }
101
-
102
- /**
103
- * Create configuration driver based on options
104
- */
105
- private static createDriver(options: ConfigModuleOptions): ConfigDriver {
106
- const driverType = options.driver || 'env';
107
-
108
- switch (driverType) {
109
- case 'env':
110
- const envDriver = new EnvDriver({
111
- envFilePath: options.envFilePath,
112
- ignoreEnvFile: options.ignoreEnvFile,
113
- expandVariables: options.expandVariables,
114
- envPrefix: options.envPrefix,
115
- globalName: options.globalName,
116
- });
117
- envDriver.load();
118
-
119
- // Merge custom load function if provided
120
- if (options.load) {
121
- this.mergeCustomConfig(envDriver, options.load);
122
- }
123
-
124
- return envDriver;
125
-
126
- case 'file':
127
- const fileDriver = new FileDriver({
128
- config: typeof options.load === 'object' ? options.load : undefined,
129
- });
130
- return fileDriver;
131
-
132
- default:
133
- throw new Error(`Unknown configuration driver: ${driverType}`);
134
- }
135
- }
136
-
137
- /**
138
- * Merge custom configuration into driver
139
- */
140
- private static mergeCustomConfig(
141
- driver: ConfigDriver,
142
- load: Record<string, any> | (() => Record<string, any> | Promise<Record<string, any>>)
143
- ): void {
144
- const customConfig = typeof load === 'function' ? load() : load;
145
-
146
- if (customConfig instanceof Promise) {
147
- customConfig.then(config => {
148
- Object.assign(driver.all(), config);
149
- });
150
- } else {
151
- Object.assign(driver.all(), customConfig);
152
- }
153
- }
154
- }
@@ -1,5 +0,0 @@
1
- /**
2
- * Constants
3
- */
4
-
5
- export { CONFIG_TOKENS } from './tokens.constant';
@@ -1,38 +0,0 @@
1
- /**
2
- * Dependency Injection Tokens
3
- *
4
- * Used for injecting configuration dependencies.
5
- */
6
-
7
- /**
8
- * Configuration driver token
9
- *
10
- * @example
11
- * ```typescript
12
- * @Inject(CONFIG_DRIVER)
13
- * private driver: ConfigDriver
14
- * ```
15
- */
16
- export const CONFIG_DRIVER = Symbol('CONFIG_DRIVER');
17
-
18
- /**
19
- * Configuration options token
20
- *
21
- * @example
22
- * ```typescript
23
- * @Inject(CONFIG_OPTIONS)
24
- * private options: ConfigModuleOptions
25
- * ```
26
- */
27
- export const CONFIG_OPTIONS = Symbol('CONFIG_OPTIONS');
28
-
29
- /**
30
- * Configuration service token
31
- *
32
- * @example
33
- * ```typescript
34
- * @Inject(CONFIG_SERVICE)
35
- * private config: ConfigService
36
- * ```
37
- */
38
- export const CONFIG_SERVICE = Symbol('CONFIG_SERVICE');