sequelize-automate
Version:
Automatically generate bare sequelize models from your database.
198 lines (177 loc) • 5.09 kB
JavaScript
const _ = require('lodash');
const { parse } = require('@babel/parser');
const { default: generate } = require('@babel/generator');
const t = require('@babel/types');
const { default: traverse } = require('@babel/traverse');
const fs = require('fs');
const { join } = require('path');
const { bigCamelCase } = require('../util/wordCase');
const {
generateOptions,
processAttributesProperties,
processOptionsProperties,
getObjectTypeAnnotation,
} = require('./common/index');
/**
* Generate codes
* @param {object} definition
* @param {object} options
*/
function generateCode(definition, options) {
const source = fs
.readFileSync(join(__dirname, './template/midway/user.text'))
.toString();
const ast = parse(source, {
sourceType: 'module',
plugins: ['typescript'],
});
traverse(ast, {
ImportDeclaration: (path) => {
const { node } = path;
if (options.isAliMidway && t.isStringLiteral(node.source, { value: 'midway' })) {
node.source = t.stringLiteral('@ali/midway');
}
},
VariableDeclarator: (path) => {
const { node } = path;
if (t.isIdentifier(node.id, { name: 'attributes' })) {
const properties = processAttributesProperties(definition.attributes);
node.init = t.objectExpression(properties);
}
if (t.isIdentifier(node.id, { name: 'options' })) {
const properties = processOptionsProperties(
node.init.properties,
definition,
);
node.init = t.objectExpression(properties);
}
},
CallExpression: (path) => {
const { node } = path;
if (
t.isMemberExpression(node.callee)
&& t.isIdentifier(node.callee.property, { name: 'define' })
) {
node.arguments[0] = t.stringLiteral(definition.modelName);
}
if (t.isIdentifier(node.callee, { name: 'providerWrapper' })) {
traverse(
node,
{
ObjectProperty: (path1) => {
const { node: node1 } = path1;
if (t.isIdentifier(node1.key, { name: 'id' })) {
node1.value = t.stringLiteral(bigCamelCase(definition.modelName));
}
},
},
{ path },
);
}
},
});
if (options.tsNoCheck) {
t.addComment(ast.program.body[0], 'leading', '@ts-nocheck', true);
}
const { code } = generate(ast, generateOptions);
return code;
}
function generateDefinition(definition) {
const source = fs
.readFileSync(join(__dirname, './template/midway/user.d.text'))
.toString();
const ast = parse(source, {
sourceType: 'module',
plugins: ['typescript'],
});
const name = `I${bigCamelCase(
definition.tableName,
)}`;
const attribute = ast.program.body[1];
attribute.declaration.id = t.identifier(`${name}Attributes`);
attribute.declaration.body = t.objectTypeAnnotation(
_.map(definition.attributes, (field, key) => {
const type = getObjectTypeAnnotation(field.type);
return Object.assign(
t.objectTypeProperty(t.identifier(key), type),
{
optional: Boolean(field.allowNull),
},
);
}),
);
const model = ast.program.body[2];
traverse(
model,
{
enter(path) {
if (path.isIdentifier({ name: 'IUserModel' })) {
const { node } = path;
node.name = `${name}Model`;
}
if (path.isIdentifier({ name: 'IUserAttributes' })) {
const { node } = path;
node.name = `${name}Attributes`;
}
},
},
{ path: model },
);
const modelStatic = ast.program.body[3];
modelStatic.declaration.id = t.identifier(`${name}ModelStatic`);
traverse(
modelStatic,
{
enter(path) {
if (path.isIdentifier({ name: 'IUserModel' })) {
const { node } = path;
node.name = `${name}Model`;
}
},
},
{ path: modelStatic },
);
const { code } = generate(ast, generateOptions);
return code;
}
function generateDB(options) {
let code = fs
.readFileSync(join(__dirname, './template/midway/user.db.text'))
.toString();
if (options.isAliMidway) {
code = code.replace('midway', '@ali/midway');
}
return code;
}
function process(definitions, options) {
const modelCodes = definitions.map((definition) => {
const { modelFileName } = definition;
const fileType = 'model';
const file = `${modelFileName}.ts`;
const code = generateCode(definition, options);
return {
file,
code,
fileType,
};
});
const definitionCodes = definitions.map((definition) => {
const { modelFileName } = definition;
const fileType = 'definition';
const file = `${modelFileName}.d.ts`;
const code = generateDefinition(definition);
return {
file,
code,
fileType,
};
});
const dbCodes = {
file: 'db.ts',
code: generateDB(options),
fileType: 'model',
};
const codes = _.concat([], modelCodes, definitionCodes, dbCodes);
return codes;
}
module.exports = process;