UNPKG

chocolate

Version:

A full stack Node.js web framework built using Coffeescript

465 lines (457 loc) 16.2 kB
// Generated by CoffeeScript 1.12.6 (function() { var _module, debug, doctypes, htmlkup, render, indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, hasProp = {}.hasOwnProperty; htmlkup = function(html, output_debug) { var SINGLETONS, c, condition, current, detect, final_whitespace, initial_indent, initial_whitespace, last_attr, last_tag, new_tag, next, nexts, noun, parent_tags, possibles, post_whitespace, pre_whitespace, preserve_ws, ref, ref1, regex, state, value, was_ws; preserve_ws = ['style', 'script']; SINGLETONS = ['area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source']; possibles = { start: ['tag-open', 'doctype', 'predoctype-whitespace', 'predoctype-comment-open', 'text', 'end'], doctype: ['reset'], reset: ['tag-open', 'ie-open', 'ie-close', 'comment-open', 'tag-close', 'text', 'end'], end: [], 'tag-open': ['attr-reset'], 'tag-close': ['reset'], 'tag-ws': ['attr', 'singleton', 'tag-gt'], 'tag-gt': ['cdata', 'reset'], 'singleton': ['reset'], 'attr-reset': ['tag-ws', 'singleton', 'tag-gt'], 'attr': ['tag-ws', 'attr-eq', 'tag-gt', 'singleton'], 'attr-eq': ['attr-value', 'attr-dqt', 'attr-sqt'], 'attr-dqt': ['attr-dvalue'], 'attr-sqt': ['attr-svalue'], 'attr-value': ['tag-ws', 'tag-gt', 'singleton'], 'attr-dvalue': ['attr-cdqt'], 'attr-svalue': ['attr-csqt'], 'attr-cdqt': ['tag-ws', 'tag-gt', 'singleton'], 'attr-csqt': ['tag-ws', 'tag-gt', 'singleton'], text: ['reset'], cdata: ['tag-close'], 'ie-open': ['reset'], 'ie-close': ['reset'], 'predoctype-whitespace': ['start'], 'predoctype-comment-open': ['predoctype-comment'], 'predoctype-comment': ['predoctype-comment-close'], 'predoctype-comment-close': ['start'], 'comment-open': ['comment'], 'comment': ['comment-close'], 'comment-close': ['reset'] }; detect = { 'start': /^/, 'reset': /^/, 'doctype': /^<!doctype .*?>/i, 'end': /^$/, 'tag-open': /^<[a-zA-Z]([-_]?[a-zA-Z0-9])*/, 'tag-close': /^<\/[a-zA-Z]([-_]?[a-zA-Z0-9])*>/, 'tag-ws': /^[ \t\n]+/, 'tag-gt': /^>/, 'singleton': /^\/>/, 'attr-reset': /^/, 'attr': /^[a-zA-Z]([-_]?[a-zA-Z0-9])*/, 'attr-eq': /^=/, 'attr-dqt': /^"/, 'attr-sqt': /^'/, 'attr-value': /^[a-zA-Z0-9]([-_]?[a-zA-Z0-9])*/, 'attr-dvalue': /^[^"]*/, 'attr-svalue': /^[^']*/, 'attr-cdqt': /^"/, 'attr-csqt': /^'/, 'cdata': /^(\/\/)?<!\[CDATA\[([^>]|>)*?\/\/]]>/, 'text': /^(.|\n)+?($|(?=<[!\/a-zA-Z]))/, 'ie-open': /^<!(?:--)?\[if.*?\]>/, 'ie-close': /^<!\[endif\](?:--)?>/, 'predoctype-whitespace': /^[ \t\n]+/, 'predoctype-comment-open': /^<!--/, 'predoctype-comment': /^(.|\n)*?(?=-->)/, 'predoctype-comment-close': /^-->/, 'comment-open': /^<!--/, 'comment': /^(.|\n)*?(?=-->)/, 'comment-close': /^-->/ }; state = 'start'; last_tag = { name: '', tags: [] }; last_attr = null; parent_tags = []; html = html.replace(/\t/g, ' '); html = html.replace(/\r/g, "\n"); initial_whitespace = (html.match(/^[ \n]*/))[0]; initial_indent = initial_whitespace.match(/[ ]*$/)[0]; initial_whitespace = initial_whitespace.substring(0, initial_whitespace.length - initial_indent.length); final_whitespace = (html.match(/[ \n]*$/))[0]; html = html.trim(); if (output_debug) { console.error({ initial_whitespace: initial_whitespace, initial_indent: initial_indent, final_whitespace: final_whitespace, html: html }); } was_ws = initial_whitespace.length ? true : false; c = 0; while (state !== 'end') { current = html.substring(c); if (!possibles[state]) { throw new Error("Missing possibles for " + state); } nexts = (function() { var i, len, ref, results; ref = possibles[state]; results = []; for (i = 0, len = ref.length; i < len; i++) { next = ref[i]; if (current.match(detect[next])) { results.push(next); } } return results; })(); if (!nexts.length) { throw new Error("At: " + state + " (" + (JSON.stringify(current.length > 10 ? current.substring(0, 10) + '...' : current)) + " @" + c + "), expected: " + (((function() { var i, len, ref, results; ref = possibles[state]; results = []; for (i = 0, len = ref.length; i < len; i++) { noun = ref[i]; results.push(noun); } return results; })()).join(' ')) + ", found " + (((function() { var results; results = []; for (noun in detect) { regex = detect[noun]; if (current.match(regex)) { results.push(noun); } } return results; })()).join(' '))); } next = nexts[0]; value = (current.match(detect[next]))[0]; c += value.length; if (output_debug) { console.error({ state: state, next: next, value: value }); } switch (next) { case 'doctype': last_tag.tags.push({ doctype: value.match(/^<!doctype (.*?)>$/i)[1].toLowerCase() }); break; case 'tag-open': new_tag = { name: value.substring(1), attrs: {}, tags: [] }; new_tag.is_singleton = (ref = new_tag.name, indexOf.call(SINGLETONS, ref) >= 0); last_tag.tags.push(new_tag); parent_tags.push(last_tag); if (output_debug) { console.error('push: ', parent_tags.length, last_tag); } last_tag = new_tag; last_attr = null; break; case 'attr': if (output_debug && last_attr) { console.error({ last_attr: last_attr }); } last_attr = value; break; case 'tag-ws': if (last_attr) { last_tag.attrs[last_attr] = true; } last_attr = null; break; case 'attr-value': case 'attr-dvalue': case 'attr-svalue': last_tag.attrs[last_attr] = value; last_attr = null; break; case 'tag-gt': if (last_attr) { last_tag.attrs[last_attr] = true; } if (last_tag.is_singleton && parent_tags.length) { last_tag = parent_tags.pop(); } if (output_debug) { console.error('closing: ', last_tag); } break; case 'singleton': case 'tag-close': case 'ie-close': if (parent_tags.length) { last_tag = parent_tags.pop(); } if (output_debug) { console.error('pop: ', parent_tags.length, last_tag); } break; case 'text': if (ref1 = last_tag.name, indexOf.call(preserve_ws, ref1) >= 0) { last_tag.tags.push(value); } else { pre_whitespace = (value.match(/^[ \n]*/))[0]; post_whitespace = (value.match(/[ \n]*$/))[0]; last_tag.tags.push((pre_whitespace ? ' ' : '') + value.trim() + (post_whitespace ? ' ' : '')); } break; case 'cdata': last_tag.tags.push(value); break; case 'comment': case 'predoctype-comment': last_tag.tags.push({ comment: value }); break; case 'ie-open': condition = value.match(/^<!(?:--)?\[if(.*?)\]>/)[1].trim(); new_tag = { name: 'ie', attrs: {}, tags: [], is_singleton: false, ie_condition: condition }; last_tag.tags.push(new_tag); parent_tags.push(last_tag); if (output_debug) { console.error('push: ', parent_tags.length, last_tag); } last_tag = new_tag; last_attr = null; } state = next; } if (output_debug) { console.error(parent_tags.length, last_tag); } while (parent_tags.length) { last_tag = parent_tags.pop(); } if (output_debug) { debug(last_tag.tags); } return initial_whitespace + (render(last_tag.tags, [initial_indent])).replace(/\n$/, '') + final_whitespace; }; doctypes = { 'html': 'default', 'html': '5', '<?xml version="1.0" encoding="utf-8" ?>': 'xml', 'html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"': 'transitional', 'html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"': 'strict', 'html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"': 'frameset', '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"': '1.1', 'html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd"': 'basic', 'html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd"': 'mobile', 'html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "ce-html-1.0-transitional.dtd"': 'ce' }; render = function(tags, indent) { var added_something, ak, attrs, av, classes, cls, extra, i, len, mapped, ref, ret, str, tag; if (indent == null) { indent = []; } ret = ''; for (i = 0, len = tags.length; i < len; i++) { tag = tags[i]; if (typeof tag === 'string') { str = tag; if (str.trim().length > 0) { if (str.match(/[\n]/)) { str = str.replace(/"""/g, '"\\""').replace(/^\n|\n$/g, ''); ret += (indent.join('')) + "text \"\"\"\n" + str + "\n\"\"\""; } else { ret += (indent.join('')) + "text " + (JSON.stringify(tag)); } ret += "\n"; } } else if (tag.doctype != null) { mapped = doctypes[tag.doctype.replace(/\s+/g, ' ')]; if (mapped === '5') { ret += "doctype 5"; } else { ret += "doctype " + (JSON.stringify((mapped != null ? mapped : tag.doctype))); } ret += "\n"; } else if (tag.comment != null) { ret += (indent.join('')) + "comment "; str = tag.comment.trim(); if (str.match(/\n/)) { indent.push(' '); str = str.replace(/"""/g, '"\\""').replace(/^\n|\n$/g, '').replace(/\n/g, "\n" + (indent.join(''))); ret += "\"\"\"\n" + (indent.join('')) + str + "\n" + (indent.join('')) + "\"\"\""; indent.pop(); } else { ret += JSON.stringify(str); } ret += "\n"; } else { ret += "" + (indent.join('')) + tag.name; extra = []; if (tag.attrs["class"]) { classes = (function() { var j, len1, ref, results; ref = tag.attrs["class"].split(" "); results = []; for (j = 0, len1 = ref.length; j < len1; j++) { cls = ref[j]; if (cls.trim() !== "") { results.push(cls.trim()); } } return results; })(); extra.push('.' + classes.join(".")); } if (tag.attrs.id) { extra.unshift("\#" + (tag.attrs.id.replace(/^\s*(\S*)\s*$/, "$1"))); } attrs = []; if (tag.attrs && Object.keys(tag.attrs).length) { ref = tag.attrs; for (ak in ref) { if (!hasProp.call(ref, ak)) continue; av = ref[ak]; if (ak === 'class' || ak === 'id') { continue; } if (av === true) { av = ak; } else if (av === false) { continue; } if (!ak.match(/^[a-zA-Z0-9]+$/)) { ak = JSON.stringify(ak); } if (!av.match(/^[0-9]+$/)) { av = JSON.stringify(av); } attrs.push(ak + ": " + av); } } added_something = false; if (extra.length) { ret += ' ' + JSON.stringify(extra.join("")); added_something = true; } if (tag.ie_condition) { ret += ' ' + JSON.stringify(tag.ie_condition); added_something = true; } if (attrs.length) { if (added_something) { ret += ', '; } else { ret += ' '; } ret += attrs.join(', '); added_something = true; } if (!added_something && tag.tags.length === 0) { ret += "()\n"; } else if (tag.tags.length === 0) { ret += "\n"; } else if (tag.tags.length === 1 && typeof tag.tags[0] === 'string') { str = tag.tags[0]; if (str.trim().length > 0) { if (added_something) { ret += ', '; } else { ret += ' '; } if (str.match(/\n/)) { indent.push(' '); str = str.replace(/"""/g, '"\\""').replace(/^\n|\n$/g, '').replace(/\n/g, "\n" + (indent.join(''))); ret += "\"\"\"\n" + (indent.join('')) + str + "\n" + (indent.join('')) + "\"\"\""; indent.pop(); } else { ret += JSON.stringify(str); } ret += "\n"; } } else { if (added_something) { ret += ', '; } else { ret += ' '; } ret += "->\n"; indent.push(' '); if (tag.tags.length) { ret += render(tag.tags, indent); } indent.pop(); } } } return ret; }; debug = function(tags, indent) { var ak, av, i, len, mapped, ref, results, tag; if (indent == null) { indent = []; } results = []; for (i = 0, len = tags.length; i < len; i++) { tag = tags[i]; if (typeof tag === 'string') { results.push(console.error((indent.join('')) + "text: " + tag)); } else if (tag.doctype) { mapped = doctypes[tag.doctype.replace(/\s+/g, ' ')]; results.push(console.error((indent.join('')) + "doctype: " + (JSON.stringify(tag.doctype)) + " => " + (JSON.stringify(mapped)))); } else if (tag.comment) { results.push(console.error((indent.join('')) + "comment: " + (JSON.stringify(tag.comment)))); } else { console.error((indent.join('')) + "{ name: " + tag.name); indent.push(' '); if (Object.keys(tag.attrs).length) { console.error((indent.join('')) + "attrs: {"); indent.push(' '); ref = tag.attrs; for (ak in ref) { if (!hasProp.call(ref, ak)) continue; av = ref[ak]; console.error("" + (indent.join('')) + ak + ": " + (JSON.stringify(av))); } console.error((indent.join('')) + "}"); indent.pop(); } if (tag.ie_condition) { console.error((indent.join('')) + "ie_condition: " + (JSON.stringify(tag.ie_condition))); } console.error((indent.join('')) + "tags:"); indent.push(' '); if (tag.tags.length) { debug(tag.tags, indent); } console.error((indent.join('')) + "}"); indent.pop(); console.error((indent.join('')) + "}"); results.push(indent.pop()); } } return results; }; _module = typeof window !== "undefined" && window !== null ? window : module; _module[_module.exports != null ? "exports" : "htmlkup"] = htmlkup; }).call(this);