Initial upload with CI/CD workflow
Some checks failed
CI / test (push) Has been cancelled

This commit is contained in:
2026-01-31 20:27:38 +00:00
parent 2a52f5ba91
commit f3c1b50205

159
src/utils/typeGenerator.ts Normal file
View File

@@ -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<string, unknown>';
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<string, unknown>;
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<string, unknown>';
return 'string';
}
export async function formatCode(code: string): Promise<string> {
try {
const formatted = await prettier.format(code, {
parser: 'typescript',
singleQuote: true,
tabWidth: 2,
trailingComma: 'es5',
printWidth: 100
});
return formatted;
} catch {
return code;
}
}