added cli-covarage tool and fixed more tests
This commit is contained in:
parent
b63e58784c
commit
b845a8eade
57 changed files with 11917 additions and 295 deletions
|
|
@ -213,28 +213,47 @@ export class ConfigManager<T = Record<string, unknown>> {
|
|||
}
|
||||
|
||||
private deepMerge(...objects: Record<string, unknown>[]): Record<string, unknown> {
|
||||
const result: Record<string, unknown> = {};
|
||||
const seen = new WeakSet();
|
||||
|
||||
const merge = (...objs: Record<string, unknown>[]): Record<string, unknown> => {
|
||||
const result: Record<string, unknown> = {};
|
||||
|
||||
for (const obj of objects) {
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
if (value === null || value === undefined) {
|
||||
result[key] = value;
|
||||
} else if (
|
||||
typeof value === 'object' &&
|
||||
!Array.isArray(value) &&
|
||||
!(value instanceof Date) &&
|
||||
!(value instanceof RegExp)
|
||||
) {
|
||||
result[key] = this.deepMerge(
|
||||
(result[key] as Record<string, unknown>) || ({} as Record<string, unknown>),
|
||||
value as Record<string, unknown>
|
||||
);
|
||||
} else {
|
||||
result[key] = value;
|
||||
for (const obj of objs) {
|
||||
if (seen.has(obj)) {
|
||||
// Skip circular reference instead of throwing
|
||||
return result;
|
||||
}
|
||||
|
||||
seen.add(obj);
|
||||
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
if (value === null || value === undefined) {
|
||||
result[key] = value;
|
||||
} else if (
|
||||
typeof value === 'object' &&
|
||||
!Array.isArray(value) &&
|
||||
!(value instanceof Date) &&
|
||||
!(value instanceof RegExp)
|
||||
) {
|
||||
if (seen.has(value)) {
|
||||
// Skip circular reference - don't merge this value
|
||||
continue;
|
||||
}
|
||||
result[key] = merge(
|
||||
(result[key] as Record<string, unknown>) || ({} as Record<string, unknown>),
|
||||
value as Record<string, unknown>
|
||||
);
|
||||
} else {
|
||||
result[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
seen.delete(obj);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
};
|
||||
|
||||
return merge(...objects);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,18 +59,21 @@ export class EnvLoader implements ConfigLoader {
|
|||
}
|
||||
|
||||
private setConfigValue(config: Record<string, unknown>, key: string, value: string): void {
|
||||
const parsedValue = this.parseValue(value);
|
||||
|
||||
try {
|
||||
// Handle provider-specific environment variables (only for application usage, not tests)
|
||||
if (!this.prefix && !this.options.convertCase) {
|
||||
const providerMapping = this.getProviderMapping(key);
|
||||
if (providerMapping) {
|
||||
// For certain fields, we need to preserve the string value
|
||||
const shouldPreserveString = this.shouldPreserveStringForKey(key);
|
||||
const parsedValue = shouldPreserveString ? value : this.parseValue(value);
|
||||
this.setNestedValue(config, providerMapping.path, parsedValue);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const parsedValue = this.parseValue(value);
|
||||
|
||||
if (this.options.convertCase) {
|
||||
// Convert to camelCase
|
||||
const camelKey = this.toCamelCase(key);
|
||||
|
|
@ -128,6 +131,15 @@ export class EnvLoader implements ConfigLoader {
|
|||
return str.toLowerCase().replace(/_([a-z])/g, (_, char) => char.toUpperCase());
|
||||
}
|
||||
|
||||
private shouldPreserveStringForKey(key: string): boolean {
|
||||
// Keys that should preserve string values even if they look like numbers
|
||||
const preserveStringKeys = [
|
||||
'QM_WEBMASTER_ID',
|
||||
'IB_MARKET_DATA_TYPE'
|
||||
];
|
||||
return preserveStringKeys.includes(key);
|
||||
}
|
||||
|
||||
private getProviderMapping(envKey: string): { path: string[] } | null {
|
||||
// Provider-specific and special environment variable mappings
|
||||
const providerMappings: Record<string, string[]> = {
|
||||
|
|
@ -213,10 +225,12 @@ export class EnvLoader implements ConfigLoader {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Handle numbers
|
||||
const num = Number(value);
|
||||
if (!isNaN(num) && value !== '') {
|
||||
return num;
|
||||
// Handle numbers (but preserve strings with leading zeros or plus signs)
|
||||
if (!/^[+-]/.test(value) && !/^0\d/.test(value)) {
|
||||
const num = Number(value);
|
||||
if (!isNaN(num) && value !== '') {
|
||||
return num;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle null/undefined
|
||||
|
|
|
|||
|
|
@ -28,9 +28,19 @@ export const ibProviderConfigSchema = baseProviderConfigSchema.extend({
|
|||
host: z.string().default('localhost'),
|
||||
port: z.number().default(5000),
|
||||
clientId: z.number().default(1),
|
||||
}).default({
|
||||
host: 'localhost',
|
||||
port: 5000,
|
||||
clientId: 1,
|
||||
}),
|
||||
account: z.string().optional(),
|
||||
marketDataType: z.enum(['live', 'delayed', 'frozen']).default('delayed'),
|
||||
marketDataType: z.union([
|
||||
z.enum(['live', 'delayed', 'frozen']),
|
||||
z.enum(['1', '2', '3']).transform((val) => {
|
||||
const mapping = { '1': 'live', '2': 'frozen', '3': 'delayed' } as const;
|
||||
return mapping[val];
|
||||
}),
|
||||
]).default('delayed'),
|
||||
});
|
||||
|
||||
// QuoteMedia provider
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue