refactor utility methods to naming.utils.ts
This commit is contained in:
parent
ed2388d7f6
commit
61338cc377
@ -8,6 +8,7 @@ import * as fs from 'fs';
|
|||||||
import { promises as fsPromises } from 'fs';
|
import { promises as fsPromises } from 'fs';
|
||||||
import { TableColumn } from 'typeorm';
|
import { TableColumn } from 'typeorm';
|
||||||
import { GenericTableGeneratorService } from './generic-table-generator.service';
|
import { GenericTableGeneratorService } from './generic-table-generator.service';
|
||||||
|
import { mapDbToTsType, toCamelCase, toKebabCase, toPascalCase, toSingular } from '../utils/naming.utils';
|
||||||
|
|
||||||
// Interface for structured field metadata passed to templates
|
// Interface for structured field metadata passed to templates
|
||||||
interface FieldDefinition {
|
interface FieldDefinition {
|
||||||
@ -42,7 +43,7 @@ export class AngularGeneratorService {
|
|||||||
const fields: FieldDefinition[] = (columns || [])
|
const fields: FieldDefinition[] = (columns || [])
|
||||||
.map(c => ({
|
.map(c => ({
|
||||||
name: c.name,
|
name: c.name,
|
||||||
tsType: this.mapDbToTsType(c.type),
|
tsType: mapDbToTsType(c.type),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
names['modelProperties'] = fields.map(f => `${f.name}: ${f.tsType};`).join('\n ');
|
names['modelProperties'] = fields.map(f => `${f.name}: ${f.tsType};`).join('\n ');
|
||||||
@ -126,15 +127,6 @@ private async generateTableComponent(tableName: string, columns: TableColumn[],
|
|||||||
return `<div class="form-control">${label}\n ${input}</div>`;
|
return `<div class="form-control">${label}\n ${input}</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private mapDbToTsType(dbType: string): string {
|
|
||||||
if (dbType.includes('int') || dbType.includes('serial')) return 'number';
|
|
||||||
if (['float', 'double', 'decimal', 'numeric', 'real'].includes(dbType)) return 'number';
|
|
||||||
if (dbType.includes('char') || dbType.includes('text') || dbType === 'uuid') return 'string';
|
|
||||||
if (dbType === 'boolean' || dbType === 'bool') return 'boolean';
|
|
||||||
if (dbType.includes('date') || dbType.includes('time')) return 'Date';
|
|
||||||
return 'any';
|
|
||||||
}
|
|
||||||
|
|
||||||
// ... (All other generate... and naming methods are unchanged)
|
// ... (All other generate... and naming methods are unchanged)
|
||||||
private async generateModel(names: NamingConvention, featureDir: string) {
|
private async generateModel(names: NamingConvention, featureDir: string) {
|
||||||
const modelsDir = path.join(featureDir, 'models');
|
const modelsDir = path.join(featureDir, 'models');
|
||||||
@ -183,36 +175,16 @@ private async generateTableComponent(tableName: string, columns: TableColumn[],
|
|||||||
fs.writeFileSync(path.join(compDir, `${names.singular}-form.component.html`), htmlContent);
|
fs.writeFileSync(path.join(compDir, `${names.singular}-form.component.html`), htmlContent);
|
||||||
}
|
}
|
||||||
private getNamingConvention(tableName: string): NamingConvention {
|
private getNamingConvention(tableName: string): NamingConvention {
|
||||||
const singular = this.toSingular(tableName);
|
const singular = toSingular(tableName);
|
||||||
const pascal = this.toPascalCase(singular);
|
const pascal = toPascalCase(singular);
|
||||||
return {
|
return {
|
||||||
singular: this.toKebabCase(singular),
|
singular: toKebabCase(singular),
|
||||||
plural: this.toKebabCase(tableName),
|
plural: toKebabCase(tableName),
|
||||||
pascal: pascal,
|
pascal: pascal,
|
||||||
camel: this.toCamelCase(singular),
|
camel: toCamelCase(singular),
|
||||||
title: pascal,
|
title: pascal,
|
||||||
kebab: this.toKebabCase(singular),
|
kebab: toKebabCase(singular),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
private toSingular(name: string): string {
|
|
||||||
const kebab = this.toKebabCase(name);
|
|
||||||
if (kebab.endsWith('ies')) return kebab.slice(0, -3) + 'y';
|
|
||||||
return kebab.endsWith('s') ? kebab.slice(0, -1) : kebab;
|
|
||||||
}
|
|
||||||
private toPascalCase(text: string): string {
|
|
||||||
return this.toKebabCase(text)
|
|
||||||
.split('-')
|
|
||||||
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
||||||
.join('');
|
|
||||||
}
|
|
||||||
private toCamelCase(text: string): string {
|
|
||||||
const pascal = this.toPascalCase(text);
|
|
||||||
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
||||||
}
|
|
||||||
private toKebabCase(text: string): string {
|
|
||||||
return text
|
|
||||||
.replace(/_/g, '-') // Replace underscores with hyphens
|
|
||||||
.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2') // Add hyphen before uppercase letters
|
|
||||||
.toLowerCase();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -7,6 +7,7 @@ import { TableColumn } from 'typeorm';
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import { promises as fsPromises } from 'fs';
|
import { promises as fsPromises } from 'fs';
|
||||||
|
import { toCamelCase, toKebabCase, toPascalCase, toSingular } from '../utils/naming.utils';
|
||||||
|
|
||||||
interface NamingConvention {
|
interface NamingConvention {
|
||||||
[key: string]: string;
|
[key: string]: string;
|
||||||
@ -98,34 +99,21 @@ export class CrudGeneratorService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getNamingConvention(tableName: string, columns?: TableColumn[]): NamingConvention {
|
private getNamingConvention(tableName: string, columns?: TableColumn[]): NamingConvention {
|
||||||
const singular = this.toSingular(tableName);
|
const singular = toSingular(tableName);
|
||||||
const pascal = this.toPascalCase(singular);
|
const pascal = toPascalCase(singular);
|
||||||
const searchableFields = (columns || [])
|
const searchableFields = (columns || [])
|
||||||
.filter(c => this.isStringBasedType(c.type))
|
.filter(c => this.isStringBasedType(c.type))
|
||||||
.map(c => `'${c.name}'`)
|
.map(c => `'${c.name}'`)
|
||||||
.join(',\n ');
|
.join(',\n ');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
singular: this.toKebabCase(singular),
|
singular: toKebabCase(singular),
|
||||||
plural: this.toKebabCase(tableName),
|
plural: toKebabCase(tableName),
|
||||||
pascal: pascal,
|
pascal: pascal,
|
||||||
camel: this.toCamelCase(singular),
|
camel: toCamelCase(singular),
|
||||||
|
kebab: toKebabCase(singular),
|
||||||
searchableFields: searchableFields
|
searchableFields: searchableFields
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
private toSingular(name: string): string {
|
|
||||||
const kebab = this.toKebabCase(name);
|
|
||||||
if (kebab.endsWith('ies')) return kebab.slice(0, -3) + 'y';
|
|
||||||
return kebab.endsWith('s') ? kebab.slice(0, -1) : kebab;
|
|
||||||
}
|
|
||||||
private toPascalCase(text: string): string {
|
|
||||||
return this.toKebabCase(text).split('-').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join('');
|
|
||||||
}
|
|
||||||
private toCamelCase(text: string): string {
|
|
||||||
const pascal = this.toPascalCase(text);
|
|
||||||
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
||||||
}
|
|
||||||
private toKebabCase(text: string): string {
|
|
||||||
return text.replace(/_/g, '-').replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -7,6 +7,7 @@ import { TemplateService } from './template.service'; // <-- 1. IMPORT TemplateS
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import { promises as fsPromises } from 'fs';
|
import { promises as fsPromises } from 'fs';
|
||||||
|
import { mapDbToTsType, toPascalCase, toSingular } from '../utils/naming.utils';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class EntityGeneratorService {
|
export class EntityGeneratorService {
|
||||||
@ -38,14 +39,14 @@ export class EntityGeneratorService {
|
|||||||
const columns = table.columns;
|
const columns = table.columns;
|
||||||
console.log(`Found ${columns.length} columns in table "${tableName}".`);
|
console.log(`Found ${columns.length} columns in table "${tableName}".`);
|
||||||
|
|
||||||
const singularName = this.toSingular(tableName);
|
const singularName = toSingular(tableName);
|
||||||
const className = this.toPascalCase(singularName);
|
const className = toPascalCase(singularName);
|
||||||
|
|
||||||
const props = columns
|
const props = columns
|
||||||
.map((col) => {
|
.map((col) => {
|
||||||
const typeormDecorator = this.getDecorator(col);
|
const typeormDecorator = this.getDecorator(col);
|
||||||
const validationDecorators = this.getValidationDecorators(col);
|
const validationDecorators = this.getValidationDecorators(col);
|
||||||
const tsType = this.mapDbToTsType(col.type);
|
const tsType = mapDbToTsType(col.type);
|
||||||
const nullable = col.isNullable ? ' | null' : '';
|
const nullable = col.isNullable ? ' | null' : '';
|
||||||
const defaultValue = col.default ? ` = ${this.formatDefaultValue(col)}` : '';
|
const defaultValue = col.default ? ` = ${this.formatDefaultValue(col)}` : '';
|
||||||
const allDecorators = [typeormDecorator, validationDecorators].filter(Boolean).join('\n ');
|
const allDecorators = [typeormDecorator, validationDecorators].filter(Boolean).join('\n ');
|
||||||
@ -96,7 +97,7 @@ export class EntityGeneratorService {
|
|||||||
decorators.push('@IsOptional()');
|
decorators.push('@IsOptional()');
|
||||||
}
|
}
|
||||||
|
|
||||||
const tsType = this.mapDbToTsType(column.type);
|
const tsType = mapDbToTsType(column.type);
|
||||||
switch (tsType) {
|
switch (tsType) {
|
||||||
case 'string':
|
case 'string':
|
||||||
decorators.push('@IsString()');
|
decorators.push('@IsString()');
|
||||||
@ -160,38 +161,4 @@ export class EntityGeneratorService {
|
|||||||
return column.default;
|
return column.default;
|
||||||
}
|
}
|
||||||
|
|
||||||
private mapDbToTsType(dbType: string): string {
|
|
||||||
if (dbType.includes('int') || dbType.includes('serial')) return 'number';
|
|
||||||
if (['float', 'double', 'decimal', 'numeric', 'real'].includes(dbType)) return 'number';
|
|
||||||
if (dbType.includes('char') || dbType.includes('text') || dbType === 'uuid') return 'string';
|
|
||||||
if (dbType === 'boolean' || dbType === 'bool') return 'boolean';
|
|
||||||
if (dbType.includes('date') || dbType.includes('time')) return 'Date';
|
|
||||||
return 'any';
|
|
||||||
}
|
|
||||||
|
|
||||||
private toSingular(name: string): string {
|
|
||||||
if (name.endsWith('ies')) {
|
|
||||||
return name.slice(0, -3) + 'y';
|
|
||||||
}
|
|
||||||
return name.endsWith('s') ? name.slice(0, -1) : name;
|
|
||||||
}
|
|
||||||
|
|
||||||
private toPascalCase(text: string): string {
|
|
||||||
return this.toKebabCase(text)
|
|
||||||
.split('-')
|
|
||||||
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
||||||
.join('');
|
|
||||||
}
|
|
||||||
|
|
||||||
private toCamelCase(text: string): string {
|
|
||||||
const pascal = this.toPascalCase(text);
|
|
||||||
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private toKebabCase(text: string): string {
|
|
||||||
return text
|
|
||||||
.replace(/_/g, '-') // Replace underscores with hyphens
|
|
||||||
.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2') // Add hyphen before uppercase letters
|
|
||||||
.toLowerCase();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -5,6 +5,7 @@ import { TableColumn } from 'typeorm';
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import { promises as fsPromises } from 'fs';
|
import { promises as fsPromises } from 'fs';
|
||||||
|
import { mapDbToTsType } from '../utils/naming.utils';
|
||||||
|
|
||||||
interface FieldDefinition { name: string; tsType: string; }
|
interface FieldDefinition { name: string; tsType: string; }
|
||||||
interface NamingConvention { [key: string]: string; /*...*/ }
|
interface NamingConvention { [key: string]: string; /*...*/ }
|
||||||
@ -23,7 +24,7 @@ export class GenericTableGeneratorService {
|
|||||||
|
|
||||||
const fields: FieldDefinition[] = columns.map(c => ({
|
const fields: FieldDefinition[] = columns.map(c => ({
|
||||||
name: c.name,
|
name: c.name,
|
||||||
tsType: this.mapDbToTsType(c.type),
|
tsType: mapDbToTsType(c.type),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
names['columnDefinitions'] = this.buildColumnDefinitions(fields);
|
names['columnDefinitions'] = this.buildColumnDefinitions(fields);
|
||||||
@ -75,12 +76,5 @@ export class GenericTableGeneratorService {
|
|||||||
.join('\n');
|
.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
private mapDbToTsType(dbType: string): string {
|
|
||||||
if (dbType.includes('int') || dbType.includes('serial')) return 'number';
|
|
||||||
if (['float', 'double', 'decimal', 'numeric', 'real'].includes(dbType)) return 'number';
|
|
||||||
if (dbType.includes('char') || dbType.includes('text') || dbType === 'uuid') return 'string';
|
|
||||||
if (dbType === 'boolean' || dbType === 'bool') return 'boolean';
|
|
||||||
if (dbType.includes('date') || dbType.includes('time')) return 'Date';
|
|
||||||
return 'any';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
51
src/utils/naming.utils.ts
Normal file
51
src/utils/naming.utils.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// dvbooking-cli/src/utils/naming.utils.ts
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts any string to kebab-case.
|
||||||
|
* e.g., 'user_roles' -> 'user-roles', 'UserRoles' -> 'user-roles'
|
||||||
|
*/
|
||||||
|
export function toKebabCase(text: string): string {
|
||||||
|
return text
|
||||||
|
.replace(/_/g, '-') // Replace underscores with hyphens
|
||||||
|
.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2') // Add hyphen before uppercase letters
|
||||||
|
.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a kebab-cased string to its singular form.
|
||||||
|
*/
|
||||||
|
export function toSingular(name: string): string {
|
||||||
|
const kebab = toKebabCase(name);
|
||||||
|
if (kebab.endsWith('ies')) return kebab.slice(0, -3) + 'y';
|
||||||
|
return kebab.endsWith('s') ? kebab.slice(0, -1) : kebab;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a kebab-cased string to PascalCase.
|
||||||
|
*/
|
||||||
|
export function toPascalCase(text: string): string {
|
||||||
|
return toKebabCase(text)
|
||||||
|
.split('-')
|
||||||
|
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
||||||
|
.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a kebab-cased string to camelCase.
|
||||||
|
*/
|
||||||
|
export function toCamelCase(text: string): string {
|
||||||
|
const pascal = toPascalCase(text);
|
||||||
|
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps database types to TypeScript types.
|
||||||
|
*/
|
||||||
|
export function mapDbToTsType(dbType: string): string {
|
||||||
|
if (dbType.includes('int') || dbType.includes('serial')) return 'number';
|
||||||
|
if (['float', 'double', 'decimal', 'numeric', 'real'].includes(dbType)) return 'number';
|
||||||
|
if (dbType.includes('char') || dbType.includes('text') || dbType === 'uuid') return 'string';
|
||||||
|
if (dbType === 'boolean' || dbType === 'bool') return 'boolean';
|
||||||
|
if (dbType.includes('date') || dbType.includes('time')) return 'Date';
|
||||||
|
return 'any';
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user