chrome-cdp-cli 1.8.1 → 2.0.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.
@@ -0,0 +1,261 @@
1
+ #!/usr/bin/env ts-node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.demonstrateOutputFormats = demonstrateOutputFormats;
5
+ const OutputManager_1 = require("./OutputManager");
6
+ const OutputFormatter_1 = require("./OutputFormatter");
7
+ const configs = {
8
+ text: {
9
+ host: 'localhost',
10
+ port: 9222,
11
+ outputFormat: 'text',
12
+ verbose: false,
13
+ quiet: false,
14
+ timeout: 30000,
15
+ debug: false
16
+ },
17
+ json: {
18
+ host: 'localhost',
19
+ port: 9222,
20
+ outputFormat: 'json',
21
+ verbose: false,
22
+ quiet: false,
23
+ timeout: 30000,
24
+ debug: false
25
+ },
26
+ yaml: {
27
+ host: 'localhost',
28
+ port: 9222,
29
+ outputFormat: 'yaml',
30
+ verbose: false,
31
+ quiet: false,
32
+ timeout: 30000,
33
+ debug: false
34
+ },
35
+ verbose: {
36
+ host: 'localhost',
37
+ port: 9222,
38
+ outputFormat: 'text',
39
+ verbose: true,
40
+ quiet: false,
41
+ timeout: 30000,
42
+ debug: false
43
+ },
44
+ quiet: {
45
+ host: 'localhost',
46
+ port: 9222,
47
+ outputFormat: 'text',
48
+ verbose: false,
49
+ quiet: true,
50
+ timeout: 30000,
51
+ debug: false
52
+ },
53
+ debug: {
54
+ host: 'localhost',
55
+ port: 9222,
56
+ outputFormat: 'text',
57
+ verbose: true,
58
+ quiet: false,
59
+ timeout: 30000,
60
+ debug: true
61
+ }
62
+ };
63
+ const sampleResults = {
64
+ simpleSuccess: {
65
+ success: true,
66
+ data: 'Operation completed successfully'
67
+ },
68
+ consoleMessages: {
69
+ success: true,
70
+ data: {
71
+ messages: [
72
+ {
73
+ type: 'log',
74
+ text: 'Application started',
75
+ timestamp: Date.now() - 5000,
76
+ args: []
77
+ },
78
+ {
79
+ type: 'warn',
80
+ text: 'Deprecated API usage detected',
81
+ timestamp: Date.now() - 3000,
82
+ args: ['api.old()']
83
+ },
84
+ {
85
+ type: 'error',
86
+ text: 'Failed to load resource',
87
+ timestamp: Date.now() - 1000,
88
+ args: ['https://example.com/missing.js']
89
+ }
90
+ ]
91
+ },
92
+ dataSource: 'proxy',
93
+ hasHistoricalData: true
94
+ },
95
+ networkRequests: {
96
+ success: true,
97
+ data: {
98
+ requests: [
99
+ {
100
+ requestId: '1',
101
+ url: 'https://api.example.com/users',
102
+ method: 'GET',
103
+ timestamp: Date.now() - 2000,
104
+ status: 200
105
+ },
106
+ {
107
+ requestId: '2',
108
+ url: 'https://api.example.com/posts',
109
+ method: 'POST',
110
+ timestamp: Date.now() - 1000,
111
+ status: 201
112
+ }
113
+ ]
114
+ },
115
+ dataSource: 'direct',
116
+ hasHistoricalData: false
117
+ },
118
+ error: {
119
+ success: false,
120
+ error: 'Connection timeout: Unable to connect to Chrome DevTools',
121
+ exitCode: 1
122
+ },
123
+ complexData: {
124
+ success: true,
125
+ data: {
126
+ pageInfo: {
127
+ title: 'Example Page',
128
+ url: 'https://example.com',
129
+ loadTime: 1250
130
+ },
131
+ metrics: {
132
+ domContentLoaded: 800,
133
+ firstPaint: 900,
134
+ firstContentfulPaint: 950
135
+ }
136
+ }
137
+ }
138
+ };
139
+ function printSeparator(title) {
140
+ console.log('\n' + '='.repeat(60));
141
+ console.log(` ${title}`);
142
+ console.log('='.repeat(60));
143
+ }
144
+ function printSubsection(title) {
145
+ console.log(`\n--- ${title} ---`);
146
+ }
147
+ async function demonstrateOutputFormats() {
148
+ const outputManager = new OutputManager_1.OutputManager();
149
+ const formatter = new OutputFormatter_1.OutputFormatter();
150
+ printSeparator('STANDARDIZED OUTPUT FORMATTING DEMO');
151
+ printSubsection('1. Output Formats (JSON, Text, YAML)');
152
+ const result = sampleResults.complexData;
153
+ console.log('\n📄 TEXT FORMAT:');
154
+ console.log(outputManager.formatOutput(result, configs.text));
155
+ console.log('\n📋 JSON FORMAT:');
156
+ console.log(outputManager.formatOutput(result, configs.json));
157
+ console.log('\n📝 YAML FORMAT:');
158
+ console.log(outputManager.formatOutput(result, configs.yaml));
159
+ printSubsection('2. Verbose Mode with Timing Information');
160
+ const timing = (0, OutputFormatter_1.createTimingInfo)('screenshot-command', Date.now() - 1500, Date.now());
161
+ const metadata = {
162
+ command: 'screenshot',
163
+ args: { filename: 'test.png', fullPage: true },
164
+ config: configs.verbose
165
+ };
166
+ const enhancedResult = (0, OutputFormatter_1.enhanceCommandResult)(sampleResults.simpleSuccess, timing, metadata);
167
+ console.log('\n🔍 VERBOSE OUTPUT:');
168
+ console.log(formatter.formatOutput(enhancedResult, {
169
+ format: 'text',
170
+ mode: { verbose: true, quiet: false, debug: false },
171
+ includeMetadata: true,
172
+ includeTiming: true
173
+ }));
174
+ printSubsection('3. Quiet Mode (Minimal Output)');
175
+ console.log('\n🤫 QUIET MODE - Success with data:');
176
+ console.log(`"${outputManager.formatOutput(sampleResults.consoleMessages, configs.quiet)}"`);
177
+ console.log('\n🤫 QUIET MODE - Success without data:');
178
+ console.log(`"${outputManager.formatOutput(sampleResults.simpleSuccess, configs.quiet)}"`);
179
+ console.log('\n🤫 QUIET MODE - Error (still shown):');
180
+ console.log(outputManager.formatOutput(sampleResults.error, configs.quiet));
181
+ printSubsection('4. Debug Mode with Detailed Information');
182
+ const debugResult = (0, OutputFormatter_1.enhanceCommandResult)(sampleResults.error, timing, metadata);
183
+ console.log('\n🔧 DEBUG OUTPUT:');
184
+ console.log(formatter.formatOutput(debugResult, {
185
+ format: 'text',
186
+ mode: { verbose: true, quiet: false, debug: true },
187
+ includeMetadata: true,
188
+ includeTiming: true
189
+ }));
190
+ printSubsection('5. Console Messages Formatting');
191
+ console.log('\n📝 CONSOLE MESSAGES (Text):');
192
+ console.log(outputManager.formatOutput(sampleResults.consoleMessages, configs.text));
193
+ console.log('\n📝 CONSOLE MESSAGES (Verbose):');
194
+ console.log(outputManager.formatOutput(sampleResults.consoleMessages, configs.verbose));
195
+ printSubsection('6. Network Requests Formatting');
196
+ console.log('\n🌐 NETWORK REQUESTS:');
197
+ console.log(outputManager.formatOutput(sampleResults.networkRequests, configs.text));
198
+ printSubsection('7. Custom Output Templates');
199
+ formatter.registerTemplate({
200
+ name: 'status-only',
201
+ description: 'Show only success status',
202
+ template: 'Status: {{success}}',
203
+ variables: ['success']
204
+ });
205
+ formatter.registerTemplate({
206
+ name: 'detailed-summary',
207
+ description: 'Detailed summary with timing',
208
+ template: '✅ {{success}} | ⏱️ {{timing.duration}}ms | 📋 {{metadata.command}}',
209
+ variables: ['success', 'timing', 'metadata']
210
+ });
211
+ console.log('\n🎨 CUSTOM TEMPLATE - Status Only:');
212
+ console.log(formatter.formatOutput(sampleResults.simpleSuccess, {
213
+ format: 'text',
214
+ mode: { verbose: false, quiet: false, debug: false },
215
+ template: 'status-only'
216
+ }));
217
+ console.log('\n🎨 CUSTOM TEMPLATE - Detailed Summary:');
218
+ console.log(formatter.formatOutput(enhancedResult, {
219
+ format: 'text',
220
+ mode: { verbose: false, quiet: false, debug: false },
221
+ template: 'detailed-summary'
222
+ }));
223
+ printSubsection('8. Consistent Error Handling');
224
+ console.log('\n❌ ERROR (Text):');
225
+ console.log(outputManager.formatOutput(sampleResults.error, configs.text));
226
+ console.log('\n❌ ERROR (JSON):');
227
+ console.log(outputManager.formatOutput(sampleResults.error, configs.json));
228
+ console.log('\n❌ ERROR (Debug):');
229
+ console.log(outputManager.formatOutput(sampleResults.error, configs.debug));
230
+ printSubsection('9. Utility Functions');
231
+ console.log('\n🛠️ VALIDATION ERRORS:');
232
+ console.log(outputManager.formatValidationErrors([
233
+ { field: 'host', message: 'Invalid hostname format', suggestion: 'Use localhost or valid IP' },
234
+ { field: 'port', message: 'Port must be between 1 and 65535' }
235
+ ]));
236
+ console.log('\n📖 HELP INFORMATION:');
237
+ console.log(outputManager.formatHelpInfo('Screenshot Command', 'Capture a screenshot of the current page with various options.', [
238
+ 'chrome-cdp-cli screenshot --filename=page.png',
239
+ 'chrome-cdp-cli screenshot --full-page --format=jpeg'
240
+ ]));
241
+ printSubsection('10. Performance and Timing');
242
+ console.log('\n⏱️ TIMING INFORMATION:');
243
+ console.log(outputManager.getTimingInfo(Date.now() - 2500, Date.now(), 'complex-operation'));
244
+ console.log('\n📊 DATA SOURCE INFORMATION:');
245
+ console.log(outputManager.formatDataSourceInfo('proxy', true));
246
+ console.log(outputManager.formatDataSourceInfo('direct', false));
247
+ printSeparator('DEMO COMPLETE');
248
+ console.log('\n✅ All output formatting features demonstrated successfully!');
249
+ console.log('\n📋 Key Features:');
250
+ console.log(' • Multiple output formats (JSON, Text, YAML)');
251
+ console.log(' • Quiet and verbose modes');
252
+ console.log(' • Custom output templates');
253
+ console.log(' • Timing information for verbose mode');
254
+ console.log(' • Consistent error handling');
255
+ console.log(' • Smart data formatting (console messages, network requests)');
256
+ console.log(' • Debug mode with detailed information');
257
+ console.log(' • Utility functions for validation and help');
258
+ }
259
+ if (require.main === module) {
260
+ demonstrateOutputFormats().catch(console.error);
261
+ }
package/dist/cli/index.js CHANGED
@@ -1,12 +1,32 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
2
16
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CLIApplication = exports.ExitCode = exports.CommandRouter = exports.CommandRegistry = exports.CLIInterface = void 0;
17
+ exports.CommandRouter = exports.CommandRegistry = exports.CLIInterface = exports.CLIApplication = exports.CommandSchemaRegistry = exports.EnhancedCLIInterface = exports.ArgumentParser = void 0;
18
+ var ArgumentParser_1 = require("./ArgumentParser");
19
+ Object.defineProperty(exports, "ArgumentParser", { enumerable: true, get: function () { return ArgumentParser_1.ArgumentParser; } });
20
+ var EnhancedCLIInterface_1 = require("./EnhancedCLIInterface");
21
+ Object.defineProperty(exports, "EnhancedCLIInterface", { enumerable: true, get: function () { return EnhancedCLIInterface_1.EnhancedCLIInterface; } });
22
+ var CommandSchemaRegistry_1 = require("./CommandSchemaRegistry");
23
+ Object.defineProperty(exports, "CommandSchemaRegistry", { enumerable: true, get: function () { return CommandSchemaRegistry_1.CommandSchemaRegistry; } });
24
+ __exportStar(require("./interfaces/ArgumentParser"), exports);
25
+ var CLIApplication_1 = require("./CLIApplication");
26
+ Object.defineProperty(exports, "CLIApplication", { enumerable: true, get: function () { return CLIApplication_1.CLIApplication; } });
4
27
  var CLIInterface_1 = require("./CLIInterface");
