From f3c1b50205eb8da8c483802b5f6215ce521c6e35 Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Sat, 31 Jan 2026 20:27:38 +0000 Subject: [PATCH] Initial upload with CI/CD workflow --- src/utils/typeGenerator.ts | 159 +++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 src/utils/typeGenerator.ts diff --git a/src/utils/typeGenerator.ts b/src/utils/typeGenerator.ts new file mode 100644 index 0000000..a75b0bb --- /dev/null +++ b/src/utils/typeGenerator.ts @@ -0,0 +1,159 @@ +import * as prettier from 'prettier'; +import { EnvSchema, ParsedEnv } from '../core/types'; + +export function generateTypeScriptInterface( + schema: EnvSchema, + parsedEnv: ParsedEnv, + interfaceName: string = 'EnvVariables' +): string { + const lines: string[] = []; + + lines.push(`export interface ${interfaceName} {`); + + for (const [key, config] of Object.entries(schema.variables)) { + const isRequired = config.required !== false; + const optionalMarker = isRequired ? '' : '?'; + const typeScriptType = getTypeScriptType(config.type, parsedEnv.flat[key]); + const comment = config.desc ? ` /** ${config.desc} */` : ''; + + let defaultValueStr = ''; + if (config.default !== undefined) { + const formattedDefault = formatDefaultValue(config.default, config.type); + defaultValueStr = ` // Default: ${formattedDefault}`; + } + + lines.push(comment); + lines.push(` ${key}${optionalMarker}: ${typeScriptType};`); + if (defaultValueStr) { + lines.push(defaultValueStr); + } + lines.push(''); + } + + lines.push('}'); + lines.push(''); + + const nestedInterfaces = generateNestedInterfaces(parsedEnv.nested); + lines.push(nestedInterfaces); + + return lines.join('\n'); +} + +function getTypeScriptType(type: string, value?: string): string { + switch (type) { + case 'string': + return 'string'; + case 'number': + case 'int': + case 'port': + return 'number'; + case 'boolean': + return 'boolean'; + case 'email': + case 'url': + return 'string'; + case 'json': + return 'Record'; + case 'enum': { + const enumValues = value ? `'${value}'` : 'string'; + return enumValues; + } + default: + return 'string'; + } +} + +function formatDefaultValue(defaultVal: string | number | boolean, type: string): string { + if (typeof defaultVal === 'string') { + if (type === 'json') { + try { + const parsed = JSON.parse(defaultVal); + return JSON.stringify(parsed, null, 2); + } catch { + return `'${defaultVal}'`; + } + } + return `'${defaultVal}'`; + } + return String(defaultVal); +} + +function generateNestedInterfaces(obj: unknown, prefix: string = ''): string { + if (obj === null || obj === undefined || typeof obj !== 'object') { + return ''; + } + + if (Array.isArray(obj)) { + return ''; + } + + const typedObj = obj as Record; + const keys = Object.keys(typedObj); + + if (keys.length === 0) { + return ''; + } + + const lines: string[] = []; + const interfaceName = prefix ? toPascalCase(prefix) : 'NestedEnv'; + + lines.push(`export interface ${interfaceName} {`); + + for (const key of keys) { + const value = typedObj[key]; + const propertyName = toCamelCase(key); + + if (value !== null && value !== undefined && typeof value === 'object' && !Array.isArray(value)) { + const nestedInterface = generateNestedInterfaces(value, `${prefix}_${key}`); + lines.push(` ${propertyName}?: ${toPascalCase(key)};`); + lines.push(''); + lines.push(nestedInterface); + } else { + const type = inferTypeFromValue(value); + lines.push(` ${propertyName}?: ${type};`); + } + } + + lines.push('}'); + lines.push(''); + + return lines.join('\n'); +} + +function toPascalCase(str: string): string { + return str + .split('_') + .map(part => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase()) + .join(''); +} + +function toCamelCase(str: string): string { + const parts = str.split('_'); + if (parts.length === 1) return str; + return parts[0].toLowerCase() + parts.slice(1).map(p => p.charAt(0).toUpperCase() + p.slice(1).toLowerCase()).join(''); +} + +function inferTypeFromValue(value: unknown): string { + if (value === null || value === undefined) return 'unknown'; + if (typeof value === 'string') return 'string'; + if (typeof value === 'number') return 'number'; + if (typeof value === 'boolean') return 'boolean'; + if (Array.isArray(value)) return 'unknown[]'; + if (typeof value === 'object') return 'Record'; + return 'string'; +} + +export async function formatCode(code: string): Promise { + try { + const formatted = await prettier.format(code, { + parser: 'typescript', + singleQuote: true, + tabWidth: 2, + trailingComma: 'es5', + printWidth: 100 + }); + return formatted; + } catch { + return code; + } +}