From f7b90c4c194d6856964125460cf450763a9d2cd9 Mon Sep 17 00:00:00 2001 From: ccd0 Date: Fri, 27 Mar 2015 23:39:45 -0700 Subject: [PATCH] Rewrite HTML template parser. --- Gruntfile.coffee | 73 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 55 insertions(+), 18 deletions(-) diff --git a/Gruntfile.coffee b/Gruntfile.coffee index 0547bfb3a..90f48dd0a 100755 --- a/Gruntfile.coffee +++ b/Gruntfile.coffee @@ -7,25 +7,62 @@ module.exports = (grunt) -> importHTML = (filename) -> "(innerHTML: #{json grunt.file.read("src/General/html/#{filename}.html").replace(/^ +| +$ + while text + switch context + when '' + if part = text.match /^[^'"<>]+/ # plain text + else if part = text.match /^<\/\w+>/ # HTML end tag + else if part = text.match /^<\w+/ # start of HTML tag + context = '<' + when '<' + if part = text.match /^ [\w-]+(?![\w-=])/ # boolean attribute + else if part = text.match /^ [\w-]+=(['"])/ # start of attribute value + context = part[1] + else if part = text.match /^>/ # end of HTML tag + context = '' + when "'", '"' + if part = text.match /^[^'"<>]+/ # attribute value + else if part = text.match /^['"]/ # end of attribute value + throw new Error 'Inconsistent quoting' if part[0] isnt context + context = '<' + unless part + throw new Error "HTML template is ill-formed (at #{text})" + text = text[part[0].length..] + context + + parseTemplate = (template, context='') -> + context0 = context + parts = [] + text = template + while text + if part = text.match /^[^{}]+(?!{)/ + try + context = checkHTML part[0], context + catch err + throw new Error "#{err.message}: #{template}" + parts.push json part[0] + else if part = text.match /^([^}]){([^}`]*)}/ + unless context is '' or (part[1] is '$' and context isnt '<') + throw new Error "Illegal insertion into HTML template: #{template}" + parts.push switch part[1] + when '$' then "E(`#{part[2]}`)" + when '&' then "`#{part[2]}`.innerHTML" + when '@' then "`#{part[2]}`.map((x) -> x.innerHTML).join('')" + else + throw new Error "Unrecognized substitution operator (#{part[1]}): #{template}" + else + break + text = text[part[0].length..] + if context isnt context0 + throw new Error "HTML template not properly terminated: #{template}" + output = if parts.length is 0 then '""' else parts.join ' + ' + [output, text] + html = (template) -> - parts = template.split /([\$&@]){([^}`]*)}/ - parts2 = [] - checkText = '' - for part, i in parts - switch i % 3 - when 0 - parts2.push json part unless part is '' - checkText += part - when 1 - if /<[^>]*$/.test(checkText) and not (part is '$' and /\=['"][^"'<>]*$/.test checkText) - throw new Error "Illegal insertion into HTML template: #{template}" - parts2.push switch part - when '$' then "E(`#{parts[i+1]}`)" - when '&' then "`#{parts[i+1]}`.innerHTML" - when '@' then "`#{parts[i+1]}`.map((x) -> x.innerHTML).join('')" - unless /^(<\w+( [\w-]+(='[^"'<>]*'|="[^"'<>]*")?)*>|<\/\w+>|[^"'<>]*)*$/.test checkText - throw new Error "HTML template is ill-formed: #{template}" - output = if parts2.length is 0 then '""' else parts2.join ' + ' + [output, remaining] = parseTemplate template + if remaining + throw new Error "Unexpected characters in template (#{remaining}): #{template}" "(innerHTML: #{output})" assert = (statement, objs...) ->