riot-compiler
Advanced tools
Comparing version 2.3.0-beta.4 to 2.3.0-beta.5
@@ -1,2 +0,2 @@ | ||
/* riot-compiler 2.3.0-beta.3, @license MIT, (c) 2015 Muut Inc. + contributors */ | ||
/* riot-compiler 2.3.0-beta.5, @license MIT, (c) 2015 Muut Inc. + contributors */ | ||
;(function (root, factory) { | ||
@@ -18,4 +18,2 @@ | ||
var brackets = _tmpl.brackets | ||
/** | ||
@@ -25,28 +23,26 @@ * @module parsers | ||
var parsers = (function () { | ||
var _mods = {} | ||
function _try(name) { | ||
if (!(name in _mods)) { | ||
function _try(name, req) { | ||
function fn(r) { | ||
try { | ||
_mods[name] = require.resolve(name) | ||
_mods[name] = require(r) | ||
} | ||
catch (e) { | ||
_mods[name] = '' | ||
_mods[name] = null | ||
} | ||
return _mods[name] | ||
} | ||
return _mods[name] | ||
} | ||
function _get(req) { | ||
switch (req) { | ||
switch (name) { | ||
case 'es6': | ||
// istanbul ignore next: we have babel-core in test | ||
case 'babel': | ||
// istanbul ignore next: not both | ||
return _try('babel-core') || _try('babel') | ||
return fn('babel-core') || fn('babel') | ||
case 'none': | ||
case 'javascript': | ||
return 'none' | ||
return _js.none | ||
case 'typescript': | ||
req += '-simple' | ||
req = name + '-simple' | ||
break | ||
@@ -58,10 +54,10 @@ case 'coffee': | ||
default: | ||
if (!req) req = name | ||
break | ||
} | ||
return _try(req) | ||
return fn(req) | ||
} | ||
function _req(name) { | ||
var req = _get(name) | ||
return req ? require(req) : null | ||
function _req(name, req) { | ||
return name in _mods ? _mods[name] : _try(name, req) | ||
} | ||
@@ -78,5 +74,4 @@ | ||
var | ||
stylus = _req('stylus'), | ||
nib = _req('nib') | ||
// istanbul ignore next: not both | ||
stylus = _req('stylus'), nib = _req('nib') | ||
/* istanbul ignore next: can't run both */ | ||
return nib ? | ||
@@ -91,11 +86,8 @@ stylus(css).use(nib()).import('nib').render() : stylus.render(css) | ||
}, | ||
livescript: function (js) { | ||
return _req('livescript').compile(js, {bare: true, header: false}) | ||
}, | ||
typescript: function (js) { | ||
return _req('typescript')(js).replace(/\r\n?/g, '\n') | ||
}, | ||
es6: function (js) { | ||
@@ -106,3 +98,2 @@ return _req('es6').transform(js, { | ||
}, | ||
coffee: function (js) { | ||
@@ -113,357 +104,363 @@ return _req('coffee').compile(js, {bare: true}) | ||
_js.babel = _js.es6 | ||
_js.javascript = _js.none | ||
_js.coffeescript = _js.coffee | ||
return {html: _html, css: _css, js: _js, _get: _get} | ||
return {html: _html, css: _css, js: _js, _req: _req} | ||
})() | ||
/** | ||
* @module compiler | ||
*/ | ||
/** | ||
* @module compiler | ||
*/ | ||
function _regEx(str, opt) { return new RegExp(str, opt) } | ||
var brackets = _tmpl.brackets //eslint-disable-line no-redeclare | ||
var | ||
function _regEx(str, opt) { return new RegExp(str, opt) } | ||
BOOL_ATTRS = _regEx( | ||
'^(?:disabled|checked|readonly|required|allowfullscreen|auto(?:focus|play)|' + | ||
'compact|controls|default|formnovalidate|hidden|inert|ismap|itemscope|loop|' + | ||
'multiple|muted|no(?:resize|shade|validate|wrap)?|open|reversed|seamless|' + | ||
'selected|sortable|truespeed|typemustmatch)$'), | ||
var | ||
RIOT_ATTRS = ['style', 'src', 'd'], | ||
BOOL_ATTRS = _regEx( | ||
'^(?:disabled|checked|readonly|required|allowfullscreen|auto(?:focus|play)|' + | ||
'compact|controls|default|formnovalidate|hidden|inert|ismap|itemscope|loop|' + | ||
'multiple|muted|no(?:resize|shade|validate|wrap)?|open|reversed|seamless|' + | ||
'selected|sortable|truespeed|typemustmatch)$'), | ||
VOID_TAGS = /^(?:input|img|br|wbr|hr|area|base|col|embed|keygen|link|meta|param|source|track)$/, | ||
RIOT_ATTRS = ['style', 'src', 'd'], | ||
HTML_ATTR = /\s*([-\w:\.\xA0-\xFF]+)\s*(?:=\s*('[^']+'|"[^"]+"|\S+))?/g, | ||
VOID_TAGS = /^(?:input|img|br|wbr|hr|area|base|col|embed|keygen|link|meta|param|source|track)$/, | ||
TRIM_TRAIL = /[ \t]+$/gm, | ||
HTML_ATTR = /\s*([-\w:\.\xA0-\xFF]+)\s*(?:=\s*('[^']+'|"[^"]+"|\S+))?/g, | ||
_bp = null | ||
TRIM_TRAIL = /[ \t]+$/gm, | ||
var path = require('path') | ||
_bp = null | ||
function q(s) { | ||
var path = require('path') | ||
return "'" + (s ? s.replace(/\\/g, '\\\\').replace(/'/g, "\\'") : '') + "'" | ||
} | ||
function q(s) { | ||
function mktag(name, html, css, attrs, js, pcex) { | ||
var | ||
c = ', ', | ||
s = '}' + (pcex.length ? ', ' + q(_bp[8]) : '') + ');' | ||
return "'" + (s ? s.replace(/\\/g, '\\\\').replace(/'/g, "\\'") : '') + "'" | ||
} | ||
if (/\S/.test(js)) { | ||
js = js.replace(/\n{3,}/g, '\n\n') | ||
if (js.slice(-1) !== '\n') s = '\n' + s | ||
} | ||
else js = '' | ||
function mktag(name, html, css, attrs, js, pcex) { | ||
var | ||
c = ', ', | ||
s = '}' + (pcex.length ? ', ' + q(_bp[8]) : '') + ');' | ||
return 'riot.tag2(' + q(name) + c + q(html) + c + q(css) + c + q(attrs) + | ||
', function(opts) {\n' + js + s | ||
if (/\S/.test(js)) { | ||
js = js.replace(/\n{3,}/g, '\n\n') | ||
if (js.slice(-1) !== '\n') s = '\n' + s | ||
} | ||
else js = '' | ||
function parseAttrs(str) { | ||
var | ||
list = [], | ||
match, | ||
k, v, | ||
DQ = '"' | ||
HTML_ATTR.lastIndex = 0 | ||
return 'riot.tag2(' + q(name) + c + q(html) + c + q(css) + c + q(attrs) + | ||
', function(opts) {\n' + js + s | ||
} | ||
while (match = HTML_ATTR.exec(str)) { | ||
function parseAttrs(str) { | ||
var | ||
list = [], | ||
match, | ||
k, v, | ||
DQ = '"' | ||
HTML_ATTR.lastIndex = 0 | ||
k = match[1].toLowerCase() | ||
v = match[2] | ||
while (match = HTML_ATTR.exec(str)) { | ||
if (!v) { | ||
list.push(k) | ||
} | ||
else { | ||
k = match[1].toLowerCase() | ||
v = match[2] | ||
if (v[0] !== DQ) | ||
v = DQ + (v[0] === "'" ? v.slice(1, -1) : v) + DQ | ||
if (!v) { | ||
list.push(k) | ||
} | ||
else { | ||
if (k === 'type' && v.toLowerCase() === '"number"') { | ||
v = DQ + _bp[0] + "'number'" + _bp[1] + DQ | ||
} | ||
else if (/\u0001\d/.test(v)) { | ||
if (v[0] !== DQ) | ||
v = DQ + (v[0] === "'" ? v.slice(1, -1) : v) + DQ | ||
if (BOOL_ATTRS.test(k)) { | ||
k = '__' + k | ||
} | ||
else if (~RIOT_ATTRS.indexOf(k)) { | ||
k = 'riot-' + k | ||
} | ||
if (k === 'type' && v.toLowerCase() === '"number"') { | ||
v = DQ + _bp[0] + "'number'" + _bp[1] + DQ | ||
} | ||
else if (/\u0001\d/.test(v)) { | ||
if (BOOL_ATTRS.test(k)) { | ||
k = '__' + k | ||
} | ||
else if (~RIOT_ATTRS.indexOf(k)) { | ||
k = 'riot-' + k | ||
} | ||
} | ||
list.push(k + '=' + v) | ||
} | ||
list.push(k + '=' + v) | ||
} | ||
return list.join(' ') | ||
} | ||
return list.join(' ') | ||
} | ||
function splitHtml(html, opts, pcex) { | ||
function splitHtml(html, opts, pcex) { | ||
if (html && _bp[4].test(html)) { | ||
var | ||
jsfn = opts.expr && (opts.parser || opts.type) ? compileJS : 0, | ||
list = brackets.split(html), | ||
expr | ||
if (html && _bp[4].test(html)) { | ||
var | ||
jsfn = opts.expr && (opts.parser || opts.type) ? compileJS : 0, | ||
list = brackets.split(html), | ||
expr | ||
for (var i = 1; i < list.length; i += 2) { | ||
expr = list[i] | ||
if (expr[0] === '^') { | ||
expr = expr.slice(1) | ||
} | ||
else if (jsfn) { | ||
expr = jsfn(expr, opts).replace(/[\r\n]+/g, ' ').trim() | ||
if (expr.slice(-1) === ';') expr = expr.slice(0, -1) | ||
} | ||
list[i] = "\u0001" + (pcex.push(expr.trim()) - 1) + _bp[1] | ||
for (var i = 1; i < list.length; i += 2) { | ||
expr = list[i] | ||
if (expr[0] === '^') { | ||
expr = expr.slice(1) | ||
} | ||
html = list.join('') | ||
else if (jsfn) { | ||
expr = jsfn(expr, opts).replace(/[\r\n]+/g, ' ').trim() | ||
if (expr.slice(-1) === ';') expr = expr.slice(0, -1) | ||
} | ||
list[i] = '\u0001' + (pcex.push(expr.trim()) - 1) + _bp[1] | ||
} | ||
return html | ||
html = list.join('') | ||
} | ||
return html | ||
} | ||
function restoreExpr(html, pcex) { | ||
if (pcex.length) { | ||
html = html | ||
.replace(/\u0001(\d+)/g, function (_, d) { | ||
return _bp[0] + pcex[d].replace(/"/g, '"') | ||
}) | ||
} | ||
return html | ||
function restoreExpr(html, pcex) { | ||
if (pcex.length) { | ||
html = html | ||
.replace(/\u0001(\d+)/g, function (_, d) { | ||
return _bp[0] + pcex[d].replace(/"/g, '"') | ||
}) | ||
} | ||
return html | ||
} | ||
var | ||
HTML_COMMENT = /<!--(?!>)[\S\s]*?-->/g, | ||
HTML_TAGS = /<([-\w]+)\s*([^"'\/>]*(?:(?:"[^"]*"|'[^']*'|\/[^>])[^'"\/>]*)*)(\/?)>/g | ||
var | ||
HTML_COMMENT = /<!--(?!>)[\S\s]*?-->/g, | ||
HTML_TAGS = /<([-\w]+)\s*([^"'\/>]*(?:(?:"[^"]*"|'[^']*'|\/[^>])[^'"\/>]*)*)(\/?)>/g | ||
function compileHTML(html, opts, pcex, intc) { | ||
function compileHTML(html, opts, pcex, intc) { | ||
if (!intc) { | ||
_bp = brackets.array(opts.brackets) | ||
html = html.replace(HTML_COMMENT, '').replace(TRIM_TRAIL, '') | ||
} | ||
if (!pcex) pcex = [] | ||
if (!intc) { | ||
_bp = brackets.array(opts.brackets) | ||
html = html.replace(HTML_COMMENT, '').replace(TRIM_TRAIL, '') | ||
} | ||
if (!pcex) pcex = [] | ||
html = splitHtml(html, opts, pcex) | ||
.replace(HTML_TAGS, function (_, name, attr, ends) { | ||
html = splitHtml(html, opts, pcex) | ||
.replace(HTML_TAGS, function (_, name, attr, ends) { | ||
name = name.toLowerCase() | ||
name = name.toLowerCase() | ||
ends = ends && !VOID_TAGS.test(name) ? '></' + name : '' | ||
ends = ends && !VOID_TAGS.test(name) ? '></' + name : '' | ||
if (attr) name += ' ' + parseAttrs(attr) | ||
if (attr) name += ' ' + parseAttrs(attr) | ||
return '<' + name + ends + '>' | ||
}) | ||
return '<' + name + ends + '>' | ||
}) | ||
html = opts.whitespace ? | ||
html.replace(/\r\n?|\n/g, '\\n') : html.trim().replace(/\s+/g, ' ') | ||
html = opts.whitespace ? | ||
html.replace(/\r\n?|\n/g, '\\n') : html.trim().replace(/\s+/g, ' ') | ||
if (opts.compact) html = html.replace(/> <([-\w\/])/g, '><$1') | ||
if (opts.compact) html = html.replace(/> <([-\w\/])/g, '><$1') | ||
return restoreExpr(html, pcex) | ||
} | ||
return restoreExpr(html, pcex) | ||
} | ||
var | ||
var | ||
JS_RMCOMMS = _regEx( | ||
'(' + brackets.S_QBLOCKS + ')|' + brackets.R_MLCOMMS.source + '|//[^\r\n]*', | ||
'g'), | ||
JS_RMCOMMS = _regEx( | ||
'(' + brackets.S_QBLOCKS + ')|' + brackets.R_MLCOMMS.source + '|//[^\r\n]*', | ||
'g'), | ||
JS_ES6SIGN = /^([ \t]*)([$_A-Za-z][$\w]*)\s*(\([^()]*\)\s*{)/m | ||
JS_ES6SIGN = /^([ \t]*)([$_A-Za-z][$\w]*)\s*(\([^()]*\)\s*{)/m | ||
function riotjs(js) { | ||
var | ||
match, | ||
toes5, | ||
parts = [], | ||
pos | ||
function riotjs(js) { | ||
var | ||
match, | ||
toes5, | ||
parts = [], | ||
pos | ||
js = js.replace(JS_RMCOMMS, function (m, q) { return q ? m : ' ' }) | ||
js = js.replace(JS_RMCOMMS, function (m, q) { return q ? m : ' ' }) | ||
while (match = js.match(JS_ES6SIGN)) { | ||
while (match = js.match(JS_ES6SIGN)) { | ||
parts.push(RegExp.leftContext) | ||
js = RegExp.rightContext | ||
pos = skipBlock(js) | ||
parts.push(RegExp.leftContext) | ||
js = RegExp.rightContext | ||
pos = skipBlock(js) | ||
toes5 = !/^(?:if|while|for|switch|catch|function)$/.test(match[2]) | ||
if (toes5) | ||
match[0] = match[1] + 'this.' + match[2] + ' = function' + match[3] | ||
toes5 = !/^(?:if|while|for|switch|catch|function)$/.test(match[2]) | ||
if (toes5) | ||
match[0] = match[1] + 'this.' + match[2] + ' = function' + match[3] | ||
parts.push(match[0], js.slice(0, pos)) | ||
js = js.slice(pos) | ||
if (toes5 && !/^\s*.\s*bind\b/.test(js)) parts.push('.bind(this)') | ||
} | ||
parts.push(match[0], js.slice(0, pos)) | ||
js = js.slice(pos) | ||
if (toes5 && !/^\s*.\s*bind\b/.test(js)) parts.push('.bind(this)') | ||
} | ||
return parts.length ? parts.join('') + js : js | ||
return parts.length ? parts.join('') + js : js | ||
function skipBlock(str) { | ||
var | ||
re = _regEx('([{}])|' + brackets.S_QBLOCKS, 'g'), | ||
level = 1, | ||
match | ||
function skipBlock(str) { | ||
var | ||
re = _regEx('([{}])|' + brackets.S_QBLOCKS, 'g'), | ||
level = 1, | ||
match | ||
while (level && (match = re.exec(str))) { | ||
if (match[1]) | ||
match[1] === '{' ? ++level : --level | ||
} | ||
return level ? str.length : re.lastIndex | ||
while (level && (match = re.exec(str))) { | ||
if (match[1]) | ||
match[1] === '{' ? ++level : --level | ||
} | ||
return level ? str.length : re.lastIndex | ||
} | ||
} | ||
function compileJS(js, opts, type) { | ||
if (!type) type = opts.type | ||
function compileJS(js, opts, type) { | ||
if (!type) type = opts.type | ||
var parser = opts.parser || (type ? parsers.js[type] : riotjs) | ||
if (!parser) | ||
throw new Error('JS parser not found: "' + type + '"') | ||
var parser = opts.parser || (type ? parsers.js[type] : riotjs) | ||
if (!parser) | ||
throw new Error('JS parser not found: "' + type + '"') | ||
return parser(js, opts).replace(TRIM_TRAIL, '') | ||
} | ||
return parser(js).replace(TRIM_TRAIL, '') | ||
} | ||
var CSS_SELECTOR = _regEx('(}|{|^)[ ;]*([^@ ;][^{}]*)(?={)|' + brackets.R_STRINGS.source, 'g') | ||
var CSS_SELECTOR = _regEx('(}|{|^)[ ;]*([^@ ;][^{}]*)(?={)|' + brackets.R_STRINGS.source, 'g') | ||
function scopedCSS(tag, style) { | ||
var scope = ':scope' | ||
function scopedCSS(tag, style) { | ||
var scope = ':scope' | ||
return style.replace(CSS_SELECTOR, function (m, p1, p2) { | ||
return style.replace(CSS_SELECTOR, function (m, p1, p2) { | ||
if (!p2) return m | ||
if (!p2) return m | ||
p2 = p2.replace(/[^,]+/g, function (sel) { | ||
var s = sel.trim() | ||
p2 = p2.replace(/[^,]+/g, function (sel) { | ||
var s = sel.trim() | ||
if (s && s !== 'from' && s !== 'to' && s.slice(-1) !== '%') { | ||
if (s && s !== 'from' && s !== 'to' && s.slice(-1) !== '%') { | ||
if (s.indexOf(scope) < 0) s = scope + ' ' + s | ||
s = s.replace(scope, tag) + ',' + | ||
s.replace(scope, '[riot-tag="' + tag + '"]') | ||
} | ||
return sel.slice(-1) === ' ' ? s + ' ' : s | ||
}) | ||
return p1 ? p1 + ' ' + p2 : p2 | ||
if (s.indexOf(scope) < 0) s = scope + ' ' + s | ||
s = s.replace(scope, tag) + ',' + | ||
s.replace(scope, '[riot-tag="' + tag + '"]') | ||
} | ||
return sel.slice(-1) === ' ' ? s + ' ' : s | ||
}) | ||
} | ||
function compileCSS(style, tag, type, scoped) { | ||
return p1 ? p1 + ' ' + p2 : p2 | ||
}) | ||
} | ||
if (type) { | ||
if (type === 'scoped-css') { | ||
scoped = true | ||
} | ||
else if (parsers.css[type]) { | ||
style = parsers.css[type](tag, style) | ||
} | ||
// istanbul ignore else: fallback to nothing | ||
else if (type !== 'css') { | ||
throw new Error('CSS parser not found: "' + type + '"') | ||
} | ||
function compileCSS(style, tag, type, scoped) { | ||
if (type) { | ||
if (type === 'scoped-css') { | ||
scoped = true | ||
} | ||
else if (parsers.css[type]) { | ||
style = parsers.css[type](tag, style) | ||
} | ||
// istanbul ignore else: fallback to nothing | ||
else if (type !== 'css') { | ||
throw new Error('CSS parser not found: "' + type + '"') | ||
} | ||
} | ||
style = style.replace(brackets.R_MLCOMMS, '').replace(/\s+/g, ' ').trim() | ||
style = style.replace(brackets.R_MLCOMMS, '').replace(/\s+/g, ' ').trim() | ||
return scoped ? scopedCSS(tag, style) : style | ||
} | ||
return scoped ? scopedCSS(tag, style) : style | ||
} | ||
var TYPE_ATTR = /\stype\s*=\s*(?:['"]([^'"]+)['"]|(\S+))/i | ||
var TYPE_ATTR = /\stype\s*=\s*(?:['"]([^'"]+)['"]|(\S+))/i | ||
function getType(str) { | ||
function getType(str) { | ||
if (str) { | ||
var match = str.match(TYPE_ATTR) | ||
str = match && (match[1] || match[2]) | ||
} | ||
return str ? str.replace('text/', '') : '' | ||
if (str) { | ||
var match = str.match(TYPE_ATTR) | ||
str = match && (match[1] || match[2]) | ||
} | ||
return str ? str.replace('text/', '') : '' | ||
} | ||
function getCode(code, opts, attrs) { | ||
var type = getType(attrs) | ||
function getCode(code, opts, attrs) { | ||
var type = getType(attrs) | ||
return compileJS(code, opts, type) | ||
} | ||
return compileJS(code, opts, type) | ||
} | ||
var END_TAGS = /\/>\n|<(?:\/[\w\-]+\s*|[\w\-]+(?:\s+(?:[-\w:\xA0-\xFF][\S\s]*?)?)?)>\n/g | ||
var END_TAGS = /\/>\n|<(?:\/[\w\-]+\s*|[\w\-]+(?:\s+(?:[-\w:\xA0-\xFF][\S\s]*?)?)?)>\n/g | ||
function splitBlocks(str) { | ||
var | ||
i, k, js = '', len = str.length | ||
function splitBlocks(str) { | ||
var | ||
i, k, js = '', len = str.length | ||
if (len && str[len - 1] !== '>') { | ||
k = str.indexOf('<') | ||
if (k < 0 || (i = str.lastIndexOf('>\n')) < 0 || k > i) | ||
return ['', str] | ||
k = str.indexOf('<') | ||
if (k < 0 || (i = str.lastIndexOf('>\n')) < 0 || k > i) | ||
return ['', str] | ||
i += 2 | ||
js = str.slice(i) | ||
str = str.slice(0, i) | ||
if (str[i - 3] !== '/') { | ||
i += 2 | ||
js = str.slice(i) | ||
str = str.slice(0, i) | ||
if (str[i - 3] !== '/') { | ||
if (str.match(END_TAGS)) { | ||
var s = RegExp.rightContext | ||
if (s) { | ||
js = s + js | ||
str = str.slice(0, len - js.length) | ||
} | ||
} | ||
else { | ||
js = str + js | ||
str = '' | ||
} | ||
if (str.match(END_TAGS)) { | ||
var s = RegExp.rightContext | ||
if (s) { | ||
js = s + js | ||
str = str.slice(0, len - js.length) | ||
} | ||
} | ||
return [str, js] | ||
else { | ||
js = str + js | ||
str = '' | ||
} | ||
} | ||
return [str, js] | ||
} | ||
function compileTemplate(lang, html) { | ||
var parser = parsers.html[lang] | ||
function compileTemplate(lang, html) { | ||
var parser = parsers.html[lang] | ||
if (!parser) | ||
throw new Error('Template parser not found: "' + lang + '"') | ||
if (!parser) | ||
throw new Error('Template parser not found: "' + lang + '"') | ||
return parser(html) | ||
} | ||
return parser(html) | ||
} | ||
var | ||
CUST_TAG = /^[ \t]*<([-\w]+)\s*([^'"\/>]*(?:(?:\/[^>]|"[^"]*"|'[^']*')[^'"\/>]*)*)(?:\/|>\n?([^<]*(?:<(?!\/\1\s*>[ \t]*$)[^<]*)*)<\/\1\s*)>[ \t]*$/gim, | ||
STYLE = /<style(\s+[^>]*)?>\n?([^<]*(?:<(?!\/style\s*>)[^<]*)*)<\/style\s*>/gi, | ||
SCRIPT = _regEx(STYLE.source.replace(/tyle/g, 'cript'), 'gi') | ||
var | ||
CUST_TAG = /^<([-\w]+)(?:\s+([^'"\/>]+(?:(?:"[^"]*"|'[^']*'|\/[^>])[^'"\/>]*)*)|\s*)?(?:\/>|>[ \t]*\n?([\s\S]*)^<\/\1\s*>|>(.*)<\/\1\s*>)/gim, | ||
STYLE = /<style(\s+[^>]*)?>\n?([^<]*(?:<(?!\/style\s*>)[^<]*)*)<\/style\s*>/gi, | ||
SCRIPT = _regEx(STYLE.source.replace(/tyle/g, 'cript'), 'gi') | ||
function compile(src, opts, url) { | ||
function compile(src, opts, url) { | ||
var label | ||
if (!opts) opts = {} | ||
if (!opts) opts = {} | ||
_bp = brackets.array(opts.brackets) | ||
_bp = brackets.array(opts.brackets) | ||
if (opts.template) | ||
src = compileTemplate(opts.template, src) | ||
if (opts.template) | ||
src = compileTemplate(opts.template, src) | ||
url = url ? | ||
'//src: ' + (/:\/\//.test(url) ? url : path.relative('.', url)) + '\n' : '' | ||
label = url ? '//src: ' + path.relative('.', url) + '\n' : '' | ||
return url + src | ||
.replace(/\r\n?/g, '\n') | ||
.replace(CUST_TAG, function (_, tagName, attribs, body) { | ||
return label + src | ||
.replace(/\r\n?/g, '\n') | ||
.replace(CUST_TAG, function (_, tagName, attribs, body, body2) { | ||
var | ||
jscode = '', | ||
styles = '', | ||
html = '', | ||
pcex = [] | ||
var | ||
jscode = '', | ||
styles = '', | ||
html = '', | ||
pcex = [] | ||
tagName = tagName.toLowerCase() | ||
tagName = tagName.toLowerCase() | ||
if (attribs) | ||
attribs = restoreExpr(parseAttrs(splitHtml(attribs, opts, pcex)), pcex) | ||
if (attribs) | ||
attribs = restoreExpr(parseAttrs(splitHtml(attribs, opts, pcex)), pcex) | ||
body = body && body.replace(HTML_COMMENT, '') | ||
if (body) { | ||
if (body2) body = body2 | ||
if (body && (body = body.replace(HTML_COMMENT, '')) && /\S/.test(body)) { | ||
if (body2) | ||
html = compileHTML(body2, opts, pcex, 1) | ||
else { | ||
body = body.replace(STYLE, function (_, _attrs, _style) { | ||
@@ -488,9 +485,10 @@ var scoped = _attrs && /\sscoped(\s|=|$)/i.test(_attrs) | ||
body = blocks[1] | ||
if (body && /\S/.test(body)) | ||
if (/\S/.test(body)) | ||
jscode += (jscode ? '\n' : '') + compileJS(body, opts) | ||
} | ||
} | ||
return mktag(tagName, html, styles, attribs, jscode, pcex) | ||
}) | ||
} | ||
return mktag(tagName, html, styles, attribs, jscode, pcex) | ||
}) | ||
} | ||
@@ -497,0 +495,0 @@ return { |
/** | ||
* Compiler for riot custom tags | ||
* @version 2.3.0-beta.3 | ||
* @version 2.3.0-beta.5 | ||
*/ | ||
@@ -11,43 +11,22 @@ | ||
var parsers = (function () { | ||
'use strict' //eslint-disable-line | ||
var _mods = {} | ||
function _try(name) { | ||
if (!(name in _mods)) { | ||
try { | ||
_mods[name] = require.resolve(name) | ||
} | ||
catch (e) { | ||
_mods[name] = '' | ||
} | ||
} | ||
return _mods[name] | ||
} | ||
function _try(name, req) { //eslint-disable-line no-redeclare | ||
function _get(req) { | ||
switch (req) { | ||
switch (name) { | ||
case 'coffee': | ||
req = 'CoffeeScript' | ||
break | ||
case 'es6': | ||
case 'babel': | ||
// istanbul ignore next: not both | ||
return _try('babel-core') || _try('babel') | ||
case 'none': | ||
case 'javascript': | ||
return 'none' | ||
case 'typescript': | ||
req += '-simple' | ||
req = 'babel' | ||
break | ||
case 'coffee': | ||
case 'coffeescript': | ||
req = 'coffee-script' | ||
break | ||
default: | ||
if (!req) req = name | ||
break | ||
} | ||
return _try(req) | ||
return _mods[name] = window[req] | ||
} | ||
function _req(name) { | ||
var req = _get(name) | ||
return req ? require(req) : null | ||
function _req(name, req) { | ||
return name in _mods ? _mods[name] : _try(name, req) | ||
} | ||
@@ -64,5 +43,4 @@ | ||
var | ||
stylus = _req('stylus'), | ||
nib = _req('nib') | ||
// istanbul ignore next: not both | ||
stylus = _req('stylus'), nib = _req('nib') | ||
/* istanbul ignore next: can't run both */ | ||
return nib ? | ||
@@ -77,11 +55,8 @@ stylus(css).use(nib()).import('nib').render() : stylus.render(css) | ||
}, | ||
livescript: function (js) { | ||
return _req('livescript').compile(js, {bare: true, header: false}) | ||
}, | ||
typescript: function (js) { | ||
return _req('typescript')(js).replace(/\r\n?/g, '\n') | ||
}, | ||
es6: function (js) { | ||
@@ -92,3 +67,2 @@ return _req('es6').transform(js, { | ||
}, | ||
coffee: function (js) { | ||
@@ -99,9 +73,12 @@ return _req('coffee').compile(js, {bare: true}) | ||
_js.babel = _js.es6 | ||
_js.javascript = _js.none | ||
_js.coffeescript = _js.coffee | ||
return {html: _html, css: _css, js: _js, _get: _get} | ||
return {html: _html, css: _css, js: _js, _req: _req} | ||
})() | ||
riot.parsers = parsers | ||
/** | ||
@@ -111,4 +88,5 @@ * @module compiler | ||
var compile = (function () { | ||
'use strict' //eslint-disable-line | ||
var brackets = riot.util.brackets | ||
function _regEx(str, opt) { return new RegExp(str, opt) } | ||
@@ -211,3 +189,3 @@ | ||
} | ||
list[i] = "\u0001" + (pcex.push(expr.trim()) - 1) + _bp[1] | ||
list[i] = '\u0001' + (pcex.push(expr.trim()) - 1) + _bp[1] | ||
} | ||
@@ -316,3 +294,3 @@ html = list.join('') | ||
return parser(js, opts).replace(TRIM_TRAIL, '') | ||
return parser(js).replace(TRIM_TRAIL, '') | ||
} | ||
@@ -388,24 +366,22 @@ | ||
if (len && str[len - 1] !== '>') { | ||
k = str.indexOf('<') | ||
if (k < 0 || (i = str.lastIndexOf('>\n')) < 0 || k > i) | ||
return ['', str] | ||
k = str.indexOf('<') | ||
if (k < 0 || (i = str.lastIndexOf('>\n')) < 0 || k > i) | ||
return ['', str] | ||
i += 2 | ||
js = str.slice(i) | ||
str = str.slice(0, i) | ||
if (str[i - 3] !== '/') { | ||
i += 2 | ||
js = str.slice(i) | ||
str = str.slice(0, i) | ||
if (str[i - 3] !== '/') { | ||
if (str.match(END_TAGS)) { | ||
var s = RegExp.rightContext | ||
if (s) { | ||
js = s + js | ||
str = str.slice(0, len - js.length) | ||
} | ||
if (str.match(END_TAGS)) { | ||
var s = RegExp.rightContext | ||
if (s) { | ||
js = s + js | ||
str = str.slice(0, len - js.length) | ||
} | ||
else { | ||
js = str + js | ||
str = '' | ||
} | ||
} | ||
else { | ||
js = str + js | ||
str = '' | ||
} | ||
} | ||
@@ -425,3 +401,3 @@ return [str, js] | ||
var | ||
CUST_TAG = /^[ \t]*<([-\w]+)\s*([^'"\/>]*(?:(?:\/[^>]|"[^"]*"|'[^']*')[^'"\/>]*)*)(?:\/|>\n?([^<]*(?:<(?!\/\1\s*>[ \t]*$)[^<]*)*)<\/\1\s*)>[ \t]*$/gim, | ||
CUST_TAG = /^<([-\w]+)(?:\s+([^'"\/>]+(?:(?:"[^"]*"|'[^']*'|\/[^>])[^'"\/>]*)*)|\s*)?(?:\/>|>[ \t]*\n?([\s\S]*)^<\/\1\s*>|>(.*)<\/\1\s*>)/gim, | ||
STYLE = /<style(\s+[^>]*)?>\n?([^<]*(?:<(?!\/style\s*>)[^<]*)*)<\/style\s*>/gi, | ||
@@ -431,2 +407,3 @@ SCRIPT = _regEx(STYLE.source.replace(/tyle/g, 'cript'), 'gi') | ||
function compile(src, opts, url) { | ||
var label | ||
@@ -440,8 +417,7 @@ if (!opts) opts = {} | ||
url = url ? | ||
'//src: ' + (/:\/\//.test(url) ? url : path.relative('.', url)) + '\n' : '' | ||
label = url ? '//src: ' + url + '\n' : '' | ||
return url + src | ||
return label + src | ||
.replace(/\r\n?/g, '\n') | ||
.replace(CUST_TAG, function (_, tagName, attribs, body) { | ||
.replace(CUST_TAG, function (_, tagName, attribs, body, body2) { | ||
@@ -459,26 +435,32 @@ var | ||
body = body && body.replace(HTML_COMMENT, '') | ||
if (body) { | ||
if (body2) body = body2 | ||
body = body.replace(STYLE, function (_, _attrs, _style) { | ||
var scoped = _attrs && /\sscoped(\s|=|$)/i.test(_attrs) | ||
styles += (styles ? ' ' : '') + | ||
compileCSS(_style, tagName, getType(_attrs), scoped) | ||
return '' | ||
}) | ||
if (body && (body = body.replace(HTML_COMMENT, '')) && /\S/.test(body)) { | ||
body = body.replace(SCRIPT, function (_, _attrs, _script) { | ||
jscode += (jscode ? '\n' : '') + getCode(_script, opts, _attrs) | ||
return '' | ||
}) | ||
if (body2) | ||
html = compileHTML(body2, opts, pcex, 1) | ||
else { | ||
var blocks = splitBlocks(body.replace(TRIM_TRAIL, '')) | ||
body = body.replace(STYLE, function (_, _attrs, _style) { | ||
var scoped = _attrs && /\sscoped(\s|=|$)/i.test(_attrs) | ||
styles += (styles ? ' ' : '') + | ||
compileCSS(_style, tagName, getType(_attrs), scoped) | ||
return '' | ||
}) | ||
body = blocks[0] | ||
if (body) | ||
html = compileHTML(body, opts, pcex, 1) | ||
body = body.replace(SCRIPT, function (_, _attrs, _script) { | ||
jscode += (jscode ? '\n' : '') + getCode(_script, opts, _attrs) | ||
return '' | ||
}) | ||
body = blocks[1] | ||
if (body && /\S/.test(body)) | ||
jscode += (jscode ? '\n' : '') + compileJS(body, opts) | ||
var blocks = splitBlocks(body.replace(TRIM_TRAIL, '')) | ||
body = blocks[0] | ||
if (body) | ||
html = compileHTML(body, opts, pcex, 1) | ||
body = blocks[1] | ||
if (/\S/.test(body)) | ||
jscode += (jscode ? '\n' : '') + compileJS(body, opts) | ||
} | ||
} | ||
@@ -490,107 +472,5 @@ | ||
})() | ||
return compile | ||
/** | ||
* Compilation for the Browser | ||
* @module riot.compile | ||
*/ | ||
riot.compile = (function () { | ||
'use strict' //eslint-disable-line | ||
var | ||
doc = typeof window === 'object' ? window.document : null, | ||
promise, | ||
ready, | ||
forEach = Array.prototype.forEach | ||
function GET(url, callback) { | ||
var req = new XMLHttpRequest() | ||
req.onreadystatechange = function () { | ||
if (req.readyState === 4) { | ||
if (req.status === 200 || !req.status && req.responseText.length) | ||
callback(req.responseText, url) | ||
} | ||
} | ||
req.open('GET', url, true) | ||
req.send('') | ||
} | ||
function unindent(src) { | ||
var ident = src.match(/^[ \t]+/) | ||
if (ident) src = src.replace(new RegExp('^' + ident[0], 'gm'), '') | ||
return src | ||
} | ||
function globalEval(js) { | ||
var | ||
node = doc.createElement('script'), | ||
root = doc.documentElement | ||
node.text = js | ||
root.appendChild(node) | ||
root.removeChild(node) | ||
} | ||
function compileScripts(callback) { | ||
var | ||
scripts = doc.querySelectorAll('script[type="riot/tag"]'), | ||
scriptsAmount = scripts.length | ||
function done() { | ||
promise.trigger('ready') | ||
ready = true | ||
if (callback) callback() | ||
} | ||
function compileTag(source, url) { | ||
globalEval(compile(source, url)) | ||
if (!--scriptsAmount) done() | ||
} | ||
if (scriptsAmount) { | ||
forEach.call(scripts, function (script) { | ||
var url = script.getAttribute('src') | ||
url ? GET(url, compileTag) : compileTag(script.innerHTML, url) | ||
}) | ||
} | ||
else done() | ||
} | ||
return function _loadAndCompile(arg, fn) { | ||
if (typeof arg === 'string') { | ||
if (/^\s*</.test(arg)) { | ||
var js = unindent(compile(arg)) | ||
if (!fn) globalEval(js) | ||
return js | ||
} else { | ||
return GET(arg, function (str, url) { | ||
var js = unindent(compile(str, url)) | ||
globalEval(js) | ||
if (fn) fn(js, str) | ||
}) | ||
} | ||
} | ||
fn = typeof arg !== 'function' ? undefined : arg | ||
if (ready) | ||
return fn && fn() | ||
if (promise) { | ||
if (fn) | ||
promise.on('ready', fn) | ||
} else { | ||
promise = riot.observable() | ||
compileScripts(fn) | ||
} | ||
} | ||
})() | ||
# Backslashes and Whitespace | ||
From the perspective of the riot compiler and `tmpl`, backslashes in the template are characters without special meaning, the compiler preserves this in the HTML, and remove inside the expressions. | ||
From the perspective of the riot compiler and `tmpl`, backslashes within the template are characters without special meaning, except when prefixed to riot brackets. `tmpl` removes the escape character from the riot brackets when compiling the template, the other backslashes are preserved. EOLs are converted to spaces and compacted. This happens in the quoted HTML text and element values, inclusive. | ||
EOLs are converted to spaces and compacted. This happens in the quoted HTML text and the element values. | ||
In strings and regexes inside expressions, whitespace are preserved. |
141
lib/core.js
@@ -6,5 +6,7 @@ /** | ||
var compile = (function () { | ||
'use strict' //eslint-disable-line | ||
var brackets = riot.util.brackets | ||
//#else | ||
//#define READ_JS_SRC 0 | ||
var brackets = _tmpl.brackets //eslint-disable-line no-redeclare | ||
//#endif | ||
@@ -60,13 +62,2 @@ | ||
//#define $_HIDEXPR_MARK '\u0001' | ||
//#define $_HIDEXPR_REPL /\u0001(\d+)/g | ||
//#define $_HIDEXPR_TEST /\u0001\d/ | ||
//#ifndef $_HIDEXPR_MARK | ||
var | ||
// REMEMBER EDIT THE #defines TOO!!! | ||
$_HIDEXPR_MARK = '\u0001', | ||
$_HIDEXPR_REPL = /\u0001(\d+)/g, | ||
$_HIDEXPR_TEST = /\u0001\d/ //http://jsperf.com/riot-regexp-indexof-dif | ||
//#endif | ||
// Escape backslashes and inner single quotes, and enclose s in single quotes | ||
@@ -127,3 +118,3 @@ function q(s) { | ||
} | ||
else if ($_HIDEXPR_TEST.test(v)) { | ||
else if (/\u0001\d/.test(v)) { | ||
// renames special attributes with expressiones in their value. | ||
@@ -165,3 +156,3 @@ if (BOOL_ATTRS.test(k)) { | ||
} | ||
list[i] = $_HIDEXPR_MARK + (pcex.push(expr.trim()) - 1) + _bp[1] | ||
list[i] = '\u0001' + (pcex.push(expr.trim()) - 1) + _bp[1] | ||
} | ||
@@ -177,3 +168,3 @@ html = list.join('') | ||
html = html | ||
.replace($_HIDEXPR_REPL, function (_, d) { | ||
.replace(/\u0001(\d+)/g, function (_, d) { | ||
return _bp[0] + pcex[d].replace(/"/g, '"') | ||
@@ -311,3 +302,3 @@ }) | ||
return parser(js, opts).replace(TRIM_TRAIL, '') | ||
return parser(js).replace(TRIM_TRAIL, '') | ||
} | ||
@@ -442,25 +433,23 @@ | ||
if (len && str[len - 1] !== '>') { | ||
k = str.indexOf('<') | ||
if (k < 0 || (i = str.lastIndexOf('>\n')) < 0 || k > i) | ||
return ['', str] | ||
k = str.indexOf('<') | ||
if (k < 0 || (i = str.lastIndexOf('>\n')) < 0 || k > i) | ||
return ['', str] | ||
// we have html and js code, maybe | ||
i += 2 | ||
js = str.slice(i) // js code | ||
str = str.slice(0, i) // likely html | ||
if (str[i - 3] !== '/') { | ||
// not ending with `/>`, so go slow to re-check | ||
if (str.match(END_TAGS)) { | ||
var s = RegExp.rightContext | ||
if (s) { | ||
js = s + js // code before last tag | ||
str = str.slice(0, len - js.length) | ||
} | ||
// we have html and js code, maybe | ||
i += 2 | ||
js = str.slice(i) // js code | ||
str = str.slice(0, i) // likely html | ||
if (str[i - 3] !== '/') { | ||
// not ending with `/>`, so go slow to re-check | ||
if (str.match(END_TAGS)) { | ||
var s = RegExp.rightContext | ||
if (s) { | ||
js = s + js // code before last tag | ||
str = str.slice(0, len - js.length) | ||
} | ||
else { // no html, we catch something | ||
js = str + js // like `v < 0 && v >\n x` | ||
str = '' | ||
} | ||
} | ||
else { // no html, we catch something | ||
js = str + js // like `v < 0 && v >\n x` | ||
str = '' | ||
} | ||
} | ||
@@ -480,6 +469,12 @@ return [str, js] | ||
// CUST_TAG regex don't allow unquoted expressions containing the `>` operator. | ||
// STYLE and SCRIPT disallows the operator `>` at all. | ||
/* | ||
CUST_TAG regex don't allow unquoted expressions containing the `>` operator. | ||
STYLE and SCRIPT disallows the operator `>` at all. | ||
The beta.4 CUST_TAG regex is fast, with RegexBuddy I get 76 steps and 14 backtracks on | ||
the test/specs/fixtures/treeview.tag :) but fails with nested tags of the same name :( | ||
With a greedy * operator, we have ~500 and 200bt, it is acceptable. So let's fix this. | ||
*/ | ||
var | ||
CUST_TAG = /^[ \t]*<([-\w]+)\s*([^'"\/>]*(?:(?:\/[^>]|"[^"]*"|'[^']*')[^'"\/>]*)*)(?:\/|>\n?([^<]*(?:<(?!\/\1\s*>[ \t]*$)[^<]*)*)<\/\1\s*)>[ \t]*$/gim, | ||
CUST_TAG = /^<([-\w]+)(?:\s+([^'"\/>]+(?:(?:"[^"]*"|'[^']*'|\/[^>])[^'"\/>]*)*)|\s*)?(?:\/>|>[ \t]*\n?([\s\S]*)^<\/\1\s*>|>(.*)<\/\1\s*>)/gim, | ||
STYLE = /<style(\s+[^>]*)?>\n?([^<]*(?:<(?!\/style\s*>)[^<]*)*)<\/style\s*>/gi, | ||
@@ -493,3 +488,4 @@ SCRIPT = _regEx(STYLE.source.replace(/tyle/g, 'cript'), 'gi') | ||
* external element sharing the starting and ending lines of the tag (HTML comments | ||
* inclusive). Custom tags in HTML files don't have this restriction. | ||
* inclusive) and should not be indented. | ||
* Custom tags in HTML files don't have this restriction. | ||
* | ||
@@ -502,2 +498,3 @@ * @param {string} src - String with zero or more custom riot tags. | ||
function compile(src, opts, url) { | ||
var label | ||
@@ -513,9 +510,12 @@ if (!opts) opts = {} | ||
url = url ? | ||
'//src: ' + (/:\/\//.test(url) ? url : path.relative('.', url)) + '\n' : '' | ||
//#if NODE | ||
label = url ? '//src: ' + path.relative('.', url) + '\n' : '' | ||
//#else | ||
label = url ? '//src: ' + url + '\n' : '' | ||
//#endif | ||
// normalize eols and start processing the tags | ||
return url + src | ||
return label + src | ||
.replace(/\r\n?/g, '\n') | ||
.replace(CUST_TAG, function (_, tagName, attribs, body) { | ||
.replace(CUST_TAG, function (_, tagName, attribs, body, body2) { | ||
@@ -536,30 +536,35 @@ // content can have attributes first, then html markup with zero or more script or | ||
if (body2) body = body2 | ||
// remove comments and trim trailing whitespace | ||
body = body && body.replace(HTML_COMMENT, '') | ||
if (body) { | ||
if (body && (body = body.replace(HTML_COMMENT, '')) && /\S/.test(body)) { | ||
// get and process the style blocks | ||
body = body.replace(STYLE, function (_, _attrs, _style) { | ||
var scoped = _attrs && /\sscoped(\s|=|$)/i.test(_attrs) | ||
styles += (styles ? ' ' : '') + | ||
compileCSS(_style, tagName, getType(_attrs), scoped) | ||
return '' | ||
}) | ||
if (body2) | ||
html = compileHTML(body2, opts, pcex, 1) | ||
else { | ||
// get and process the style blocks | ||
body = body.replace(STYLE, function (_, _attrs, _style) { | ||
var scoped = _attrs && /\sscoped(\s|=|$)/i.test(_attrs) | ||
styles += (styles ? ' ' : '') + | ||
compileCSS(_style, tagName, getType(_attrs), scoped) | ||
return '' | ||
}) | ||
// now the script blocks | ||
body = body.replace(SCRIPT, function (_, _attrs, _script) { | ||
jscode += (jscode ? '\n' : '') + getCode(_script, opts, _attrs) | ||
return '' | ||
}) | ||
// now the script blocks | ||
body = body.replace(SCRIPT, function (_, _attrs, _script) { | ||
jscode += (jscode ? '\n' : '') + getCode(_script, opts, _attrs) | ||
return '' | ||
}) | ||
// separate the untagged javascript block from the html markup | ||
var blocks = splitBlocks(body.replace(TRIM_TRAIL, '')) | ||
// separate the untagged javascript block from the html markup | ||
var blocks = splitBlocks(body.replace(TRIM_TRAIL, '')) | ||
body = blocks[0] | ||
if (body) | ||
html = compileHTML(body, opts, pcex, 1) | ||
body = blocks[0] | ||
if (body) | ||
html = compileHTML(body, opts, pcex, 1) | ||
body = blocks[1] | ||
if (body && /\S/.test(body)) | ||
jscode += (jscode ? '\n' : '') + compileJS(body, opts) | ||
body = blocks[1] | ||
if (/\S/.test(body)) | ||
jscode += (jscode ? '\n' : '') + compileJS(body, opts) | ||
} | ||
} | ||
@@ -573,3 +578,5 @@ | ||
//#if RIOT | ||
return compile | ||
})() | ||
//#endif |
//#if NODE | ||
//#undef RIOT | ||
/* riot-compiler 2.3.0-beta.3, @license MIT, (c) 2015 Muut Inc. + contributors */ | ||
/* riot-compiler 2.3.0-beta.5, @license MIT, (c) 2015 Muut Inc. + contributors */ | ||
;(function (root, factory) { | ||
@@ -20,4 +20,2 @@ | ||
var brackets = _tmpl.brackets | ||
//#else | ||
@@ -28,18 +26,16 @@ //#define RIOT | ||
* Compiler for riot custom tags | ||
* @version 2.3.0-beta.3 | ||
* @version 2.3.0-beta.5 | ||
*/ | ||
//#endif | ||
//#include_once parsers | ||
//#if NODE | ||
//#indent 0 | ||
//#endif | ||
//#include_once core | ||
//#if NODE | ||
//#if RIOT | ||
//#include_once browser | ||
//#else | ||
return { | ||
@@ -46,0 +42,0 @@ compile: compile, |
@@ -5,32 +5,32 @@ /** | ||
var parsers = (function () { | ||
//#if RIOT | ||
'use strict' //eslint-disable-line | ||
//#endif | ||
var _mods = {} // cache of modules | ||
// cache for the names of modules | ||
var _mods = {} | ||
/* | ||
Search a instance for a parser. | ||
If found, saves the function in _mods before return it to caller. | ||
Returns null if not found. | ||
*/ | ||
//#if NODE | ||
function _try(name, req) { | ||
function _try(name) { | ||
if (!(name in _mods)) { | ||
function fn(r) { | ||
try { | ||
_mods[name] = require.resolve(name) | ||
_mods[name] = require(r) | ||
} | ||
catch (e) { | ||
_mods[name] = '' | ||
_mods[name] = null | ||
} | ||
return _mods[name] | ||
} | ||
return _mods[name] | ||
} | ||
function _get(req) { | ||
switch (req) { | ||
switch (name) { | ||
case 'es6': | ||
// istanbul ignore next: we have babel-core in test | ||
case 'babel': | ||
// istanbul ignore next: not both | ||
return _try('babel-core') || _try('babel') | ||
return fn('babel-core') || fn('babel') | ||
case 'none': | ||
case 'javascript': | ||
return 'none' | ||
return _js.none | ||
case 'typescript': | ||
req += '-simple' | ||
req = name + '-simple' | ||
break | ||
@@ -42,15 +42,33 @@ case 'coffee': | ||
default: | ||
if (!req) req = name | ||
break | ||
} | ||
return _try(req) | ||
return fn(req) | ||
} | ||
//#else | ||
function _try(name, req) { //eslint-disable-line no-redeclare | ||
// we can add error handling here: 'Please install your super tool' | ||
function _req(name) { | ||
var req = _get(name) | ||
return req ? require(req) : null // allow test & require (nib) | ||
switch (name) { | ||
case 'coffee': | ||
req = 'CoffeeScript' | ||
break | ||
case 'es6': | ||
req = 'babel' | ||
break | ||
default: | ||
if (!req) req = name | ||
break | ||
} | ||
return _mods[name] = window[req] | ||
} | ||
//#endif | ||
// ## The parsers object | ||
// Returns a parser instance, null if the parser is not found. | ||
// Public through the parsers._get function. | ||
function _req(name, req) { | ||
return name in _mods ? _mods[name] : _try(name, req) | ||
} | ||
//// The parsers object -- | ||
var _html = { | ||
@@ -65,5 +83,4 @@ jade: function (html) { | ||
var | ||
stylus = _req('stylus'), | ||
nib = _req('nib') // optional nib support | ||
// istanbul ignore next: not both | ||
stylus = _req('stylus'), nib = _req('nib') // optional nib support | ||
/* istanbul ignore next: can't run both */ | ||
return nib ? | ||
@@ -78,11 +95,8 @@ stylus(css).use(nib()).import('nib').render() : stylus.render(css) | ||
}, | ||
livescript: function (js) { | ||
return _req('livescript').compile(js, {bare: true, header: false}) | ||
}, | ||
typescript: function (js) { | ||
return _req('typescript')(js).replace(/\r\n?/g, '\n') | ||
}, | ||
es6: function (js) { | ||
@@ -93,3 +107,2 @@ return _req('es6').transform(js, { | ||
}, | ||
coffee: function (js) { | ||
@@ -100,7 +113,12 @@ return _req('coffee').compile(js, {bare: true}) | ||
_js.babel = _js.es6 | ||
_js.javascript = _js.none | ||
_js.coffeescript = _js.coffee // 4 the nostalgics | ||
return {html: _html, css: _css, js: _js, _get: _get} | ||
return {html: _html, css: _css, js: _js, _req: _req} | ||
})() | ||
//#if RIOT | ||
riot.parsers = parsers | ||
//#endif |
{ | ||
"name": "riot-compiler", | ||
"version": "2.3.0-beta.4", | ||
"version": "2.3.0-beta.5", | ||
"description": "Compiler for riot .tag files", | ||
@@ -31,10 +31,10 @@ "main": "dist/compiler.js", | ||
"dependencies": { | ||
"riot-tmpl": "2.3.0-beta.4" | ||
"riot-tmpl": "^2.3.0-beta.8" | ||
}, | ||
"devDependencies": { | ||
"coveralls": "^2.11.4", | ||
"eslint": "^1.7.2", | ||
"eslint": "^1.7.3", | ||
"expect.js": "^0.3.1", | ||
"istanbul": "^0.4.0", | ||
"jspreproc": "^0.2.3", | ||
"jspreproc": "^0.2.4", | ||
"mocha": "^2.3.3" | ||
@@ -41,0 +41,0 @@ }, |
@@ -17,19 +17,4 @@ /* | ||
basedir = path.join(__dirname, 'specs', 'fixtures'), | ||
tags = ['box', 'input-last', 'mixed-js', 'same', 'scoped', 'timetable'] | ||
var | ||
data = { num: 1, str: 'string', date: new Date(), bool: true, item: null }, | ||
exprList = [ | ||
['{ date }', data.date], | ||
['{ num === 0 ? 0 : num }', data.num], | ||
['<p>{str}</p>', '<p>string</p>'], | ||
[' "{ str.slice(0, 3).replace(/t/, \'T\') }" ', ' "sTr" '], | ||
['{this.num}', 1], | ||
['{ !bool }', false], | ||
['{}', undefined] | ||
], | ||
csList = [ | ||
['{ foo: num }', 'foo'], | ||
['{ foo: num, bar: item }', 'foo'], | ||
['{ foo: date.getFullYear() > 2000, bar: str==this.str }', 'foo bar'] | ||
] | ||
tags = ['box', 'empty', 'input-last', 'mixed-js', 'same', 'scoped', 'timetable', 'treeview', 'oneline'], | ||
data = { num: 1, str: 'string', date: new Date(), bool: true, item: null } | ||
@@ -36,0 +21,0 @@ var files = tags.map(function (f) { |
@@ -1,2 +0,2 @@ | ||
riot.tag2('root-attribs', '', '', 'disable="disable" style="display:none" id="{_id}"', function(opts) { | ||
riot.tag2('root-attribs', '', '', 'disabled="disabled" style="display:none" id="{_id}"', function(opts) { | ||
}, '{ }'); |
//THIS IS A LINE COMMENT | ||
click (e) { | ||
alert('Hello!') | ||
/* COMMENT */ alert('Hello!') //COMMENT } | ||
} | ||
@@ -11,4 +11,7 @@ | ||
* COMMENT */ | ||
change (e) { | ||
change (e)/* COMMENT */{ | ||
alert('Hello!') //ANOTHER LINE COMMENT | ||
} | ||
/*COMMENT | ||
click (e) {} | ||
*/ |
// alternative to nested custom tags using the comment hack. | ||
// as the compiler expects only blanks after closing the tag, the inline | ||
// comment following the first closing tag prevents the compiler sees it. | ||
// UPDATE: hack NOT NECESSARY with the 0 indent restriction. | ||
riot.tag2('treeitem', '<div class="{bold: isFolder()}" onclick="{toggle}" ondblclick="{changeType}"> {name} <span if="{isFolder()}">[{open ? \'-\' : \'+\'}]</span> </div> <ul if="{isFolder()}" show="{isFolder() && open}"> <li each="{child, i in nodes}"> <treeitem data="{child}"></treeitem> </li> <li onclick="{addChild}">+</li> </ul>', '', '', function(opts) { | ||
var self = this | ||
}, '{ }'); |
riot.tag2('treeitems', '<treeitem> <div class="{bold: isFolder()}" onclick="{toggle}" ondblclick="{changeType}"> {name} <span if="{isFolder()}">[{open ? \'-\' : \'+\'}]</span> </div> <ul if="{isFolder()}" show="{isFolder() && open}"> <li each="{child, i in nodes}"> <treeitem data="{child}"></treeitem> </li> <li onclick="{addChild}">+</li> </ul> </treeitem>', '', '', function(opts) { | ||
var self = this | ||
var self = this | ||
}, '{ }'); |
@@ -12,6 +12,6 @@ // | ||
function have(mod) { | ||
if (compiler.parsers._get(mod)) | ||
function have(mod, req) { | ||
if (compiler.parsers._req(mod, req)) | ||
return true | ||
console.error('\tnot installed locally: ' + mod) | ||
console.error('\tnot installed locally: ' + (req || mod) + ' alias "' + mod + '"') | ||
return false | ||
@@ -44,3 +44,3 @@ } | ||
this.timeout(5000) | ||
this.timeout(10000) | ||
@@ -53,3 +53,3 @@ function testStr(str, resStr, opts) { | ||
it('jade', function () { | ||
if (have('jade')) { | ||
if (have('jade') && have('coffee')) { | ||
testParser('test.jade', { template: 'jade' }) | ||
@@ -98,3 +98,3 @@ testParser('slide.jade', { template: 'jade' }) | ||
this.timeout(8000) | ||
this.timeout(10000) | ||
@@ -128,3 +128,3 @@ // complex.tag | ||
it('coffeescript', function () { | ||
if (have('coffee-script')) { | ||
if (have('coffee')) { | ||
testParser('test', { type: 'coffee', expr: true }) | ||
@@ -143,3 +143,3 @@ } | ||
it('typescript', function () { | ||
if (have('typescript-simple')) { | ||
if (have('typescript')) { | ||
testParser('test', { type: 'typescript' }) | ||
@@ -151,3 +151,3 @@ } | ||
it('es6 (babel-core or babel)', function () { | ||
if (have('babel')) { | ||
if (have('es6')) { | ||
testParser('test', { type: 'es6' }) | ||
@@ -169,6 +169,6 @@ } | ||
this.timeout(5000) | ||
this.timeout(10000) | ||
function _sass(tag, css) { | ||
return '' + require('node-sass').renderSync({ | ||
return '' + compiler.parsers._req('sass').renderSync({ | ||
data: css, | ||
@@ -199,3 +199,3 @@ indentedSyntax: true, | ||
it('sass, indented 2, margin 0 (custom parser)', function () { | ||
if (have('node-sass')) { | ||
if (have('sass', 'node-sass')) { | ||
compiler.parsers.css.sass = _sass | ||
@@ -202,0 +202,0 @@ testParser('sass', {}) |
@@ -62,3 +62,3 @@ describe('Compile tags', function() { | ||
it('detect some fake closing html tags', function () { | ||
it('Detect some fake closing html tags', function () { | ||
testFile('html-block1') | ||
@@ -68,2 +68,6 @@ testFile('html-block2') | ||
it('The treeview question', function () { | ||
testFile('treeview') | ||
}) | ||
/* | ||
@@ -75,7 +79,11 @@ it('Include files (v2.3)', function() { | ||
it('dealing with unclosed es6 methods', function () { | ||
it('Dealing with unclosed es6 methods', function () { | ||
testFile('unclosed-es6') | ||
}) | ||
it('with attributes in the root', function () { | ||
it('Compatibility with one line tags', function () { | ||
testFile('oneline') | ||
}) | ||
it('With attributes in the root', function () { | ||
var | ||
@@ -87,14 +95,11 @@ src = cat('fixtures', 'root-attribs.tag'), | ||
it('do not change internet urls', function () { | ||
var | ||
js = compiler.compile('<url/>', {}, 'http://github.com'), | ||
str = [ | ||
'//src: http://github.com', | ||
"riot.tag2('url', '', '', '', function(opts) {", | ||
'});' | ||
].join('\n') | ||
it('Empty tag', function () { | ||
testFile('empty') | ||
}) | ||
expect(js).to.equal(str) | ||
it('The url name is optional', function () { | ||
var js = compiler.compile('<url/>', {}) | ||
expect(js).to.equal("riot.tag2('url', '', '', '', function(opts) {\n});") | ||
}) | ||
}) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
107369
98
7
0
2608
+ Addedriot-tmpl@2.4.2(transitive)
- Removedriot-tmpl@2.3.0-beta.4(transitive)
Updatedriot-tmpl@^2.3.0-beta.8