5
28
  Object.defineProperty(exports, "CLIInterface", { enumerable: true, get: function () { return CLIInterface_1.CLIInterface; } });
6
29
  var CommandRegistry_1 = require("./CommandRegistry");
7
30
  Object.defineProperty(exports, "CommandRegistry", { enumerable: true, get: function () { return CommandRegistry_1.CommandRegistry; } });
8
31
  var CommandRouter_1 = require("./CommandRouter");
9
32
  Object.defineProperty(exports, "CommandRouter", { enumerable: true, get: function () { return CommandRouter_1.CommandRouter; } });
10
- Object.defineProperty(exports, "ExitCode", { enumerable: true, get: function () { return CommandRouter_1.ExitCode; } });
11
- var CLIApplication_1 = require("./CLIApplication");
12
- Object.defineProperty(exports, "CLIApplication", { enumerable: true, get: function () { return CLIApplication_1.CLIApplication; } });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,357 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.ConfigurationManager = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const yaml = __importStar(require("js-yaml"));
40
+ const interfaces_1 = require("./interfaces");
41
+ class ConfigurationManager {
42
+ constructor() {
43
+ this.configSources = [];
44
+ this.availableProfiles = [];
45
+ }
46
+ async loadConfiguration(sources) {
47
+ this.configSources = sources.sort((a, b) => a.priority - b.priority);
48
+ let mergedConfig = { ...interfaces_1.DEFAULT_CLI_CONFIG };
49
+ for (const source of this.configSources) {
50
+ mergedConfig = this.mergeConfiguration(mergedConfig, source.data);
51
+ }
52
+ const validation = this.validateConfiguration(mergedConfig);
53
+ if (!validation.valid) {
54
+ const errorMessages = validation.errors.map(e => `${e.field}: ${e.message}`).join(', ');
55
+ throw new Error(`Configuration validation failed: ${errorMessages}`);
56
+ }
57
+ this.loadedConfig = mergedConfig;
58
+ return mergedConfig;
59
+ }
60
+ validateConfiguration(config) {
61
+ const errors = [];
62
+ const warnings = [];
63
+ if (!config.host || typeof config.host !== 'string') {
64
+ errors.push({
65
+ field: 'host',
66
+ message: 'Host must be a non-empty string',
67
+ code: 'INVALID_HOST',
68
+ suggestion: 'Use a valid hostname like "localhost" or IP address'
69
+ });
70
+ }
71
+ if (typeof config.port !== 'number' || config.port < 1 || config.port > 65535) {
72
+ errors.push({
73
+ field: 'port',
74
+ message: 'Port must be a number between 1 and 65535',
75
+ code: 'INVALID_PORT',
76
+ suggestion: 'Use a valid port number like 9222'
77
+ });
78
+ }
79
+ if (typeof config.timeout !== 'number' || config.timeout < 1) {
80
+ errors.push({
81
+ field: 'timeout',
82
+ message: 'Timeout must be a positive number',
83
+ code: 'INVALID_TIMEOUT',
84
+ suggestion: 'Use a timeout value in milliseconds, e.g., 30000'
85
+ });
86
+ }
87
+ const validFormats = ['json', 'text', 'yaml'];
88
+ if (!validFormats.includes(config.outputFormat)) {
89
+ errors.push({
90
+ field: 'outputFormat',
91
+ message: `Output format must be one of: ${validFormats.join(', ')}`,
92
+ code: 'INVALID_OUTPUT_FORMAT',
93
+ suggestion: 'Use "json", "text", or "yaml"'
94
+ });
95
+ }
96
+ const booleanFields = ['verbose', 'quiet', 'debug'];
97
+ for (const field of booleanFields) {
98
+ if (typeof config[field] !== 'boolean') {
99
+ errors.push({
100
+ field,
101
+ message: `${field} must be a boolean`,
102
+ code: 'INVALID_BOOLEAN',
103
+ suggestion: 'Use true or false'
104
+ });
105
+ }
106
+ }
107
+ if (!Array.isArray(config.pluginDirs)) {
108
+ errors.push({
109
+ field: 'pluginDirs',
110
+ message: 'Plugin directories must be an array',
111
+ code: 'INVALID_PLUGIN_DIRS',
112
+ suggestion: 'Use an array of directory paths'
113
+ });
114
+ }
115
+ else {
116
+ for (let i = 0; i < config.pluginDirs.length; i++) {
117
+ if (typeof config.pluginDirs[i] !== 'string') {
118
+ errors.push({
119
+ field: `pluginDirs[${i}]`,
120
+ message: 'Plugin directory path must be a string',
121
+ code: 'INVALID_PLUGIN_DIR_PATH',
122
+ suggestion: 'Use a valid directory path'
123
+ });
124
+ }
125
+ }
126
+ }
127
+ if (typeof config.aliases !== 'object' || config.aliases === null) {
128
+ errors.push({
129
+ field: 'aliases',
130
+ message: 'Aliases must be an object',
131
+ code: 'INVALID_ALIASES',
132
+ suggestion: 'Use an object with string keys and values'
133
+ });
134
+ }
135
+ else {
136
+ for (const [alias, command] of Object.entries(config.aliases)) {
137
+ if (typeof command !== 'string') {
138
+ errors.push({
139
+ field: `aliases.${alias}`,
140
+ message: 'Alias target must be a string',
141
+ code: 'INVALID_ALIAS_TARGET',
142
+ suggestion: 'Use a valid command name'
143
+ });
144
+ }
145
+ }
146
+ }
147
+ if (typeof config.commands !== 'object' || config.commands === null) {
148
+ errors.push({
149
+ field: 'commands',
150
+ message: 'Commands configuration must be an object',
151
+ code: 'INVALID_COMMANDS_CONFIG',
152
+ suggestion: 'Use an object with command names as keys'
153
+ });
154
+ }
155
+ if (config.verbose && config.quiet) {
156
+ warnings.push({
157
+ field: 'verbose,quiet',
158
+ message: 'Verbose and quiet modes are conflicting',
159
+ code: 'CONFLICTING_OPTIONS'
160
+ });
161
+ }
162
+ return {
163
+ valid: errors.length === 0,
164
+ errors,
165
+ warnings
166
+ };
167
+ }
168
+ getConfigurationPrecedence() {
169
+ return [...this.configSources];
170
+ }
171
+ resolveConfigValue(key, type) {
172
+ if (!this.loadedConfig) {
173
+ throw new Error('Configuration not loaded. Call loadConfiguration first.');
174
+ }
175
+ const value = this.getNestedValue(this.loadedConfig, key);
176
+ if (value === undefined) {
177
+ throw new Error(`Configuration key "${key}" not found`);
178
+ }
179
+ if (!this.validateValueType(value, type)) {
180
+ throw new Error(`Configuration key "${key}" has invalid type. Expected ${type}, got ${typeof value}`);
181
+ }
182
+ return value;
183
+ }
184
+ async loadYAMLConfig(filePath) {
185
+ try {
186
+ const content = await fs.promises.readFile(filePath, 'utf-8');
187
+ let config;
188
+ try {
189
+ config = yaml.load(content);
190
+ }
191
+ catch (yamlError) {
192
+ config = JSON.parse(content);
193
+ }
194
+ if (typeof config !== 'object' || config === null) {
195
+ throw new Error('Configuration file must contain a valid object');
196
+ }
197
+ if (config.profiles) {
198
+ this.availableProfiles = Object.keys(config.profiles);
199
+ }
200
+ return config;
201
+ }
202
+ catch (error) {
203
+ throw new Error(`Failed to load configuration file "${filePath}": ${error instanceof Error ? error.message : String(error)}`);
204
+ }
205
+ }
206
+ loadEnvironmentConfig() {
207
+ const envConfig = {};
208
+ const envMappings = {
209
+ [`${interfaces_1.ENV_PREFIX}HOST`]: 'host',
210
+ [`${interfaces_1.ENV_PREFIX}PORT`]: 'port',
211
+ [`${interfaces_1.ENV_PREFIX}TIMEOUT`]: 'timeout',
212
+ [`${interfaces_1.ENV_PREFIX}OUTPUT_FORMAT`]: 'outputFormat',
213
+ [`${interfaces_1.ENV_PREFIX}VERBOSE`]: 'verbose',
214
+ [`${interfaces_1.ENV_PREFIX}QUIET`]: 'quiet',
215
+ [`${interfaces_1.ENV_PREFIX}DEBUG`]: 'debug',
216
+ [`${interfaces_1.ENV_PREFIX}PROFILE`]: 'profile',
217
+ [`${interfaces_1.ENV_PREFIX}CONFIG_FILE`]: 'configFile'
218
+ };
219
+ for (const [envVar, configKey] of Object.entries(envMappings)) {
220
+ const value = process.env[envVar];
221
+ if (value !== undefined) {
222
+ envConfig[configKey] = this.parseEnvironmentValue(value, configKey);
223
+ }
224
+ }
225
+ const pluginDirs = process.env[`${interfaces_1.ENV_PREFIX}PLUGIN_DIRS`];
226
+ if (pluginDirs) {
227
+ envConfig.pluginDirs = pluginDirs.split(',').map(dir => dir.trim());
228
+ }
229
+ return {
230
+ type: 'env',
231
+ priority: interfaces_1.CONFIG_PRIORITIES.env,
232
+ data: envConfig,
233
+ source: 'environment variables'
234
+ };
235
+ }
236
+ getAvailableProfiles() {
237
+ return [...this.availableProfiles];
238
+ }
239
+ async loadProfile(profileName) {
240
+ const configFiles = await this.findConfigurationFiles();
241
+ for (const configFile of configFiles) {
242
+ try {
243
+ const config = await this.loadYAMLConfig(configFile);
244
+ if (config.profiles && config.profiles[profileName]) {
245
+ return config.profiles[profileName];
246
+ }
247
+ }
248
+ catch (error) {
249
+ continue;
250
+ }
251
+ }
252
+ throw new Error(`Profile "${profileName}" not found in any configuration file`);
253
+ }
254
+ async createConfigurationSources(cliOptions = {}) {
255
+ const sources = [];
256
+ sources.push({
257
+ type: 'default',
258
+ priority: interfaces_1.CONFIG_PRIORITIES.default,
259
+ data: { ...interfaces_1.DEFAULT_CLI_CONFIG },
260
+ source: 'defaults'
261
+ });
262
+ const configFile = cliOptions.configFile || await this.findDefaultConfigFile();
263
+ if (configFile) {
264
+ try {
265
+ const fileConfig = await this.loadYAMLConfig(configFile);
266
+ let profileConfig = {};
267
+ const profileName = cliOptions.profile || fileConfig.profile;
268
+ if (profileName && fileConfig.profiles && fileConfig.profiles[profileName]) {
269
+ profileConfig = fileConfig.profiles[profileName];
270
+ }
271
+ const mergedFileConfig = this.mergeConfiguration(fileConfig, profileConfig);
272
+ sources.push({
273
+ type: 'file',
274
+ priority: interfaces_1.CONFIG_PRIORITIES.file,
275
+ data: mergedFileConfig,
276
+ source: configFile
277
+ });
278
+ }
279
+ catch (error) {
280
+ if (cliOptions.configFile) {
281
+ throw error;
282
+ }
283
+ }
284
+ }
285
+ sources.push(this.loadEnvironmentConfig());
286
+ sources.push({
287
+ type: 'cli',
288
+ priority: interfaces_1.CONFIG_PRIORITIES.cli,
289
+ data: cliOptions,
290
+ source: 'command line'
291
+ });
292
+ return sources;
293
+ }
294
+ async findConfigurationFiles() {
295
+ const configFiles = [];
296
+ for (const searchPath of interfaces_1.DEFAULT_CONFIG_PATHS) {
297
+ for (const fileName of interfaces_1.DEFAULT_CONFIG_FILES) {
298
+ const filePath = path.join(searchPath, fileName);
299
+ try {
300
+ await fs.promises.access(filePath, fs.constants.R_OK);
301
+ configFiles.push(filePath);
302
+ }
303
+ catch {
304
+ }
305
+ }
306
+ }
307
+ return configFiles;
308
+ }
309
+ async findDefaultConfigFile() {
310
+ const configFiles = await this.findConfigurationFiles();
311
+ return configFiles.length > 0 ? configFiles[0] : null;
312
+ }
313
+ mergeConfiguration(base, override) {
314
+ const result = { ...base };
315
+ for (const [key, value] of Object.entries(override)) {
316
+ if (value !== undefined && value !== null) {
317
+ if (typeof value === 'object' && !Array.isArray(value) && typeof result[key] === 'object' && !Array.isArray(result[key])) {
318
+ result[key] = this.mergeConfiguration(result[key], value);
319
+ }
320
+ else {
321
+ result[key] = value;
322
+ }
323
+ }
324
+ }
325
+ return result;
326
+ }
327
+ parseEnvironmentValue(value, key) {
328
+ if (['verbose', 'quiet', 'debug'].includes(key)) {
329
+ return value.toLowerCase() === 'true' || value === '1';
330
+ }
331
+ if (['port', 'timeout'].includes(key)) {
332
+ const num = parseInt(value, 10);
333
+ return isNaN(num) ? value : num;
334
+ }
335
+ return value;
336
+ }
337
+ getNestedValue(obj, key) {
338
+ return key.split('.').reduce((current, prop) => current?.[prop], obj);
339
+ }
340
+ validateValueType(value, expectedType) {
341
+ switch (expectedType) {
342
+ case 'string':
343
+ return typeof value === 'string';
344
+ case 'number':
345
+ return typeof value === 'number';
346
+ case 'boolean':
347
+ return typeof value === 'boolean';
348
+ case 'array':
349
+ return Array.isArray(value);
350
+ case 'object':
351
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
352
+ default:
353
+ return false;
354
+ }
355
+ }
356
+ }
357
+ exports.ConfigurationManager = ConfigurationManager;