catjs
Version:
(Mobile) Web Automation Framework
968 lines (787 loc) • 35.8 kB
JavaScript
var _Scrap = catrequire("cat.common.scrap"),
_tplutils = catrequire("cat.tpl.utils"),
_utils = catrequire("cat.utils"),
_codeutils = catrequire("cat.code.utils"),
_uglifyutils = catrequire("cat.uglify.utils"),
_typedas = require("typedas"),
_behavior = require("./Behavior.js"),
_path = require("path"),
_global = catrequire("cat.global"),
_log = _global.log(),
_catlibtils = catrequire("cat.lib.utils"),
_delayManagerUtils = require("./utils/DelayManagerUtils"),
_elutils = require("./utils/ExpressionUtils");
module.exports = function () {
var funcSnippetTpl = _tplutils.readTemplateFile("scrap/_func_snippet"),
importJSTpl = _tplutils.readTemplateFile("scrap/_import_js"),
requireJSTpl = _tplutils.readTemplateFile("scrap/_require_js"),
requireGlobalsJSTpl = _tplutils.readTemplateFile("scrap/_require_globals_snippet"),
importCSSTpl = _tplutils.readTemplateFile("scrap/_import_css"),
assertTpl = _tplutils.readTemplateFile("scrap/_assert_call"),
project = catrequire("cat.cli").getProject();
function _isCatjs(lib) {
if (lib) {
lib = _path.basename(lib);
lib = lib.trim();
if (lib === "cat.js" || lib === "cat") {
return true;
}
}
return false;
}
// Build the library names according to the libraries manifest
function __updateLibs(deplibs) {
var result = [],
manifest = project.getManifest();
function _Details(config) {
var me = this;
function _init(config, props) {
var lib = config.lib;
me.name = config.name;
me.path = config.path;
me.exclude = config.exclude;
props.forEach(function (item) {
if (item in lib) {
me[item] = lib[item];
}
});
}
_init(config, ["exports", "deps", "globals", "exclude"]);
}
if (manifest) {
deplibs.forEach(function (libitem) {
var lib, names,
item;
if (libitem) {
item = libitem.name;
lib = manifest.getLibrary(item);
if (lib) {
// get the actual file names
names = lib.getFileNames();
if (names && names.length > 0) {
names.forEach(function (libpath) {
if (libpath) {
result.push(new _Details({name: item, path: libpath, lib: lib, exclude: (libitem.exclude||false) }));
}
});
} else {
// push the library name as is, [.js] will be concatenated
result.push(new _Details({name: item, path: item, lib: lib, exclude: (libitem.exclude||false) }));
}
} else {
// push the library name as is, [.js] will be concatenated
result.push(new _Details({name: item, path: item, lib: {}, exclude: (libitem.exclude||false) }));
}
}
});
}
return result;
}
return {
init: function (config) {
/**
* Annotation for javascript code
*
* properties:
* name - code
* single - false
* singleton - 1[default -1]
* $type - js
*/
_Scrap.add({name: "context",
single: false,
singleton: 1,
func: function (config) {
var ctx,
me = this;
ctx = this.get("context");
if (ctx) {
me.setCtxArguments(ctx);
}
}});
/**
* Annotation for javascript code
*
* properties:
* name - code
* single - false
* $type - js
*/
_Scrap.add({name: "code",
single: false,
singleton: 1,
func: function (config) {
var codeRows,
code,
me = this,
dm,
scrap = me.config;
codeRows = this.get("code");
if (codeRows) {
codeRows = _codeutils.prepareCode(codeRows);
dm = new _delayManagerUtils({
scrap: me
});
if (codeRows) {
dm.add({
rows: codeRows,
args: [
"scrapName: 'code'"
],
type: "code"
});
}
dm.dispose();
}
}});
/**
* Annotation for javascript code
*
* properties:
* name - js
* single - false
* $type - js
*/
_Scrap.add({name: "js",
single: false,
singleton: 1,
func: function (config) {
var codeRows,
code,
me = this,
dm,
scrap = me.config;
codeRows = this.get("js");
if (codeRows) {
codeRows = _codeutils.prepareCode(codeRows);
dm = new _delayManagerUtils({
scrap: me
});
if (codeRows) {
dm.add({
rows: codeRows,
args: [
"scrapName: 'js'"
],
type: "js"
});
}
dm.dispose();
}
}});
/**
* Annotation for javascript code
*
* properties:
* name - log
* single - false
* $type - js
*/
_Scrap.add({name: "log",
single: false,
singleton: 1,
func: function (config) {
var logRows,
code = [],
me = this, dm;
logRows = this.get("log");
if (logRows) {
logRows.forEach(function (row) {
if (row) {
code.push(_tplutils.template({
content: funcSnippetTpl,
data: {
comment: " Generated log statement according to the scrap comment (see @@code)",
code: ['console.log(', row, ");"].join("")
}
}));
}
});
if (code) {
dm = new _delayManagerUtils({
scrap: me
});
dm.add({
rows: code,
args: [
"scrapName: 'log'"
],
type: "log"
});
dm.dispose();
}
}
}});
/**
* Annotation for javascript run@
*
* properties:
* name - run@
* runat - true
* singleton - 1[default -1]
* $type - js
*/
_Scrap.add({name: "run@",
func: function (config) {
}});
/**
* Annotation for javascript catui
*
* properties:
* name - catui
* singleton - 1[default -1]
* $type - js
*/
_Scrap.add({name: "catui",
func: function (config) {
var me = this,
catui = me.get("catui");
if (catui) {
me.print(_tplutils.template({
content: funcSnippetTpl,
data: {
comment: " CAT UI call ",
code: ["_cat.core.ui.", catui, "();"].join("")
}
}));
}
}});
/**
* Annotation for javascript standalone
*
* properties:
* name - catui
* singleton - 1[default -1]
* $type - js
*/
_Scrap.add({name: "standalone",
func: function (config) {
var me = this,
standalone = me.get("standalone");
if (standalone && standalone.trim().toLowerCase() === "true") {
this.$setStandalone(true);
}
}});
/**
* Annotation for javascript resolve
*
* properties:
* name - catui
* singleton - 1[default -1]
* $type - js
*/
_Scrap.add({name: "resolve",
func: function (config) {
var me = this,
resolve = me.get("resolve");
if (resolve && resolve.trim().toLowerCase() === "true") {
this.$setResolve(true);
} else if (resolve && resolve.trim().toLowerCase() === "false") {
this.$setResolve(false);
}
}});
/**
* Annotation for javascript signal
*
* properties:
* name - signal
* singleton - 1[default -1]
* $type - js
*/
_Scrap.add({name: "signal",
func: function (config) {
var me = this,
signal = me.get("signal");
// TODO need to be refactored (see manager)
if (me.get("manager")) {
return undefined;
}
if (signal) {
me.print(_tplutils.template({
content: funcSnippetTpl,
data: {
comment: " Signal call ",
code: ["_cat.utils.Signal.send('", signal , "');"].join("")
}
}));
}
}});
/**
* Annotation for javascript manager
*
* properties:
* name - manager
* single - false
* singleton - 1[default -1]
* $type - js
*/
_Scrap.add({name: "manager",
single: false,
singleton: 1,
func: function (config) {
var me = this,
manager,
runat = me.get("name"),
signal;
manager = me.get("manager");
if (manager) {
// TODO need to be refactored (see signal)
signal = me.get("signal");
me.print(_tplutils.template({
content: funcSnippetTpl,
data: {
comment: " Manager call ",
code: "(function() {_cat.core.managerCall('" + runat + "', function(){_cat.utils.Signal.send('" + signal + "');}); })();"
}
}));
}
}});
/**
* Annotation for javascript manager's scraps attributes
*
* properties:
* name - code
* single - false
* $type - js
*/
_Scrap.add({name: "perform",
single: false,
func: function (config) {
var scrapsRows,
me = this,
scrapItemName, scrapItemValue,
scrapItem,
runat = me.get("name"),
innerscraps;
scrapsRows = me.get("perform");
if (scrapsRows) {
innerscraps = me.extractAnnotations(scrapsRows);
// extract nested annotations
for (scrapItemName in innerscraps) {
scrapItemValue = innerscraps[scrapItemName];
me.print(_tplutils.template({
content: funcSnippetTpl,
data: {
comment: " Add Manager behavior ",
code: "_cat.core.setManagerBehavior('" + runat + "', '" + scrapItemName + "', '" + scrapItemValue + "');"
}
}));
}
}
}});
/**
* Annotation for description (aimed for the ui)
*
* properties:
* name - description
* single - false
* $type - js
*/
_Scrap.add({name: "description",
single: true,
singleton: 1,
func: function (config) {
}
});
/**
* Annotation for an assertion
*
* properties:
* name - chai
* single - false
* $type - js
*/
_Scrap.add({name: "assert",
single: false,
func: function (config) {
var codeRows,
me = this,
dm, codeRow, size,
scrap = me.config;
codeRows = this.get("assert");
if (codeRows) {
codeRows = _codeutils.prepareCode(codeRows);
size = codeRows.length;
for (var idx=0; idx<size; idx++) {
codeRow = codeRows[idx];
if (codeRow) {
if (codeRow.trim().indexOf("_cat.utils.chai.assert") === -1) {
codeRows[idx] = _tplutils.template({
content: assertTpl,
data: {
code: ("function() { return chai.assert." + codeRow + "}")
}
});
}
}
}
dm = new _delayManagerUtils({
scrap: me
});
dm.add({
rows: codeRows,
args: [
"scrapName: 'assert'"
], type: "assert"
});
dm.dispose();
}
}
});
/**
* Annotation for require a javascript file on requirejs environment
* Currently support for catjs and its dependencies, for adding your require configuration use the applications'
*
* properties:
* name - require
* single - true
* $type - js
*/
_Scrap.add({name: "require",
func: function (config) {
this.setSingle("inject", true);
this.set("injectcode", true);
this.set("auto", false);
var requirerows = this.get("require"),
me = this,
basedir, libs, code,
requirelist = [],
requirecsslist = [],
config = {
shim: {
catjs: {
exports: '_cat'
},
"catsrcjs": {
deps: [
"catjs"
]
}
},
paths: {
}
}, globals = [];
function _addGlobals(lib) {
var glob, exp;
if (lib) {
glob = ("globals" in lib ? lib.globals : false);
exp = ("exports" in lib ? lib.exports : undefined);
if (glob && exp) {
globals.push(_tplutils.template({
content: requireGlobalsJSTpl,
data: {
handle: lib.name,
exports: exp
}
}));
}
}
}
if (requirerows) {
if (!_typedas.isArray(requirerows)) {
requirerows = [requirerows];
}
requirerows.forEach(function (lib) {
var basedirsplit, catpath;
if (lib && _isCatjs(lib)) {
libs = project.getInfo("dependencies");
basedir = _path.dirname(lib) + "/";
if (requirerows) {
requirerows = _codeutils.prepareCode(requirerows);
code = requirerows.join("\n");
if (code) {
// update the libs according to the manifest
libs = __updateLibs(libs);
libs.forEach(function (lib) {
var fullpathlib,
key, libpath = lib.path;
if (libpath) {
if (libpath.lastIndexOf(".map") !== -1) {
return undefined;
}
libpath = libpath.split(".js").join("");
basedirsplit = basedir.split("/");
basedirsplit = basedirsplit.filter(function(n){ return (n !== undefined && n !== ""); });
if (basedirsplit[basedirsplit.length - 1] === "cat") {
basedirsplit.pop();
basedir = basedirsplit.join("/");
}
key = lib.name.split(".").join("");
if (key === "cat") {
basedir = _path.join(basedir, "cat") + "/";
}
fullpathlib = basedir + libpath;
if (key === "cat") {
catpath = fullpathlib;
config.paths["catsrcjs"] = fullpathlib + ".src";
key = "catjs";
requirecsslist.push([basedir, "cat.css"].join(""));
}
if (_catlibtils.extExists(libpath)) {
if (libpath.lastIndexOf(".css") !== -1) {
requirecsslist.push(basedir + libpath);
return undefined;
}
}
if (!lib.exclude) {
config.paths[key] = fullpathlib;
if (lib.deps || lib.exports) {
if (!config.shim[key]) {
config.shim[key] = {};
}
if (lib.deps) {
config.shim[key].deps = lib.deps;
}
if (lib.exports) {
config.shim[key].exports = lib.exports;
}
_addGlobals(lib);
}
}
requirelist.push(key);
if (key === "catjs") {
requirelist.push("catsrcjs");
}
}
});
// override configuration
if (config.paths.chai) {
config.shim.catjs.deps = ["chai"];
}
me.print(_tplutils.template({
content: requireJSTpl,
data: {
comment: " catjs require configuration - for additional require config use your application's ",
config: JSON.stringify(config),
require: JSON.stringify(requirelist),
requirerefs: requirelist.join(",").split('"').join(""),
cssfiles: JSON.stringify(requirecsslist),
globals: (globals.length > 0 ? globals.join(" ") : ""),
catjspath: (catpath + ".js")
}
}));
}
}
}
});
}
}
});
/**
* Annotation for importing javascript file within HTML page
*
* properties:
* name - import
* single - true
* $type - html
*/
_Scrap.add({name: "import",
single: false,
func: function (config) {
var project = catrequire("cat.cli").getProject();
function _getType(value) {
var type = "js";
if (value) {
type = _path.extname(value);
}
return {type: type.split(".").join(""), value: value};
}
function generateLibs(value) {
var libs = [], deplibs = [], basedir,
libcounter = 0,
libsrcs = [],
basedirsplit;
if (_isCatjs(value)) {
// handle cat library
deplibs = project.getInfo("dependencies");
// update the libs according to the manifest
libs = __updateLibs(deplibs);
libs.forEach(function (lib) {
if (lib.path === "cat") {
libs.splice(libcounter, 1);
}
libcounter++;
});
basedir = _path.dirname(value);
basedirsplit = basedir.split("/");
if (basedirsplit[basedirsplit.length - 1] === "cat") {
basedirsplit.pop();
basedir = basedirsplit.join("/");
}
// set the base directory according to the cat.js path
basedir += "/";
// override the cat.js file path
value = basedir + "cat/cat.js"
libs.forEach(function (lib) {
if (lib.path.indexOf("cat.src") === -1) {
libsrcs.push([basedir, lib.path].join(""));
}
});
libsrcs.push(value);
libsrcs.push([basedir, "cat/cat.src.js"].join(""));
libsrcs.push([basedir, "cat/cat.css"].join(""));
} else {
libsrcs.push(value);
}
return libsrcs;
}
function _printByType(type, value) {
var contentByType,
elementId,
contents = {
"js": importJSTpl,
"css": importCSSTpl
};
if (type) {
contentByType = contents[type];
}
if (value.indexOf("cat.js") !== -1) {
elementId = "catjsscript"
} else {
elementId = value.replace(/\.|\//g, "");
}
if (contentByType) {
me.print(_tplutils.template({
content: contentByType,
data: {
events: {onload: ( value.indexOf("cat.src.js") !== -1 ? "onload=\"_cat.core.init({win: this})\"" : undefined )},
src: value,
elementId: elementId
}
}));
}
}
var importannos = this.get("import"),
me = this;
me.$setType("html");
me.set("auto", false);
if (importannos) {
importannos.forEach(function (item) {
var libs;
if (item) {
libs = generateLibs(item);
libs.forEach(function (lib) {
var typeo = _getType(lib),
importType = typeo.type;
if (importType && importType !== "map") {
_printByType(importType, typeo.value);
}
});
}
});
}
}});
/**
* Annotation for embed javascript block code within HTML page
*
* properties:
* name - embed
* single - false
* $type - html
*/
_Scrap.add({name: "embed", func: function (config) {
this.$setType("html");
}});
/**
* Annotation for embed javascript block code within HTML page
*
* properties:
* name - inject
* single - true
* $type - html
*/
_Scrap.add({name: "inject", func: function (config) {
var injectanno = this.get("inject");
this.setSingle("inject", true);
this.$setType("*");
this.set("auto", false);
this.print(injectanno);
}});
/**
*
* properties:
* name - inject
* single - true
* $type - html
*/
_Scrap.add({name: "replace", func: function (config) {
var me = this,
innerscraps,
scrapsRows = this.getContextItem("behavior"),
replace = this.get("replace"),
scrapName, scrapValue,
behave = {},
behaviorLoad,
requireName;
//this.$setType("*");
if (_typedas.isArray(scrapsRows)) {
// in case we have specified the behaviors within the annotation
// extract nested annotations
innerscraps = me.extractAnnotations(scrapsRows);
for (scrapName in innerscraps) {
if (scrapName) {
if (scrapName === "replace") {
scrapValue = innerscraps[scrapName];
scrapValue = scrapValue.trim();
// look inside the OOTB functionality
behaviorLoad = _utils.resolveObject(_behavior, scrapValue);
if (behaviorLoad) {
behave.inject = behaviorLoad;
} else {
// try resolving user's custom object
try {
requireName = _path.join(_path.resolve("."), scrapValue);
behaviorLoad = require(requireName);
if (behaviorLoad) {
behave.inject = behaviorLoad[scrapName];
} else {
_utils.log("warning", "[cat scrap-common plugin] failed to resolve 'replace' functionality module, " + requireName);
}
} catch (e) {
// failed to load user behavior
_utils.log("warning", "[cat scrap-common plugin] failed to resolve 'replace' functionality module, " + scrapValue);
}
}
}
}
}
} else if (_typedas.isString(scrapsRows)) {
// or else we supplied an object with the behaviors implemented as an object
scrapValue = scrapsRows;
behave.inject = scrapValue;
}
if (behave && behave.inject) {
// insert the behavior
this.$setBehavior(behave);
// set the replace data info
this.$setReplaceData({action: behave.inject});
} else {
_utils.log("warning", "[cat scrap-common plugin] No valid behavior was found, check your scrap behavior settings.");
}
}});
/**
*
* properties:
* name - inject
* single - true
* $type - html
*/
_Scrap.add({name: "behavior",
single: false,
func: function (config) {
var me = this;
}
});
config.emitter.emit("job.done", {status: "done"});
/**
* Annotations for single row purpose in here -------------------
*
*/
},
apply: function () {
},
getType: function () {
return "scrap-common";
}
};
};