beyond
Version:
The Full Stack Universal Typescript Framework
253 lines (213 loc) • 5.88 kB
JavaScript
const Deployment = require('./deployment');
const TEMPLATES = require('./templates');
const { join } = require('path');
/**
* Represents a project or package file.
*
* To load the file content, the load method must be called explicitly.
* @type {Project}
*/
module.exports = class Project extends require('../file-manager') {
_id;
_version = 1;
_port;
_imprimir = true;
/**
* @deprecated
* @type {string}
* @private
*/
_fileName = 'package.json';
_templates = TEMPLATES;
skeleton = [
'name',
'version',
'title',
'description',
'license',
'layout',
'template',
{ name: 'languages', type: 'eoc' },
{ name: 'params', type: 'eoc' },
{ name: 'modules', type: 'eoc' },
{ name: 'deployment', type: 'eoc' },
'static',
{ name: 'dependencies' },
{ name: 'devDependencies' },
];
async ready() {}
#params;
get params() {
return this.#params.structure;
}
set params(value) {
this.#params.set(value);
}
get id() {
return this._id;
}
relativePath() {
return `${this.id}/${this._fileName}`;
}
#modules;
get modules() {
return this.#modules;
}
set modules(data) {
this.#modules.set(data);
}
#languages;
get languages() {
return this.#languages;
}
set languages(data) {
this.#languages.set(data);
}
#deployment;
get deployment() {
return this.#deployment;
}
set deployment(data) {
this.#deployment.set(data);
}
/**
* @returns {string|*}
*/
get modulesPath() {
return this.#modules.file.file;
}
get path() {
return this.file?.file;
}
#dependencies;
get dependencies() {
return this.#dependencies;
}
#devDependencies;
get devDependencies() {
return this.#devDependencies;
}
#loading;
constructor(path, specs = undefined) {
super(path, 'package.json');
// this.#backend = new Service(path, this);
this.#languages = new (require('./languages'))();
this.#deployment = new Deployment(this.file.dirname);
this.#params = new (require('./params'))();
this.#modules = new (require('../modules'))(path, 'modules');
this.#modules.setDefault();
specs && this._checkProperties(specs);
}
async load(update = false) {
try {
if (this.#loading || (this.loaded && !update)) {
return this.#loading.value;
}
this.#loading = Promise.pending();
await this._load();
/**
* support to validate if the project.json does not have a module entry property
*/
if (!this.file.json?.module) {
this.#modules.setDefault();
}
this.#loading.resolve();
this.#loading = undefined;
} catch (e) {
return { error: e.message, exc: e };
}
}
_setId(name) {
return (this._id = name.replace(/ /g, '-').toLowerCase());
}
async create(type, specs) {
try {
if (!type) throw 'The type of project was not specified';
const folder = this._setId(specs.name);
if (!folder) throw Error('The project instance requires a name');
if (!this._templates.hasOwnProperty(type)) {
/**
* @TODO: @julio check with felix and box
*/
throw `Does not exist a ${type} template`;
}
const { fs } = global.utils;
if (await fs.exists(this.file.dirname)) {
throw `The application is already exists in ${this.path}`;
}
const tplPath = await this.templatesPath();
if (!(await fs.exists(tplPath))) {
return { status: false, error: `${await this.templatesPackage()} package not installed.` };
}
if (!(await fs.exists(join(tplPath, this._templates[type])))) {
return { status: false, error: `Template nor found check ${tplPath} version.` };
}
const current = require('path').resolve(tplPath, this._templates[type]);
await fs.copy(current, this.file.dirname);
await this._load();
// this.#deployment.addPlatforms(specs.platforms);
/**
* set dependencies and devDependencies from package.json template
*/
const content = await this.file.readJSON();
this.#dependencies = content.dependencies;
this.#devDependencies = content.devDependencies;
this.save(specs);
await this.readFiles(specs);
specs.npm && (await this.install());
} catch (exc) {
return { status: false, error: exc.message };
}
}
install() {
return new Promise((resolve, reject) => {
const { exec } = require('child_process');
exec(
'npm install',
{
cwd: this.file.dirname,
},
(error, stdout, stderr) => {
error && console.error('error', error);
stderr && console.error('stderr', stderr);
resolve();
}
);
}).catch(e => console.trace(e));
}
async save(values = {}) {
const json = { deployment: this.#deployment.getProperties() };
return super.save({ ...values, ...json });
}
/**
* reads the template files and replaces the contents of [name] with those defined in the parameters
* @param specs
* @param dirname
* @returns {Promise<void>}
*/
async readFiles(specs, dirname) {
const { readdir, save, promises } = global.utils.fs;
dirname = dirname ?? this.file.dirname;
const files = await readdir(dirname);
let items = [];
let filenames = [];
files.forEach(file => {
if (file === 'package.json') return;
const filename = require('path').join(dirname, file);
if (!filename.includes('.')) {
//is directory
this.readFiles(specs, filename);
return;
}
filenames.push(filename);
items.push(promises.readFile(filename, { encoding: 'utf-8' }));
});
items.size = 0;
const contents = await Promise.all(items);
contents.forEach((content, index) => {
content = content.replace(/\$\[name]/gm, specs.name);
items.push(save(filenames[index], content, 'utf-8'));
});
await Promise.all(items);
}
};