auto-typegen
Version:
Automatically generate TypeScript interfaces from JSON data, API responses, or database schemas. Perfect for Mongoose, Sequelize, and raw data. Simplify your workflow and ensure type safety with just one function call!
90 lines (89 loc) • 3.46 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.TypeGenerator = void 0;
class TypeGenerator {
constructor() {
this.generatedInterfaces = {};
this.usedInterfaceNames = new Set(); // Track used names
}
generate(data, interfaceName = 'AutoGenerated') {
this.generatedInterfaces = {};
this.usedInterfaceNames.clear();
this.processData(data, interfaceName);
return this.formatInterfaces(interfaceName);
}
processData(data, interfaceName) {
var _a;
if (data instanceof Date)
return 'Date';
if (((_a = data === null || data === void 0 ? void 0 : data.constructor) === null || _a === void 0 ? void 0 : _a.name) === 'ObjectId')
return 'string';
if (Array.isArray(data)) {
return this.processArray(data, interfaceName);
}
if (typeof data === 'object' && data !== null) {
return this.processObject(data, interfaceName);
}
return typeof data;
}
processArray(arr, parentName) {
if (arr.length === 0)
return 'any[]';
const elementType = this.processData(arr[0], parentName);
return `${elementType}[]`;
}
processObject(obj, interfaceName) {
// Generate a unique signature for nested objects
const signature = this.getObjectSignature(obj, interfaceName);
if (this.generatedInterfaces[signature]) {
return this.generatedInterfaces[signature];
}
let uniqueName = interfaceName;
let counter = 1;
// Ensure unique interface names
while (this.usedInterfaceNames.has(uniqueName)) {
uniqueName = `${interfaceName}_${counter++}`;
}
this.usedInterfaceNames.add(uniqueName);
const interfaceBody = Object.entries(obj)
.map(([key, value]) => {
const type = this.processData(value, `${uniqueName}${this.capitalize(key)}`);
return `${key}: ${type};`;
})
.join('\n ');
const interfaceCode = `interface ${uniqueName} {\n ${interfaceBody}\n}`;
this.generatedInterfaces[signature] = uniqueName;
this.generatedInterfaces[uniqueName] = interfaceCode;
return uniqueName;
}
// Generate a recursive signature for nested objects
getObjectSignature(obj, parentName) {
return Object.entries(obj)
.sort(([a], [b]) => a.localeCompare(b))
.map(([key, value]) => {
let type;
if (Array.isArray(value)) {
type = `array:${this.processData(value[0] || {}, `${parentName}${this.capitalize(key)}`)}`;
}
else if (typeof value === 'object' && value !== null) {
type = `object:${this.getObjectSignature(value, `${parentName}${this.capitalize(key)}`)}`;
}
else {
type = typeof value;
}
return `${key}:${type}`;
})
.join(',');
}
capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
formatInterfaces(rootName) {
// Include ALL generated interfaces
return (Object.values(this.generatedInterfaces)
.filter((v) => v.includes('interface'))
.reverse()
.join('\n\n') + `\n\nexport { ${rootName} };`);
}
}
exports.TypeGenerator = TypeGenerator;