nsify
Version:
NetSuite-side require() the node.js
274 lines (256 loc) • 10.5 kB
JavaScript
'use strict';
var fs = require('fs'),
path = require('path'),
camelcase = require('uppercamelcase');
const $TYPES = {
cl: 'client',
re: 'restlet',
sc: 'schedule',
st: 'suitelet',
ue: 'user-event'
};
const
/**
* SuiteScript ID
*/
$RE_ID = /@ns.id:[ ]*["|']([\w -\_]*)["|']/,
/**
* SuiteScript Name
*/
$RE_NAME = /@ns.name:[ ]*["|']([\w ]*)["|']/,
/**
* SuiteScript Type
* @defaults ['client', 'schedule', 'suitelet', 'restlet', 'user-event']
*/
$RE_TYPE = /@ns.type:[ ]*["|']([\w -]*)["|']/,
/**
* SuiteScript Alias
*/
$RE_ALIAS = /@ns.alias:[ ]*["|']([\w ]*)["|']/,
/**
* SuiteScript Description
*/
$RE_DESC = /@ns.desc:[ ]*["|']([\w -\_|]*)["|']/,
/**
* Others libraries for SuiteScript
*/
$RE_LIBS = /@ns.libs:[ ]*(['|"][\w\/'", -\.]*)\n/,
/**
* Configure any record for Client or User Event
*/
$RE_RECORD = /@ns.record:[ ]*["|']([\w ]*)["|']/,
$RE_RECORDS = /@ns.records:[ ]*(['|"][\w\/'", -]*\n)/,
/**
* SuiteScript Functions
*/
/** Function for Schedule or Suitelet */
$RE_FUNC = /@ns.function:[ ]*["|']([\w/\.:]*)["|']/,
/** Functions for User Event */
$RE_FUNC_BEFORE_LOAD = /@ns.functions.beforeLoad:[ ]*["|']([\w\.]*)["|']/,
$RE_FUNC_BEFORE_SMT = /@ns.functions.beforeSubmit:[ ]*["|']([\w\.]*)["|']/,
$RE_FUNC_AFTER_SMT = /@ns.functions.afterSubmit:[ ]*["|']([\w\.]*)["|']/,
/** Functions for RESTlet */
$RE_FUNC_POST = /@ns.functions.post:[ ]*["|']([\w\.]*)["|']/,
$RE_FUNC_GET = /@ns.functions.get:[ ]*["|']([\w\.]*)["|']/,
$RE_FUNC_DELETE = /@ns.functions.delete:[ ]*["|']([\w\.]*)["|']/,
$RE_FUNC_PUT = /@ns.functions.put:[ ]*["|']([\w\.]*)["|']/,
/** Functions for Client */
$RE_FUNC_PAGE_INIT = /@ns.functions.pageInit:[ ]*["|']([\w\.]*)["|']/,
$RE_FUNC_SAVE_REC = /@ns.functions.saveRecord:[ ]*["|']([\w\.]*)["|']/,
$RE_FUNC_VALIDATE_FIELD = /@ns.functions.validateField:[ ]*["|']([\w\.]*)["|']/,
$RE_FUNC_FIELD_CHANGED = /@ns.functions.fieldChanged:[ ]*["|']([\w\.]*)["|']/,
$RE_FUNC_POST_SOURCING = /@ns.functions.postSourcing:[ ]*["|']([\w\.]*)["|']/,
$RE_FUNC_LINE_INIT = /@ns.functions.lineInit:[ ]*["|']([\w\.]*)["|']/,
$RE_FUNC_VALIDATE_LINE = /@ns.functions.validateLine:[ ]*["|']([\w\.]*)["|']/,
$RE_FUNC_VALIDATE_INSERT = /@ns.functions.validateInsert:[ ]*["|']([\w\.]*)["|']/,
$RE_FUNC_VALIDATE_DELETE = /@ns.functions.validateDelete:[ ]*["|']([\w\.]*)["|']/,
$RE_FUNC_RECALC = /@ns.functions.recalc:[ ]*["|']([\w\.]*)["|']/,
/**
* SuiteScript Parameters
*/
$RE_PARAM = `@ns.params.([A-Za-z0-9-\_]*):[ ]*((["|']([A-Za-z-]*)["|'])|({([A-Za-z-:'"\., ]*)}))`,
/**
* Validate if functions exists in script.
*
* @param func {string} Function name.
*/
$RE_FUNC_VALIDATE = (func) => new RegExp(`${func}[ \\n]*[:=][ \\n]*function[ \n]*\\(`, 'g'),
/**
* Custom Annotations
*/
$RE_CUSTOM = `@ns.custom.([A-Za-z0-9-\\_]*):[ ]*["|']([\\w\\/'", -\\.]*)\\n`;
var parseStr = (l) => l.replace(/['|"]/g, '').trim();
/**
*
* @param scriptPath {string}
* @param [format] {'nsmockup'}
* @returns {{
* id: string,
* name: string,
* type: 'client'|'schedule'|'suitelet'|'restlet'|'user-event',
* desc: string,
* alias: string,
* [function]: string,
* [functions]: {
* [post]: string,
* [get]: string,
* [delete]: string,
* [put]: string,
* [afterSubmit]: string,
* [beforeSubmit]: string,
* [beforeLoad]: string,
* [pageInit]: string,
* [saveRecord]: string
* },
* libs: [string],
* params: object,
* [records]: [string],
* [config]: {
* [noAlias]: boolean,
* [concat]: [string]
* },
* [custom]: object
* }}
*/
module.exports = (scriptPath, format) => {
if (!scriptPath) {
return null;
} else {
scriptPath = path.resolve(scriptPath);
}
let ext = ~scriptPath.indexOf('.js') ? '' : '.js',
filePath = `${scriptPath}${ext}`;
if (!fs.existsSync(filePath)) {
return null;
}
let script = fs.readFileSync(filePath, 'utf8'),
name = path.basename(filePath, '.js'),
prefix = name.substr(0, 2).toLowerCase(),
type = $TYPES[prefix],
id = (type ? name.substr(3) : name).replace(/[ ;:+=\|\\]/g, '_');
if (!type) {
type = 'library';
}
let nsId = ($RE_ID.test(script) ? $RE_ID.exec(script)[1] : id).replace('customscript', ''),
nsObj = {
id: nsId,
name: $RE_NAME.test(script) ? $RE_NAME.exec(script)[1] : nsId.replace(/[_-]/g, ' '),
type: $RE_TYPE.test(script) ? $RE_TYPE.exec(script)[1] : type,
alias: $RE_ALIAS.test(script) ? $RE_ALIAS.exec(script)[1] : nsId,
desc: $RE_DESC.test(script) ? $RE_DESC.exec(script)[1] : '',
libs: $RE_LIBS.test(script) ? $RE_LIBS.exec(script)[1].split(',').map(parseStr) : [],
params: {}
};
nsObj.type = nsObj.type.toLowerCase();
nsObj.name = nsObj.name.split(' ').map(word => {
if (word.length === 2) {
// Uppercase team abbreviations like FC, CD, SD
return word.toUpperCase();
} else {
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
}
}).join(' ');
if (/[ -;:/]/.test(nsObj.alias)) {
nsObj.alias = camelcase(nsObj.alias);
}
switch (nsObj.type) {
case 'client': {
nsObj.functions = {
pageInit: $RE_FUNC_PAGE_INIT.test(script) ? $RE_FUNC_PAGE_INIT.exec(script)[1] : 'pageInit',
saveRecord: $RE_FUNC_SAVE_REC.test(script) ? $RE_FUNC_SAVE_REC.exec(script)[1] : 'saveRecord',
validateField: $RE_FUNC_VALIDATE_FIELD.test(script) ? $RE_FUNC_VALIDATE_FIELD.exec(script)[1] : 'validateField',
fieldChanged: $RE_FUNC_FIELD_CHANGED.test(script) ? $RE_FUNC_FIELD_CHANGED.exec(script)[1] : 'fieldChanged',
postSourcing: $RE_FUNC_POST_SOURCING.test(script) ? $RE_FUNC_POST_SOURCING.exec(script)[1] : 'postSourcing',
lineInit: $RE_FUNC_LINE_INIT.test(script) ? $RE_FUNC_LINE_INIT.exec(script)[1] : 'lineInit',
validateLine: $RE_FUNC_VALIDATE_LINE.test(script) ? $RE_FUNC_VALIDATE_LINE.exec(script)[1] : 'validateLine',
validateInsert: $RE_FUNC_VALIDATE_INSERT.test(script) ? $RE_FUNC_VALIDATE_INSERT.exec(script)[1] : 'validateInsert',
validateDelete: $RE_FUNC_VALIDATE_DELETE.test(script) ? $RE_FUNC_VALIDATE_DELETE.exec(script)[1] : 'validateDelete',
recalc: $RE_FUNC_RECALC.test(script) ? $RE_FUNC_RECALC.exec(script)[1] : 'recalc'
};
let record = $RE_RECORD.test(script) ? $RE_RECORD.exec(script)[1] : null;
if (record) {
nsObj.records = [record];
} else {
nsObj.records = $RE_RECORDS.test(script) ? $RE_RECORDS.exec(script)[0].split(',').map(parseStr) : [];
}
break;
}
case 'schedule':
nsObj.function = $RE_FUNC.test(script) ? $RE_FUNC.exec(script)[1] : 'process';
break;
case 'suitelet':
nsObj.function = $RE_FUNC.test(script) ? $RE_FUNC.exec(script)[1] : 'execute';
break;
case 'restlet':
nsObj.functions = {
get: $RE_FUNC_GET.test(script) ? $RE_FUNC_GET.exec(script)[1] : 'get',
delete: $RE_FUNC_DELETE.test(script) ? $RE_FUNC_DELETE.exec(script)[1] : 'delete',
post: $RE_FUNC_POST.test(script) ? $RE_FUNC_POST.exec(script)[1] : 'post',
put: $RE_FUNC_PUT.test(script) ? $RE_FUNC_PUT.exec(script)[1] : 'put'
};
break;
case 'user-event': {
nsObj.functions = {
beforeLoad: $RE_FUNC_BEFORE_LOAD.test(script) ? $RE_FUNC_BEFORE_LOAD.exec(script)[1] : 'beforeLoad',
beforeSubmit: $RE_FUNC_BEFORE_SMT.test(script) ? $RE_FUNC_BEFORE_SMT.exec(script)[1] : 'beforeSubmit',
afterSubmit: $RE_FUNC_AFTER_SMT.test(script) ? $RE_FUNC_AFTER_SMT.exec(script)[1] : 'afterSubmit'
};
let record = $RE_RECORD.test(script) ? $RE_RECORD.exec(script)[1] : '';
if (record) {
nsObj.records = [record];
} else {
nsObj.records = $RE_RECORDS.test(script) ? $RE_RECORDS.exec(script)[1].split(',').map(parseStr) : [];
}
break;
}
}
// Verify Parameters
let reParam = new RegExp($RE_PARAM, 'g');
for (let match; (match = reParam.exec(script)); ) {
let param = match[1],
value = match[2];
if (value[0] === '{') {
let obj, paramObj = {};
eval('obj = ' + value);
['type', 'name'].forEach(prop => {
paramObj[prop] = obj[prop];
});
nsObj.params[param] = paramObj;
} else {
nsObj.params[param] = {type: value.substring(1, value.length - 1)};
}
}
// Verify Custom Annotations
let reCustom = new RegExp($RE_CUSTOM, 'g');
for (let match; (match = reCustom.exec(script)); ) {
if (!nsObj.custom) nsObj.custom = {};
let param = match[1],
value = match[2];
nsObj.custom[param] = value.replace(/['"]/g, '').trim();
}
// Remove uncreated functions
let alias = nsObj.alias,
verifyFunction = (objBase, funcName, defFunc) => {
funcName = funcName.indexOf(`${alias}.`) === 0 ? funcName.replace(`${alias}.`, '') : funcName;
if ($RE_FUNC_VALIDATE(funcName).test(script)) {
objBase[defFunc] = funcName;
} else {
delete objBase[defFunc];
}
};
if (nsObj.functions) {
let funcs = nsObj.functions;
Object.keys(nsObj.functions).forEach(func => {
let funcName = funcs[func].trim();
verifyFunction(funcs, funcName, func);
});
} else if (nsObj.function) {
let funcName = nsObj.function.trim();
verifyFunction(nsObj, funcName, 'function');
}
if (format === 'nsmockup') {
return require('./nsmockup-parse')(nsObj, filePath);
} else {
return nsObj;
}
};