UNPKG

allexsdk

Version:
564 lines (490 loc) 18.5 kB
'use strict'; function logj (data) { console.log(JSON.stringify(data, null, 2)); } function createPBWebAppInterpreter (Lib, Node) { 'use strict'; var Node = require('allex_nodehelpersserverruntimelib')(Lib), Bower = require('allex_bowerhelperssdklib')(Lib), Fs = Node.Fs, Path = Node.Path, WEBAPP_TEMPLATES = Path.resolve (__dirname, '..', '..', 'templates', 'webapps'); ///Grunt based interpreter ... function PBWebAppInterpreter (pbwr, grunt, params, defer) { this.required_files = null; this.required_dirs = null; this.pbwr = pbwr; this.cwd = this.pbwr.cwd; this.reset(); this.go = this._go.bind(this, grunt, params, defer); this.done = new Lib.HookCollection(); grunt.task.options({ done: this.done.fire.bind(this.done) }); } PBWebAppInterpreter.prototype.destroy = function () { this.pbwr = null; this.cwd = null; Lib.objNullAll(this.required_files); this.required_files = null; Lib.objNullAll(this.required_dirs); this.required_dirs = null; this.go = null; this.done.destroy(); this.done = null; }; PBWebAppInterpreter.prototype.reset = function () { this.required_files = {}; this.required_dirs = {}; }; PBWebAppInterpreter.prototype.map_to_cp_command = function (item) { return 'cp -LRp '+item.src+' '+item.dest; } PBWebAppInterpreter.prototype._go = function (grunt, params, defer) { var linkpath, testdir; Fs.removeSync(Path.resolve(this.cwd, '_generated')); if (!this.pbwr) return this.error('No reader set ...'); if (!this.pbwr.isReady()) { var unresolved = this.pbwr.getUnresolvedComponents(); if (unresolved.length) return this.error('Reader not ready, missing components: '+unresolved.join(',')); if (!this.pbwr.connection_data) return this.error('No connection data provided'); return this.error('This should never happen ...'); } var page_grunt = this.gruntPages(); var config = { html_template: page_grunt.template, symlink: { pages : {files: page_grunt.html} }, jshint:{}, exec: { clean: 'rm -rf '+Path.resolve(this.cwd, '_tmp') } }; //first check if there is a link to includes and layouts linkpath = Path.resolve(this.cwd, 'includes'); if (!Fs.existsSync(linkpath)){ try { if (Fs.readlinkSync(linkpath)){ Fs.removeSync(linkpath); }}catch(ignore){} config.symlink.includes = { files : [{src: Path.resolve(WEBAPP_TEMPLATES, 'includes'), dest: Path.resolve(this.cwd, 'includes')}] }; }else{ config.symlink.includes = {}; } linkpath = Path.resolve(this.cwd, 'layouts'); if (!Fs.existsSync(linkpath)){ try { if (Fs.readlinkSync(linkpath)){ Fs.removeSync(linkpath); }} catch(ignore){} config.symlink.layouts = { files : [{src: Path.resolve(WEBAPP_TEMPLATES, 'layouts'), dest: Path.resolve(this.cwd, 'layouts')}] }; }else{ config.symlink.layouts = {}; } if (this.pbwr.devel) { config.jshint.devel = { options: { globals: { 'jQuery': true, 'angular':true } }, files: { src: Path.resolve(this.cwd, 'js')+'/**' } }; config.symlink.components = {files: this.symlinkComponents()}; config.symlink.js = {files:[{src:Path.resolve(this.cwd, 'js'), dest:Path.resolve(this.cwd,'_generated', 'js')}]}; config.symlink.css= {files:[{src:Path.resolve(this.cwd, 'css'),dest:Path.resolve(this.cwd,'_generated','css')}]}; config.symlink.partials = {files:this.symlinkPartials()}; config.symlink.partials.files.forEach(this.require_existence.bind(this, 'dest', 'src')); config.symlink.publics = {files:this.symlinkPublics()}; config.symlink.roots = { files: this.symlinkRoots()}; }else{ var docopya = ['echo "starting file copy ..."']; testdir = Path.resolve(this.cwd, 'css'); if (!Fs.dirIsEmpty(testdir)) { docopya.push(this.map_to_cp_command({src: testdir+(Path.sep+'*'), dest: Path.resolve(this.cwd,'_generated','css')})); } Array.prototype.push.apply(docopya, this.symlinkComponents().map(this.map_to_cp_command.bind(this))); Array.prototype.push.apply(docopya, this.symlinkPublics().map(this.map_to_cp_command.bind(this))); Array.prototype.push.apply(docopya, this.symlinkPartials().map(this.map_to_cp_command.bind(this))); Array.prototype.push.apply(docopya, this.symlinkRoots().map(this.map_to_cp_command.bind(this))); Array.prototype.push.apply(docopya, config.symlink.pages.files.map(this.map_to_cp_command.bind(this))); config.exec.docopy = docopya.join(' && '); config.concat = this.concatJS(); config.uglify = { options: { }, all: { files:this.uglifyJS() } }; this.required_dirs[Path.resolve(this.cwd, '_generated','css')] = true; this.required_dirs[Path.resolve(this.cwd, '_generated','partials')] = true; this.required_dirs[Path.resolve(this.cwd, '_generated','js')] = true; this.required_dirs[Path.resolve(this.cwd, '_generated','components')] = true; } config.mkdir = { all: { options:{ create: Object.keys(this.required_dirs) } }, tmp: { options:{ create: [Path.resolve(this.cwd, '_tmp')] } } }; config.fileExists = {all:Object.keys(this.required_files)}; config.template = {}; this.prepareManifest(config.template); if(this.pbwr.requires_connection) { Lib.traverse(this.pbwr.jstemplates, this._adaptJSTemplatesRecords.bind(this, config.template)); } if (!Object.keys(config.template).length) { config.template = null; } var tasklist; if (this.pbwr.devel) { tasklist = ['fileExists', 'jshint', 'mkdir', 'symlink']; if (Object.keys(config.html_template).length) { tasklist.push ('html_template'); } if (config.template) { tasklist.push('template'); } }else{ tasklist = []; if (config.template) { tasklist.push('template'); } tasklist.push('fileExists', 'jshint', 'mkdir', 'symlink:includes', 'symlink:layouts', 'concat', 'uglify', 'exec:docopy'); if (Object.keys(config.html_template).length) { tasklist.push ('html_template'); } } tasklist.push ('exec:clean'); grunt.initConfig(config); grunt.registerTask('default', tasklist); defer.resolve(true); }; PBWebAppInterpreter.prototype._adaptJSTemplatesRecords = function (config, record) { var files_rec = {}; files_rec[record.dest_path] = record.src_path; config[record.dest_path] = { options: { data: record.data }, files : files_rec }; }; PBWebAppInterpreter.prototype.symlinkComponents = function () { var pbwr = this.pbwr, ret = []; Lib.traverse(pbwr.components, this._decideComponentsLink.bind(this,ret)); return ret; }; PBWebAppInterpreter.prototype._decideComponentsLink = function (ret,item) { if (!item.public_dirs){ if (this.pbwr.devel || (!this.pbwr.devel && !item.protoboard)){ ret.push({ dest: Path.join(this.cwd, '_generated', 'components', item.name), src: item.path }); } }else{ if (this.pbwr.devel) { this.required_dirs[Path.resolve(this.cwd, '_generated', 'components')] = true; ret.push ({ src: item.path, dest:Path.resolve(this.cwd, '_generated', 'components', item.name) }); }else{ this.required_dirs[Path.resolve(this.cwd, '_generated', 'components', item.name)] = true; Array.prototype.push.apply(ret,item.public_dirs.map(this._componentsPublicDirs.bind(this, item))); } } } PBWebAppInterpreter.prototype._componentsPublicDirs = function (item, dir) { ///TODO: not tested yet ... var src = Path.resolve(item.path, dir), target = Path.resolve(this.cwd, '_generated', 'components', item.name, dir) if (!target.length) { console.log('Failed', JSON.stringify(item)); } this.required_dirs[Path.dirname(target)] = true; return { src: src, dest:target }; }; PBWebAppInterpreter.prototype.require_existence = function (dir_field, src_field, rec) { this.required_dirs[Path.dirname(rec[dir_field])] = true; if (rec[src_field]) this.required_files[rec[src_field]] = true; }; PBWebAppInterpreter.prototype.getAssetList = function (type){ if ('js' === type || 'css' === type){ var ret = []; for (var i in this.pbwr.pages) { Array.prototype.push.apply(ret, this.pbwr.pages[i][type]); } return ret; } if ('partials' === type){ return this.pbwr.partials; } }; function toSymlinkRecord(self, rec) { return { dest: Path.resolve(self.cwd, '_generated', rec.dest_path), src: Path.join(rec.src_path) } }; function toPartialsSymlinkRecord (self, rec) { var ret = toSymlinkRecord(self, rec); self.required_dirs[Path.dirname(ret.dest)] = true; return ret; } PBWebAppInterpreter.prototype.symlinkPartials = function () { var ret = this.getAssetList('partials').map(toPartialsSymlinkRecord.bind(null, this)); return ret; }; PBWebAppInterpreter.prototype.symlinkRoots = function () { var ret = []; var robots = this.pbwr.pb_data.robots; if (robots) { ret.push ({ src : Lib.isString(robots) ? Path.resolve(this.cwd, robots) : Path.resolve(__dirname, '..', '..', 'templates', 'webapps', 'robots.txt'), dest: Path.resolve (this.cwd, '_generated', 'robots.txt') }); } return ret; }; function appendPublicDir (ret, cwd, dir){ if (Fs.dirExists(Path.resolve(cwd, dir))) { ret.push ({ src: Path.resolve(cwd, dir), dest:Path.resolve(cwd, '_generated', dir) }); } } PBWebAppInterpreter.prototype.symlinkPublics = function () { var ret = []; appendPublicDir(ret, this.cwd, 'public'); var rd = this.pbwr.pb_data.public_dirs; if (rd) { rd.forEach(appendPublicDir.bind(null, ret, this.cwd)); } return ret; }; PBWebAppInterpreter.prototype._assetListToCache = function (val) { var ret = val.dest_path.replace(Path.resolve(this.cwd,'_generated'), ''); return ret.replace (/^\//, ''); }; function appendpublic (item) { return 'public/'+item; } function ignore (ignore_list, item) { ///TODO: stigli smo do ovde, ai nismo isli dalje .... } PBWebAppInterpreter.prototype.generateUniManifest = function (config, pagedata, name) { /// try { ///TODO: do some sanity checks ... var manifest = { cache: [], network: [], fallback : {} }; var value = pagedata.vars.manifest; if (!value) return; if (value.auto) { if (this.pbwr.devel) { manifest.cache.push.apply (manifest.cache, pagedata.js.map(_dest_path)); }else{ manifest.cache.push ('js/'+name+'.min.js'); } manifest.cache.push.apply (manifest.cache, pagedata.css.map(_dest_path)); if (value.auto.ignore_partials) { Array.prototype.push.apply(manifest.cache, this.getAssetList('partials').map(this._assetListToCache.bind(this)).filter(ignore.bind(null, value.auto.ignore_partials))); }else{ Array.prototype.push.apply(manifest.cache, this.getAssetList('partials').map(this._assetListToCache.bind(this))); } if (value.auto.ignore_public) { Array.prototype.push.apply(manifest.cache, Fs.readdirRecursively(Path.resolve(this.cwd, 'public')).map(appendpublic).filter(ignore.bind(null, value.auto.ignore_public))); }else{ Array.prototype.push.apply(manifest.cache, Fs.readdirRecursively(Path.resolve(this.cwd, 'public')).map(appendpublic)); } } if (value.manual_cache) { //not that you can add only files to manifest ... Array.prototype.push.apply(manifest.cache, value.manual_cache); } if (!manifest.cache.length) { manifest.cache = null; }else{ } if (!manifest.network.length) manifest.network = null; if (!Object.keys(manifest.fallback)) manifest.fallback = null; this._adaptJSTemplatesRecords(config, { dest_path:Path.resolve(this.cwd, '_generated', name+'.manifest'), src_path: Path.resolve(__dirname, '..', '..', 'templates', 'webapps', 'cache_manifest.swig'), data: manifest }); }catch (e) { console.log(e); } }; function toIconsList (a, img) { a.push ({ src: img.href, sizes: img.size+'x'+img.size, type: 'image/png' }); } PBWebAppInterpreter.prototype.generageJSONManifest = function (config, pagedata, name) { var distro_value = pagedata.distro_vars && pagedata.distro_vars[this.pbwr.distro] ? pagedata.distro_vars[this.pbwr.distro].jsonmanifest : null, value = Lib.extend({}, pagedata.vars.jsonmanifest, distro_value), vars = this.processDistroVars(pagedata.vars, pagedata.distro_vars), wname = vars.webapp ? vars.webapp.title : null, start_url = name+'.html', icons = vars.icons; if (value.start_url) { if (this.pbwr.devel) { start_url = value.start_url.devel; }else{ start_url = value.start_url.production; } } var icons_list = []; Lib.traverseShallow(icons, toIconsList.bind(null, icons_list)); try { var data = { name: wname, icons : icons_list, start_url: start_url, display : value.display || 'fullscreen', orientation : value.orientation || undefined, short_name : value.short_name, '_webapp_timestamp' : (new Date()).getTime() }; this._adaptJSTemplatesRecords (config, { dest_path: Path.resolve(this.cwd, '_generated', name+'.json'), src_path: Path.resolve(__dirname, '..', '..', 'templates', 'webapps', 'json_manifest.swig'), data: {data:data} }); }catch (e) { console.log(e); } }; PBWebAppInterpreter.prototype._appendCacheManifest = function (config, pagedata, name) { if (pagedata.vars && pagedata.vars.manifest) { this.generateUniManifest(config, pagedata, name); } if (pagedata.vars && pagedata.vars.jsonmanifest) { this.generageJSONManifest(config, pagedata, name); } }; PBWebAppInterpreter.prototype.prepareManifest = function (config) { Lib.traverseShallow (this.pbwr.pages, this._appendCacheManifest.bind(this, config)); }; PBWebAppInterpreter.prototype.gruntPages = function () { var ret = { template: {}, html: [] }; for (var i in this.pbwr.pages) { var html_page = Path.resolve(this.cwd, 'pages', i+'.html'); if (Fs.fileExists(html_page)) { ret.html.push({ src : html_page, dest: Path.resolve(this.cwd, '_generated', i+'.html'), cwd : this.cwd }); }else{ ret.template[i] = this._gruntPage(i, this.pbwr.pages[i]); } } return ret; }; PBWebAppInterpreter.prototype.error = function (s) { throw new Error(s); }; PBWebAppInterpreter.prototype.uglifyJS = function () { var ret = {}; for (var i in this.pbwr.pages) { ret[Path.resolve(this.cwd, '_generated', 'js', i+'.min.js')] = [Path.resolve(this.cwd, '_tmp', i+'.js')]; } return ret; }; PBWebAppInterpreter.prototype.concatJS = function () { var ret = {}; for (var i in this.pbwr.pages) { ret[i+'_js_concat'] = { src: this.pbwr.pages[i].js.map(_src_path), dest: Path.join('_tmp',i+'.js'), nonull : true }; } return ret; }; PBWebAppInterpreter.prototype._gruntPage = function (name, data) { return { options: { locals: { js: this.pbwr.devel ? data.js.map(_to_conditionals) : [{path:Path.join('js', name+'.min.js')}], css:data.css.map(_to_conditionals), vars: this.processDistroVars(data.vars, data.distro_vars), devel : this.pbwr.devel, page: name, cache_manifest : this.decideToLoadManifest (name, data) ? name+'.manifest' : false, head_content : this.loadHeadContent(name, data) } }, expand: true, cwd: Path.resolve(this.cwd, 'pages'), dest:Path.resolve(this.cwd, '_generated'), src: name+'.swig' }; }; PBWebAppInterpreter.prototype.loadHeadContent = function (name, pagedata) { var vars = this.processDistroVars (pagedata.vars, pagedata.distro_vars); if (!vars || !vars.head_content) return null; var content = '', p; for (var i = 0; i < vars.head_content.length; i++) { p = Path.resolve(this.cwd, vars.head_content[i]); if (Fs.fileExists(p)) { if (content.length) content += "\n"; content += Fs.readFileSync (p, {encoding : 'utf8'}); } } return content; }; PBWebAppInterpreter.prototype.processDistroVars = function (vars, distro_vars) { if (!distro_vars) return vars; //nothing to be done ... var distro = this.pbwr.getSafeDistro(); if (!distro_vars[distro]) return vars; return Lib.extend ({}, vars, distro_vars[distro]); }; PBWebAppInterpreter.prototype.decideToLoadManifest = function (name, data) { if (this.pbwr.devel) { return !!data.include_manifest_devel; } return data.vars && data.vars.manifest; }; function _to_conditionals (rec) { return { path : rec.dest_path, conditional: rec.conditional } } function _dest_path (rec) { return rec.dest_path; } function _src_path (rec) { return rec.src_path; } return PBWebAppInterpreter; } module.exports = createPBWebAppInterpreter;