@prolaxu/galaxy-api-tool
Version:
CLI tool for generating Galaxy API files (Controllers, Resources, Vue components)
173 lines (141 loc) • 6.23 kB
JavaScript
const fs = require('fs-extra');
const path = require('path');
const Handlebars = require('handlebars');
const pluralize = require('pluralize');
class Generator {
constructor(basePath = process.cwd()) {
this.basePath = basePath;
this.templatesPath = path.join(__dirname, '..', 'templates');
// Register Handlebars helpers
this.registerHelpers();
}
registerHelpers() {
Handlebars.registerHelper('capitalize', (text) => {
return text.charAt(0).toUpperCase() + text.slice(1);
});
Handlebars.registerHelper('toLowerCase', (text) => {
return text.toLowerCase();
});
Handlebars.registerHelper('pluralize', (text) => {
return pluralize(text);
});
Handlebars.registerHelper('singularize', (text) => {
return pluralize.singular(text);
});
}
async loadTemplate(templateName) {
const templatePath = path.join(this.templatesPath, templateName);
const templateContent = await fs.readFile(templatePath, 'utf8');
return Handlebars.compile(templateContent);
}
async ensureDirectory(dirPath) {
await fs.ensureDir(dirPath);
}
async writeFile(filePath, content) {
await this.ensureDirectory(path.dirname(filePath));
await fs.writeFile(filePath, content, 'utf8');
}
validateModelName(modelName) {
if (!modelName || modelName.trim() === '') {
throw new Error('Model name is required');
}
if (!/^[a-zA-Z][a-zA-Z0-9_/]*$/.test(modelName)) {
throw new Error('Model name must start with a letter and contain only letters, numbers, underscores, and slashes');
}
}
parseModelInput(modelInput) {
this.validateModelName(modelInput);
let modelName, groupFolder, importPath, fullLowerPath;
if (modelInput.includes('/')) {
groupFolder = path.dirname(modelInput);
modelName = path.basename(modelInput);
const lowerGroup = groupFolder.toLowerCase();
const lowerName = modelName.toLowerCase();
fullLowerPath = `${lowerGroup}/${lowerName}`;
importPath = `${lowerGroup}/${lowerName}`;
} else {
groupFolder = '';
modelName = modelInput;
const lowerName = modelName.toLowerCase();
fullLowerPath = lowerName;
importPath = lowerName;
}
return {
modelName,
groupFolder,
importPath,
fullLowerPath
};
}
async generateApi(modelName) {
this.validateModelName(modelName);
const data = { modelName };
// Generate Controller
const controllerTemplate = await this.loadTemplate('controller.hbs');
const controllerContent = controllerTemplate(data);
const controllerPath = path.join(this.basePath, 'src', 'GalaxyAPI', 'Controllers', `${modelName}Controller.php`);
await this.writeFile(controllerPath, controllerContent);
// Generate Request
const requestTemplate = await this.loadTemplate('request.hbs');
const requestContent = requestTemplate(data);
const requestPath = path.join(this.basePath, 'src', 'GalaxyAPI', 'Requests', `${modelName}Request.php`);
await this.writeFile(requestPath, requestContent);
// Generate Resource
const resourceTemplate = await this.loadTemplate('resource.hbs');
const resourceContent = resourceTemplate(data);
const resourcePath = path.join(this.basePath, 'src', 'GalaxyAPI', 'Resources', `${modelName}Resource.php`);
await this.writeFile(resourcePath, resourceContent);
}
async generateApiEmpty(modelName) {
this.validateModelName(modelName);
const data = { modelName };
// Generate Controller (empty version)
const controllerTemplate = await this.loadTemplate('controller-empty.hbs');
const controllerContent = controllerTemplate(data);
const controllerPath = path.join(this.basePath, 'src', 'GalaxyAPI', 'Controllers', `${modelName}Controller.php`);
await this.writeFile(controllerPath, controllerContent);
// Generate Resource
const resourceTemplate = await this.loadTemplate('resource.hbs');
const resourceContent = resourceTemplate(data);
const resourcePath = path.join(this.basePath, 'src', 'GalaxyAPI', 'Resources', `${modelName}Resource.php`);
await this.writeFile(resourcePath, resourceContent);
}
async generateViews(modelInput) {
const parsed = this.parseModelInput(modelInput);
const { modelName, groupFolder, importPath, fullLowerPath } = parsed;
const data = {
modelName,
groupFolder,
importPath,
fullLowerPath
};
// Generate Store
const storeTemplate = await this.loadTemplate('store.hbs');
const storeContent = storeTemplate(data);
const storePath = path.join(this.basePath, 'resources', 'assets', 'spa', 'stores', 'modules', fullLowerPath, `use${modelName}Store.js`);
await this.writeFile(storePath, storeContent);
// Generate Form
const formTemplate = await this.loadTemplate('form.hbs');
const formContent = formTemplate(data);
const formPath = path.join(this.basePath, 'resources', 'assets', 'spa', 'modules', fullLowerPath, `${modelName}Form.vue`);
await this.writeFile(formPath, formContent);
// Generate List
const listTemplate = await this.loadTemplate('list.hbs');
const listContent = listTemplate(data);
const listPath = path.join(this.basePath, 'resources', 'assets', 'spa', 'modules', fullLowerPath, `${modelName}ListComponent.vue`);
await this.writeFile(listPath, listContent);
// Generate Select
const selectTemplate = await this.loadTemplate('select.hbs');
const selectContent = selectTemplate(data);
const selectPath = path.join(this.basePath, 'resources', 'assets', 'spa', 'modules', fullLowerPath, `${modelName}Select.vue`);
await this.writeFile(selectPath, selectContent);
return {
...parsed,
storePath: `resources/assets/spa/stores/modules/${fullLowerPath}/use${modelName}Store.js`,
formPath: `resources/assets/spa/modules/${fullLowerPath}/${modelName}Form.vue`,
listPath: `resources/assets/spa/modules/${fullLowerPath}/${modelName}ListComponent.vue`,
selectPath: `resources/assets/spa/modules/${fullLowerPath}/${modelName}Select.vue`
};
}
}
module.exports = Generator;