periodicjs
Version:
Periodic is a rapid enterprise application framework for data driven web and mobile applications.
370 lines (341 loc) • 11.7 kB
JavaScript
;
const fs = require('fs-extra');
const path = require('path');
const structurePath = path.resolve(__dirname, './__EXT_CONTAINER_STRUCTURE');
function getExtensionPaths(options) {
if (options.source !== 'npm') {
throw new Error('invalid extension type');
}
return {
package: path.join(this.config.app_root, 'node_modules', options.name, 'package.json'),
ext: path.join(this.config.app_root, 'node_modules', options.name, 'periodicjs.ext.json'),
};
}
function getExtensionDoc(options) {
const createdat = new Date(); //Date.now();
const updatedat = new Date(); //Date.now();
const { ext_package_json, ext_config_json, ext_source, } = options;
// console.log({ ext_config_json });
const ext = Object.assign({},
ext_config_json, {
name: ext_package_json.name,
version: ext_package_json.version,
author: ext_package_json.author,
contributors: ext_package_json.contributors,
description: ext_package_json.description,
source: ext_source,
enabled: (typeof options.enabled === 'boolean') ? options.enabled : true,
createdat,
updatedat,
});
// console.log({ ext_package_json, ext_config_json, ext_source, ext })
if (!ext.name) {
throw new Error('Extension package.json is missing a name');
}
if (!ext.version) {
throw new Error('Extension package.json is missing a version');
}
if (typeof ext.periodic_type !== 'number') {
throw new Error('Extension periodicjs.ext.json is missing a periodic_type classification (0-core, 1-communication, 2-auth, 3-uac, 4-api, 5-admin,6-data,7-ui)');
}
if (typeof ext.periodic_priority !== 'number') {
throw new Error('Extension periodicjs.ext.json is missing a periodic_priority');
}
if (!ext.periodic_compatibility) {
throw new Error('Extension periodicjs.ext.json is missing a periodic_compatibility');
}
if (!ext.periodic_config) {
throw new Error('Extension periodicjs.ext.json is missing a periodic_config');
}
return ext;
}
function create(options) {
return new Promise((resolve, reject) => {
try {
const newdocOptions = Object.assign({}, options);
if (typeof options === 'string') {
newdocOptions.source = 'npm';
newdocOptions.name = options;
}
const ext_source = newdocOptions.source;
const extensionDB = this.datas.get('extension');
const extPath = getExtensionPaths.call(this, newdocOptions);
let createdExt;
switch (ext_source) {
case 'npm':
default:
Promise.all([
fs.readJSON(extPath.package),
fs.readJSON(extPath.ext),
])
.then(results => {
const [ext_package_json, ext_config_json, ] = results;
const newdoc = getExtensionDoc({ ext_package_json, ext_config_json, ext_source, });
if (this.extensions && this.extensions.has(newdoc.name)) {
const deleteOptions = this.extensions.get(newdoc.name)._id
?{
id: this.extensions.get(newdoc.name)._id.toString(),
docid: '_id',
}
: {
query: {
name:this.extensions.get(newdoc.name),
},
};
extensionDB.delete(deleteOptions)
.then((deleteStatus) => {
return extensionDB.create({ newdoc, });
})
.catch(reject);
} else {
return extensionDB.create({ newdoc, });
}
})
.then(createdDoc => {
createdExt = createdDoc;
return this.tasks.resetExtensions();
})
.then(resetedExtensions => {
const extPath = path.join(this.config.app_root, 'node_modules', newdocOptions.name);
const extPubPath = path.join(extPath, 'public');
const appPubExtPath = path.join(this.config.app_root, 'public/extensions', newdocOptions.name);
if (fs.existsSync(extPubPath)) {
fs.copy(extPubPath, appPubExtPath, { overwrite: false, })
.then(() => {
resolve(createdExt);
})
.catch(reject);
} else {
resolve(createdExt);
}
})
.catch(reject);
break;
}
} catch (e) {
reject(e);
}
});
}
function update(options) {
return new Promise((resolve, reject) => {
const { ext, _id, } = options;
const createdat = Date.now();
const updatedat = Date.now();
const extensionDB = this.datas.get('extension');
let updatedDoc;
try {
extensionDB.update({
updatedoc: Object.assign({},
ext,
(_id) ? { _id, } : {}, {
createdat,
updatedat,
}),
})
.then(updatedExt => {
updatedDoc = updatedExt;
return this.tasks.resetExtensions();
})
.then(resetedExtensions => {
resolve(updatedDoc);
})
.catch(reject);
// resolve();
} catch (e) {
reject(e);
}
});
}
function remove(options) {
return new Promise((resolve, reject) => {
let { name, _id, } = options;
const extensionDB = this.datas.get('extension');
let deletedDoc;
try {
if (typeof options === 'string') {
name = options;
}
// this.logger.info({ name, _id, });
if (_id) {
extensionDB.delete({
id: _id.toString(),
docid:'_id',
})
.then(result => {
// console.log({result,options});
deletedDoc = result;
return this.tasks.resetExtensions();
})
.then(resetedExtensions => {
// console.log('DELETED ID',{deletedDoc})
resolve(deletedDoc);
})
.catch(reject);
resolve();
} else {
extensionDB.load({ docid: 'name', query: name, })
.then(result => {
if (!result) {
resolve('extension not found');
} else {
const deleteOptions = result._id
?{
id: result._id.toString(),
docid:'_id',
}
: {
query: {
name,
},
};
return extensionDB.delete(deleteOptions);
}
})
.then(result => {
deletedDoc = result;
return this.tasks.resetExtensions();
})
.then(resetedExtensions => {
// console.log({deletedDoc,options});
resolve(deletedDoc);
})
.catch(reject);
}
} catch (e) {
reject(e);
}
});
}
function list(options) {
return new Promise((resolve, reject) => {
try {
this.datas.get('extension')
.search({
query: {},
limit: 1000,
sort: {
periodic_type: 1,
periodic_priority: 1,
},
//$p.crud.ext.list().then(console.log).catch(console.error);
// $p.datas.get('extension').search({ query:{}, limit:1000,
// sort: [
// [ 'periodic_type', 'ASC' ],
// [ 'periodic_priority', 'ASC' ],
// ],
// }).then(result => { console.log({ result }) }).catch(console.error);
})
.then(resolve)
.catch(reject);
} catch (e) {
reject(e);
}
});
}
function init(container, options) {
//
return new Promise((resolve, reject) => {
try {
const extensionName = options.toString();
const extensionPath = (container) ?
path.join(this.config.app_root, 'content/container', extensionName) :
path.join(this.config.app_root, 'node_modules', extensionName);
const extensionPackageJsonPath = path.join(extensionPath, 'package.json');
//create directory for extension
fs.ensureDir(extensionPath)
.then(() => {
//copy structure
return fs.copy(structurePath, extensionPath, { overwrite: false, });
})
.then(() => {
return fs.readJSON(extensionPackageJsonPath);
})
.then(extPackageJson => {
const updatedJSON = Object.assign({}, extPackageJson);
updatedJSON.name = extensionName;
updatedJSON.scripts.postinstall = `cd ../../ && periodicjs aex ${extensionName}`;
updatedJSON.scripts.postuninstall = `cd ../../ && periodicjs rex ${extensionName}`;
updatedJSON.name = extensionName;
//update package.json
return fs.outputJSON(extensionPackageJsonPath, updatedJSON, { spaces: 2, });
})
.then(() => {
//update readme
resolve(fs.outputFile(path.join(extensionPath, 'README.md'), generateREADME({ extensionName, })));
})
.catch(reject);
} catch (e) {
reject(e);
}
});
}
function generateREADME(options) {
const { extensionName, repoUserName = 'githubUserOrgName', repoPackageName = '', } = options;
return `# ${extensionName} [](https://coveralls.io/github/${repoUserName}/${repoPackageName || extensionName}?branch=master) [](https://travis-ci.org/${repoUserName}/${repoPackageName || extensionName})
A simple extension.
[API Documentation](https://github.com/${repoUserName}/${repoPackageName || extensionName}/blob/master/doc/api.md)
## Usage
### CLI TASK
You can preform a task via CLI
\`\`\`
$ cd path/to/application/root
### Using the CLI
$ periodicjs ext ${extensionName} hello
### Calling Manually
$ node index.js --cli --command --ext --name=${extensionName} --task=hello
\`\`\`
## Configuration
You can configure ${extensionName}
### Default Configuration
\`\`\`javascript
{
settings: {
defaults: true,
},
databases: {
},
};
\`\`\`
## Installation
### Installing the Extension
Install like any other extension, run \`npm run install ${extensionName}\` from your periodic application root directory and then normally you would run \`periodicjs addExtension ${extensionName}\`, but this extension does this in the post install npm script.
\`\`\`
$ cd path/to/application/root
$ npm run install ${extensionName}
$ periodicjs addExtension ${extensionName} //this extension does this in the post install script
\`\`\`
### Uninstalling the Extension
Run \`npm run uninstall ${extensionName}\` from your periodic application root directory and then normally you would run \`periodicjs removeExtension ${extensionName}\` but this extension handles this in the npm post uninstall script.
\`\`\`
$ cd path/to/application/root
$ npm run uninstall ${extensionName}
$ periodicjs removeExtension ${extensionName} // this is handled in the npm postinstall script
\`\`\`
## Testing
*Make sure you have grunt installed*
\`\`\`
$ npm install -g grunt-cli
\`\`\`
Then run grunt test or npm test
\`\`\`
$ grunt test && grunt coveralls #or locally $ npm test
\`\`\`
For generating documentation
\`\`\`
$ grunt doc
$ jsdoc2md commands/**/*.js config/**/*.js controllers/**/*.js transforms/**/*.js utilities/**/*.js index.js > doc/api.md
\`\`\`
## Notes
* Check out https://github.com/repetere/periodicjs for the full Periodic Documentation`;
}
module.exports = {
getExtensionPaths,
getExtensionDoc,
generateREADME,
create,
remove,
update,
list,
init,
};