template-nestjs-generator
Version:
A custom NestJS CRUD generator
140 lines (129 loc) • 6.64 kB
text/typescript
import * as ts from "typescript"
import * as fs from "fs-extra"
interface PropertyInfo {
name: string
type: string
required?: boolean
nullable?: boolean
length?: number
default?: any
relation?: string
}
export function getEntityProperties(entityFilePath: string): PropertyInfo[] {
const sourceFile = ts.createSourceFile(
entityFilePath,
fs.readFileSync(entityFilePath, "utf8"),
ts.ScriptTarget.ESNext,
true
)
const properties: PropertyInfo[] = []
let propertyInfo: PropertyInfo
ts.forEachChild(sourceFile, (node) => {
if (ts.isClassDeclaration(node)) {
node.members.forEach((member) => {
if (ts.isPropertyDeclaration(member) && member.name) {
const propertyName = member.name.getText(sourceFile)
const typeNode = member.type
const type = typeNode ? typeNode.getText(sourceFile) : "any"
// Extract specific attributes from decorators
const decorators = ts.getDecorators(member)
propertyInfo = {
name: propertyName,
type,
} as PropertyInfo
if (decorators) {
decorators.forEach((decorator) => {
const expression = decorator.expression
if (
ts.isCallExpression(expression) &&
ts.isIdentifier(expression.expression)
) {
const decoratorName =
expression.expression.getText(sourceFile)
if (
decoratorName === "Column" ||
decoratorName === "PrimaryGeneratedColumn"
) {
const args = expression.arguments
if (
args.length > 0 &&
ts.isObjectLiteralExpression(args[0])
) {
args[0].properties.forEach(
(property) => {
if (
ts.isPropertyAssignment(
property
) &&
ts.isIdentifier(
property.name
)
) {
const key =
property.name.getText(
sourceFile
)
const value =
property.initializer.getText(
sourceFile
)
if (key === "nullable") {
propertyInfo.nullable =
value === "true"
} else if (
key === "length"
) {
propertyInfo.length =
parseInt(value, 10)
} else if (
key === "default"
) {
propertyInfo.default = value
}
propertyInfo.required =
!propertyInfo.nullable
}
}
)
}
}
}
})
}
properties.push(propertyInfo)
} else if (
ts.isPropertyDeclaration(member) &&
ts.isIdentifier(member.name)
) {
const propertyName = member.name.getText(sourceFile)
const typeNode = member.type
const type = typeNode ? typeNode.getText(sourceFile) : "any"
// Check for relation decorators
const decorators = ts.getDecorators(member)
if (decorators) {
decorators.forEach((decorator) => {
const expression = decorator.expression
if (
ts.isCallExpression(expression) &&
ts.isIdentifier(expression.expression)
) {
const decoratorName =
expression.expression.getText(sourceFile)
if (
decoratorName === "OneToMany" ||
decoratorName === "ManyToOne" ||
decoratorName === "OneToOne" ||
decoratorName === "ManyToMany"
) {
propertyInfo.relation = decoratorName
}
}
})
}
properties.push({ name: propertyName, type })
}
})
}
})
return properties
}