Last active
August 29, 2015 14:16
-
-
Save prurigro/e45d70c3cc44b8f57194 to your computer and use it in GitHub Desktop.
Converts json to tidy html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
/* | |
* json2weblist: convert a heading in json to an HTML list, then tidy it up | |
* Version: 1.0.1 | |
* | |
* Requirements: | |
* Node.js: http://nodejs.org/ | |
* Tidy-HTML: http://tidy.sourceforge.net/ | |
* * Experimental version with HTML5 support : https://github.com/w3c/tidy-html5 | |
* * Less official, more maintained fork : https://github.com/bbatsche/tidy-html5 | |
* | |
* Script by: | |
* Kevin MacMartin | |
* [email protected] | |
* https://github.com/prurigro | |
* | |
* Libraries included: | |
* node-json2html (convert json to html) : https://github.com/moappi/node-json2html | |
* htmltidy (tidy-html5 frontend) : https://github.com/vavere/htmltidy | |
* | |
* Released under the MIT license : http://opensource.org/licenses/MIT | |
*/ | |
// library:json2html | |
var json2html={'transform':function(json,transform,_options){var out={'events':[],'html':''};var options={'events':false};options=json2html._extend(options,_options);if(transform!==undefined||json!==undefined){var obj=typeof json==='string'?JSON.parse(json):json;out=json2html._transform(obj,transform,options);} if(options.events)return(out);else return(out.html);},'_extend':function(obj1,obj2){var obj3={};for(var attrname in obj1){obj3[attrname]=obj1[attrname];} for(var attrname in obj2){obj3[attrname]=obj2[attrname];} return obj3;},'_append':function(obj1,obj2){var out={'html':'','event':[]};if(typeof obj1!=='undefined'&&typeof obj2!=='undefined'){out.html=obj1.html+obj2.html;out.events=obj1.events.concat(obj2.events);} return(out);},'_transform':function(json,transform,options){var elements={'events':[],'html':''};if(Array.isArray(json)){var len=json.length;for(var j=0;j<len;++j){elements=json2html._append(elements,json2html._apply(json[j],transform,j,options));}}else if(typeof json==='object'){elements=json2html._append(elements,json2html._apply(json,transform,undefined,options));} return(elements);},'_apply':function(obj,transform,index,options){var element={'events':[],'html':''};if(Array.isArray(transform)){var t_len=transform.length;for(var t=0;t<t_len;++t){element=json2html._append(element,json2html._apply(obj,transform[t],index,options));}}else if(typeof transform==='object'){if(transform.tag!==undefined){element.html+='<'+transform.tag;var children={'events':[],'html':''};var html;for(var key in transform){switch(key){case'tag':break;case'children':if(Array.isArray(transform.children)){children=json2html._append(children,json2html._apply(obj,transform.children,index,options));}else if(typeof transform.children==='function'){var temp=transform.children.call(obj,obj,index);if(typeof temp==='object'){if(temp.html!==undefined&&temp.events!==undefined)children=json2html._append(children,temp);}else if(typeof temp==='string'){children.html+=temp;}} break;case'html':html=json2html._getValue(obj,transform,'html',index);break;default:var isEvent=false;if(key.length>2) if(key.substring(0,2).toLowerCase()=='on'){if(options.events){var data={'action':transform[key],'obj':obj,'data':options.eventData,'index':index};var id=json2html._guid();element.events[element.events.length]={'id':id,'type':key.substring(2),'data':data};element.html+=" json2html-event-id='"+id+"'";} isEvent=true;} if(!isEvent){var val=json2html._getValue(obj,transform,key,index);if(val!==undefined)element.html+=" "+key+"='"+val+"'";} break;}} element.html+='>';if(html)element.html+=html;element=json2html._append(element,children);element.html+='</'+transform.tag+'>';}} return(element);},'_guid':function(){var S4=function(){return(((1+Math.random())*0x10000)|0).toString(16).substring(1);};return(S4()+S4()+"-"+S4()+S4()+"-"+S4()+S4());},'_getValue':function(obj,transform,key,index){var out='';var val=transform[key];var type=typeof val;if(type==='function'){return(val.call(obj,obj,index));}else if(type==='string'){var _tokenizer=new json2html._tokenizer([/\$\{([^\}\{]+)\}/],function(src,real,re){return real?src.replace(re,function(all,name){var components=name.split('.');var useObj=obj;var outVal='';var c_len=components.length;for(var i=0;i<c_len;++i){if(components[i].length>0){var newObj=useObj[components[i]];useObj=newObj;if(useObj===null||useObj===undefined)break;}} if(useObj!==null&&useObj!==undefined)outVal=useObj;return(outVal);}):src;});out=_tokenizer.parse(val).join('');} return(out);},'_tokenizer':function(tokenizers,doBuild){if(!(this instanceof json2html._tokenizer)) return new json2html._tokenizer(tokenizers,doBuild);this.tokenizers=tokenizers.splice?tokenizers:[tokenizers];if(doBuild) this.doBuild=doBuild;this.parse=function(src){this.src=src;this.ended=false;this.tokens=[];do{this.next();}while(!this.ended);return this.tokens;};this.build=function(src,real){if(src) this.tokens.push(!this.doBuild?src:this.doBuild(src,real,this.tkn));};this.next=function(){var self=this,plain;self.findMin();plain=self.src.slice(0,self.min);self.build(plain,false);self.src=self.src.slice(self.min).replace(self.tkn,function(all){self.build(all,true);return'';});if(!self.src) self.ended=true;};this.findMin=function(){var self=this,i=0,tkn,idx;self.min=-1;self.tkn='';while((tkn=self.tokenizers[i++])!==undefined){idx=self.src[tkn.test?'search':'indexOf'](tkn);if(idx!=-1&&(self.min==-1||idx<self.min)){self.tkn=tkn;self.min=idx;}} if(self.min==-1) self.min=self.src.length;};}}; | |
// library:htmltidy | |
var Stream=require('stream').Stream;var inherits=require('util').inherits;var fs=require('fs');var path=require('path');var spawn=require('child_process').spawn;var TIDY_OK=0;var TIDY_WARN=1;var TIDY_ERR=2;var DEFAULT_OPTS={showWarnings:false,tidyMark:false,forceOutput:true,quiet:false};var tidyExec=chooseExec();function TidyWorker(opts){Stream.call(this);var mergedOpts=merge(opts,DEFAULT_OPTS);this.writable=true;this.readable=true;this._worker=spawn(tidyExec,parseOpts(mergedOpts));var self=this;var errors='';this._worker.stdin.on('drain',function(){self.emit('drain');});this._worker.stdin.on('error',function(){self.emit('error');});this._worker.stdout.on('data',function(data){self.emit('data',data);});this._worker.stdout.on('close',function(data){self.emit('close');});this._worker.stderr.on('data',function(data){errors+=data;});this._worker.on('exit',function(code){switch(code){case TIDY_WARN:if(mergedOpts.showWarnings){self.emit('error',errors);} break;case TIDY_ERR:if(mergedOpts.showErrors){self.emit('error',errors);} break;} self.emit('end');});} inherits(TidyWorker,Stream);TidyWorker.prototype.write=function(data){if(!this._worker) throw new Error('worker has been destroyed');return this._worker.stdin.write(data);};TidyWorker.prototype.end=function(data){if(!this._worker) throw new Error('worker has been destroyed');this._worker.stdin.end(data);};TidyWorker.prototype.pause=function(){if(!this._worker) throw new Error('worker has been destroyed');if(this._worker.stdout.pause) this._worker.stdout.pause();};TidyWorker.prototype.resume=function(){if(!this._worker) throw new Error('worker has been destroyed');if(this._worker.stdout.resume) this._worker.stdout.resume();};TidyWorker.prototype.destroy=function(){if(this._worker) return;this._worker.kill();this._worker=null;this.emit('close');};function createWorker(opts){return new TidyWorker(opts);} function tidy(text,opts,cb){if(typeof opts=='function'){cb=opts;opts={};} if(typeof cb!='function') throw new Error('no callback provided for tidy');var worker=new TidyWorker(opts);var result='';var error='';worker.on('data',function(data){result+=data;});worker.on('error',function(data){error+=data;});worker.on('end',function(code){cb(error,result);});worker.end(text);} function chooseExec(){var tidyExe;switch(process.platform){case'win32':tidyExe=path.join('win32','tidy.exe');break;case'linux':tidyExe='tidy';break;case'darwin':tidyExe=path.join('darwin','tidy');break;default:throw new Error('unsupported execution platform');} if(process.platform=='linux'){__dirname='/usr';} tidyExe=path.join(__dirname,'bin',tidyExe);var existsSync=fs.existsSync||path.existsSync;if(!existsSync(tidyExe)) throw new Error('missing tidy executable: '+tidyExe);return tidyExe;} function parseOpts(opts){opts=opts||{};var args=[];for(var n in opts){args.push('--'+toHyphens(n));switch(typeof opts[n]){case'string':case'number':args.push(opts[n]);break;case'boolean':args.push(opts[n]?'yes':'no');break;default:throw new Error('unknown option type');}} return args;} function toHyphens(str){return str.replace(/([A-Z])/g,function(m,w){return'-'+w.toLowerCase();});} function merge(obj1,obj2){obj1=obj1||{};obj2=obj2||{};var obj3={};for(var attrname in obj2)obj3[attrname]=obj2[attrname];for(var attrname2 in obj1)obj3[attrname2]=obj1[attrname2];return obj3;} exports.createWorker=createWorker;exports.tidy=tidy; | |
// library:htmltidy:config | |
var opts = { | |
language : 'en', | |
charEncoding : 'utf8', | |
indent : 'auto', | |
doctype : 'html5', | |
tidyMark : false, | |
outputXhtml : true, | |
clean : true, | |
breakBeforeBr : true, | |
quiet : true, | |
tabSize : 4, | |
indentSpaces : 4 | |
} | |
/* ----------------------------- */ | |
/* JSON to HTML List Converter */ | |
/* ----------------------------- */ | |
// Get the JSON variable name to generate a list from or exit | |
if (process.argv[2] != null) { | |
var jsonDataName=process.argv[2]; | |
} else { | |
var appNameRegex = /[^\/]*$/; | |
var appName = appNameRegex.exec(process.argv[1]); | |
process.stdout.write('USAGE\n'); | |
process.stdout.write(' Generate HTML list from json data with matching names: '+appName+' [jsonHeading]\n'); | |
process.stdout.write(' Include a custom title and heading in the HTML output: '+appName+' [jsonHeading] [docTitle]\n'); | |
process.exit(0); | |
} | |
// Generate the HTML above the list and include a title if one was specified | |
var websiteTitle=''; | |
var websiteH1=''; | |
if (process.argv[3] != null) { | |
websiteTitle=process.argv[3]; | |
websiteH1='<h1>'+websiteTitle+'</h1>'; | |
} | |
var htmlHead='<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>'+websiteTitle+'</title></head><body>'+websiteH1; | |
// Read JSON from stdin | |
var stdin = process.stdin; | |
stdin.resume(); | |
stdin.setEncoding('utf8'); | |
stdin.on('data', function(json_string) { | |
if (json_string === '\u0003') process.exit(1); | |
// Transform JSON into HTML | |
json_string = '['+json_string+']' | |
var transform = {'tag':'li','html':'${'+jsonDataName+'}'} | |
var messyHTML = json2html.transform(json_string,transform); | |
// Clean HTML with tidy and write to stdout | |
tidy(htmlHead+'<ol>'+messyHTML+'</ol></body></html>', | |
function(err, tidyHTML) { | |
process.stdout.write(tidyHTML); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment