Skip to content

Commit

Permalink
Merge pull request #5 from nealwp/updates/v1.1
Browse files Browse the repository at this point in the history
Updates/v1.1
  • Loading branch information
nealwp authored May 14, 2023
2 parents c267e65 + e71ea4a commit 59efd8d
Show file tree
Hide file tree
Showing 14 changed files with 553 additions and 93 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules
.vscode
dist
dist
coverage
31 changes: 29 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "smodg",
"version": "1.0.3",
"version": "1.1.0",
"description": "Generate basic Sequelize models from TypeScript declaration files",
"main": "index.js",
"bin": {
Expand All @@ -23,13 +23,15 @@
"license": "ISC",
"devDependencies": {
"@types/jest": "^29.4.1",
"@types/minimist": "^1.2.2",
"copyfiles": "^2.4.1",
"jest": "^29.5.0",
"rimraf": "^4.4.0",
"ts-jest": "^29.0.5",
"ts-node": "^10.9.1"
},
"dependencies": {
"minimist": "^1.2.8",
"typescript": "^4.9.5"
}
}
8 changes: 7 additions & 1 deletion src/formatters.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/**
* Convert a string to snake_case
* */
const snakeCase = (str: string) => {
return str.replace(/[A-Z]/g, (match, index) => {
if (index === 0) {
Expand All @@ -10,6 +13,9 @@ const snakeCase = (str: string) => {
});
}

/**
* Convert a string to kebab-case
*/
const kebabCase = (str: string) => {
return str.replace(/[A-Z]/g, (match, index) => {
if (index === 0) {
Expand All @@ -22,4 +28,4 @@ const kebabCase = (str: string) => {
});
}

export { snakeCase, kebabCase }
export { snakeCase, kebabCase }
149 changes: 137 additions & 12 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,152 @@
#!/usr/bin/env node

import fs from 'node:fs'
import { argv } from 'node:process';
import minimist from 'minimist';
import { generateModelInputs } from './parser';
import { modelTemplate } from './templates/model.smodg';
import { modelTemplate, migrationTemplate } from './templates';
import { kebabCase } from './formatters';
import { version } from '../package.json'

try {
const sourceCode = fs.readFileSync(argv[2], 'utf-8')
const modelInputs = generateModelInputs(sourceCode)
export const main = (args: minimist.ParsedArgs) => {

const model = modelTemplate(modelInputs)
const filePath = args._[0]

let generateMigrationFile = false
let schema = ""
let outputDir = 'src/models'

if(args.h || args.help){
printHelp()
return
}

if(args.v || args.version){
printVersion()
return
}

if(args.migration){
generateMigrationFile = true
}

if(args.s){
schema = args.s
} else if (args.schema) {
schema = args.schema
}

if(args.o){
outputDir = args.o
} else if (args.outputDir) {
outputDir = args.outputDir
}

if (!fs.existsSync('./src/models')) {
fs.mkdirSync('./src/models')
if(!filePath){
console.error('error: path to type file is required!')
return
}

try {
fs.writeFileSync(`./src/models/${kebabCase(modelInputs.modelName)}.model.ts`, model)

const sourceCode = fs.readFileSync(filePath, 'utf-8')
const modelInputs = generateModelInputs(sourceCode, schema)
const model = modelTemplate(modelInputs)

writeModelToFile(model, { outputDir, modelName: modelInputs.modelName })

if (generateMigrationFile) {

const migrationInputs = {
tableDefinition: modelInputs.tableDefinition,
columnDefinitions: modelInputs.columnDefinitions
}

const migration = migrationTemplate(migrationInputs)
writeMigrationToFile(migration, {modelName: modelInputs.modelName})
}
} catch(error) {
console.error(error)
}

}

export const writeModelToFile = (model: string, options: {outputDir: string, modelName: string}) => {

if (!fs.existsSync(`./${options.outputDir}`)) {
fs.mkdirSync(`./${options.outputDir}`)
}

try {
fs.writeFileSync(`./${options.outputDir}/${kebabCase(options.modelName)}.model.ts`, model)
} catch (error) {
console.error(error)
}
}

const writeMigrationToFile = (migration: string, options: {modelName: string}) => {

if (!fs.existsSync(`./src/migrations`)) {
fs.mkdirSync(`./src/migrations`)
}

try {
fs.writeFileSync(`./src/migrations/${dateFormatString()}-Create-Table-${options.modelName}.ts`, migration)
} catch(error) {
console.error(error)
}
}


const dateFormatString = () => {
const currentDate = new Date();
const year = currentDate.getFullYear();
const month = String(currentDate.getMonth() + 1).padStart(2, '0');
const day = String(currentDate.getDate()).padStart(2, '0');
const hours = String(currentDate.getHours()).padStart(2, '0');
const minutes = String(currentDate.getMinutes()).padStart(2, '0');
const seconds = String(currentDate.getSeconds()).padStart(2, '0');

return `${year}.${month}.${day}T${hours}.${minutes}.${seconds}`;
}

export const printHelp = () => {
const helpText = `
=================================
Sequelize Model Generator
=================================
Generate a Sequelize model based on a TypeScript type declaration.
Usage:
smodg [options] <filepath>
Options:
--help, -h show help
--migration create an Umzug migration. default: false
--outputDir=PATH, model output directory, relative to current path. default: "src/models"
-o PATH
--schema=NAME specify a schema. default is no schema
-s NAME
--version, -v print installed version
`

console.log(helpText)
}

export const printVersion = () => {
console.log(`smodg v${version}`)
}


const args = minimist(process.argv.slice(2), {
stopEarly: true,
boolean: true
})

} catch (error) {
console.error(error)
}
main(args)
83 changes: 83 additions & 0 deletions src/models/.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@

import {
Column,
Table,
Model,
DataType,
CreatedAt,
UpdatedAt,
ForeignKey,
HasMany,
} from 'sequelize-typescript';

import { as Type } from '@_YOUR_TYPES'
import { ModelAttributeColumnOptions } from 'sequelize';

interface CreationAttributes extends Type {}

interface Attributes extends CreationAttributes {
id: number;
createdBy: string;
createdDate: Date;
updatedBy: string;
updatedDate: Date;
}

type Keys = keyof Attributes

interface ColumnOptions extends ModelAttributeColumnOptions {
field: string
}

export const tableDefinition = {
tableName: '',
}

export const columnDefinition: Record<Keys, ColumnOptions> = {
id: {
field: "id",
type: DataType.INTEGER,
primaryKey: true,
autoIncrement: true,
},

createdBy: {
field: "created_by",
type: DataType.STRING,
},
createdDate: {
field: "created_date",
type: DataType.DATE,
},
updatedBy: {
field: "updated_by",
type: DataType.STRING,
},
updatedDate: {
field: "updated_date",
type: DataType.DATE,
},
}

@Table(tableDefinition)
export class
extends Model<Attributes, CreationAttributes>
implements Attributes {
@Column(columnDefinition.id)
id!: number;

@Column(columnDefinition.createdBy)
createdBy!: string;

@CreatedAt
@Column(columnDefinition.createdDate)
createdDate!: Date;

@Column(columnDefinition.updatedBy)
updatedBy!: string;

@UpdatedAt
@Column(columnDefinition.updatedDate)
updatedDate!: Date;
}

Loading

0 comments on commit 59efd8d

Please sign in to comment.