@lakutata/cli
Version:
Lakutata CLI tool
180 lines (179 loc) • 8.78 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Creator = void 0;
const Information_js_1 = require("./Information.js");
const DeGitPuller_js_1 = require("../components/DeGitPuller.js");
const Spinner_js_1 = require("../components/Spinner.js");
const CreateProjectOptions_js_1 = require("../../options/CreateProjectOptions.js");
const node_path_1 = __importDefault(require("node:path"));
const promises_1 = require("node:fs/promises");
const SpecialChar_js_1 = require("../SpecialChar.js");
const lakutata_1 = require("lakutata");
const di_1 = require("lakutata/decorator/di");
const logger_1 = require("lakutata/com/logger");
const helper_1 = require("lakutata/helper");
const dto_1 = require("lakutata/decorator/dto");
const ansis_1 = __importDefault(require("ansis"));
const cli_table3_1 = __importDefault(require("cli-table3"));
const OnlineLatestVersion_1 = require("./OnlineLatestVersion");
class Creator extends lakutata_1.Provider {
/**
* Check if the target path exists
* @param targetDirectory
* @param initOnly
* @protected
*/
async checkTargetPathExistence(targetDirectory, initOnly) {
const exists = await (0, helper_1.IsExists)(targetDirectory);
if (!exists && initOnly) {
this.log.error(`${SpecialChar_js_1.charCross} The target path does not exist.`);
return this.app.exit(1);
}
await (0, promises_1.mkdir)(targetDirectory, { recursive: true });
this.log.info(`${SpecialChar_js_1.charCheck} The target path does not exist.`);
}
/**
* Check target path is a valid directory
* @param targetDirectory
* @protected
*/
async checkTargetPathIsDirectory(targetDirectory) {
const targetInfo = await (0, promises_1.stat)(targetDirectory);
if (!targetInfo.isDirectory()) {
this.log.error(`${SpecialChar_js_1.charCross} The target path is not a valid directory.`);
return this.app.exit(1);
}
this.log.info(`${SpecialChar_js_1.charCheck} The target path is a valid directory.`);
}
/**
* Check target directory is empty, if the target directory is not empty, throw error and exit
* @param targetDirectory
* @param initOnly
* @protected
*/
async checkTargetDirectoryIsEmpty(targetDirectory, initOnly) {
const files = await (0, promises_1.readdir)(targetDirectory);
if (files.length && !initOnly) {
this.log.error(`${SpecialChar_js_1.charCross} The target directory is not empty.`);
return this.app.exit(1);
}
this.log.info(`${SpecialChar_js_1.charCheck} The target directory is empty.`);
}
/**
* project information filling
* @protected
*/
async projectInformationFilling(targetPath, fields) {
const items = await (0, helper_1.Glob)(node_path_1.default.resolve(targetPath, '**/*'));
for (const item of items) {
const stats = await (0, promises_1.stat)(item);
if (!stats.isFile())
continue;
const rawContent = await (0, promises_1.readFile)(item, { encoding: 'utf-8' });
const filledContent = (0, helper_1.Templating)(rawContent, fields, { ignoreMissing: true });
if (rawContent !== filledContent)
await (0, promises_1.writeFile)(item, filledContent, { flag: 'w' });
}
}
/**
* Exec create
* @param options
*/
async create(options) {
const appName = options.name;
const appId = options.id;
const appDescription = options.description;
const authorName = options.author;
const licenseName = options.license;
const appTemplate = options.template;
const targetPath = options.overwrite ? node_path_1.default.resolve(options.path) : node_path_1.default.resolve(options.path, options.name);
const table = new cli_table3_1.default();
table.push([{ content: ansis_1.default.bold.cyan('Project Creation Information'), colSpan: 2, hAlign: 'center' }], [ansis_1.default.blue('APP ID & Project Name'), appId], [ansis_1.default.blue('APP Name'), appName], [ansis_1.default.blue('APP Description'), appDescription], [ansis_1.default.blue('Project Create Target Path'), targetPath], [ansis_1.default.blue('Project Create Mode'), options.overwrite ? ansis_1.default.yellow('Initialize project in an existing directory') : ansis_1.default.green('Create a new folder for the project')], [ansis_1.default.blue('Project Author Name'), authorName], [ansis_1.default.blue('Project License'), licenseName], [ansis_1.default.blue('Project Template Repository'), this.puller.getGitSource(appTemplate)]);
console.log(table.toString());
await new Promise(resolve => {
let timeLeft = 15;
const interval = setInterval(() => {
timeLeft -= 1;
if (!timeLeft) {
clearInterval(interval);
this.spinner.stop();
return resolve();
}
}, 1000);
this.spinner.start(() => `Please confirm the project creation information; the creation process will commence in ${timeLeft} seconds.`);
});
await this.checkTargetPathExistence(targetPath, options.overwrite);
await this.checkTargetPathIsDirectory(targetPath);
await this.checkTargetDirectoryIsEmpty(targetPath, options.overwrite);
this.spinner.start('Pulling');
await this.puller.pull(appTemplate, targetPath);
this.spinner.stop();
this.log.info(`${SpecialChar_js_1.charCheck} Template pulled.`);
this.spinner.start('Filling information');
await this.projectInformationFilling(targetPath, {
$APP_NAME: appName,
$APP_ID: appId,
$APP_DESC: appDescription,
$APP_AUTHOR: authorName,
$APP_LICENSE: licenseName
});
this.spinner.stop();
this.log.info(`${SpecialChar_js_1.charCheck} Project information filling completed.`);
this.spinner.start('Installing');
const { execa } = await import('execa');
await execa('npm', ['install'], { cwd: targetPath });
await execa('npm', ['install', `${this.onlineVersion.getName()}@${await this.onlineVersion.getVersion()}`], { cwd: targetPath });
this.spinner.stop();
this.log.info(`${SpecialChar_js_1.charCheck} Project has been successfully created.`);
}
}
exports.Creator = Creator;
__decorate([
(0, di_1.Inject)(lakutata_1.Application),
__metadata("design:type", lakutata_1.Application)
], Creator.prototype, "app", void 0);
__decorate([
(0, di_1.Inject)('log'),
__metadata("design:type", logger_1.Logger)
], Creator.prototype, "log", void 0);
__decorate([
(0, di_1.Inject)('spinner'),
__metadata("design:type", Spinner_js_1.Spinner)
], Creator.prototype, "spinner", void 0);
__decorate([
(0, di_1.Inject)('puller'),
__metadata("design:type", DeGitPuller_js_1.DeGitPuller)
], Creator.prototype, "puller", void 0);
__decorate([
(0, di_1.Inject)('info'),
__metadata("design:type", Information_js_1.Information)
], Creator.prototype, "frameworkInfo", void 0);
__decorate([
(0, di_1.Inject)('onlineVersion'),
__metadata("design:type", OnlineLatestVersion_1.OnlineLatestVersion
/**
* Check if the target path exists
* @param targetDirectory
* @param initOnly
* @protected
*/
)
], Creator.prototype, "onlineVersion", void 0);
__decorate([
(0, dto_1.Accept)(CreateProjectOptions_js_1.CreateProjectOptions.required()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [CreateProjectOptions_js_1.CreateProjectOptions]),
__metadata("design:returntype", Promise)
], Creator.prototype, "create", null);