diff --git a/CHANGELOG.md b/CHANGELOG.md index fea58d8..9d56354 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,10 @@ # riot-tmpl Changes ### v2.3.21 -- Refactorization of `brackets`, now is ~8% faster. +- Refactorization, now `tmpl` and `brackets` are ~5% faster. - Removed unused `tmpl.isRaw` function (internal). - Changes to comments. +- Files to preprocess are moved from the "lib" to the "src" directory, "lib" was removed. ### v2.3.20 - Fixed lint issues with new .eslintrc.yml, almost compatible with [JavaScript Standard Style](http://standardjs.com/) diff --git a/Makefile b/Makefile index 0617ed3..a12c10f 100644 --- a/Makefile +++ b/Makefile @@ -22,13 +22,13 @@ test: build test-mocha test-karma build: eslint # rebuild all @ mkdir -p $(DIST) - @ $(JSPP) $(JSPP_RIOT_FLAGS) lib/index.js > $(DIST)riot.tmpl.js - @ $(JSPP) $(JSPP_ES6_FLAGS) lib/index.js > $(DIST)es6.tmpl.js - @ $(JSPP) $(JSPP_NODE_FLAGS) lib/index.js > $(DIST)tmpl.js + @ $(JSPP) $(JSPP_RIOT_FLAGS) src/index.js > $(DIST)riot.tmpl.js + @ $(JSPP) $(JSPP_ES6_FLAGS) src/index.js > $(DIST)es6.tmpl.js + @ $(JSPP) $(JSPP_NODE_FLAGS) src/index.js > $(DIST)tmpl.js eslint: # check code style - @ $(ESLINT) -c ./.eslintrc.yml lib + @ $(ESLINT) -c ./.eslintrc.yml src test-karma: @ $(KARMA) start test/karma.conf.js diff --git a/dist/es6.tmpl.js b/dist/es6.tmpl.js index 8a56ded..e5d4bee 100644 --- a/dist/es6.tmpl.js +++ b/dist/es6.tmpl.js @@ -75,7 +75,7 @@ var brackets = (function (UNDEF) { arr = arr.concat(pair.replace(/(?=[[\]()*+?.^$|])/g, '\\').split(' ')) arr[4] = _rewrite(arr[1].length > 1 ? /{[\S\s]*?}/ : _pairs[4], arr) - arr[5] = _rewrite(/\\({|})/g, arr) + arr[5] = _rewrite(pair.length > 3 ? /\\({|})/g : _pairs[5], arr) arr[6] = _rewrite(_pairs[6], arr) arr[7] = RegExp('\\\\(' + arr[3] + ')|([[({])|(' + arr[3] + ')|' + S_QBLOCKS, REGLOB) arr[8] = pair @@ -107,7 +107,7 @@ var brackets = (function (UNDEF) { if (isexpr) { if (match[2]) { - re.lastIndex = skipBraces(match[2], re.lastIndex) + re.lastIndex = skipBraces(str, match[2], re.lastIndex) continue } if (!match[3]) @@ -128,25 +128,25 @@ var brackets = (function (UNDEF) { return parts - function unescapeStr (str) { + function unescapeStr (s) { if (tmpl || isexpr) - parts.push(str && str.replace(_bp[5], '$1')) + parts.push(s && s.replace(_bp[5], '$1')) else - parts.push(str) + parts.push(s) } - function skipBraces (ch, pos) { + function skipBraces (s, ch, ix) { var match, recch = FINDBRACES[ch] - recch.lastIndex = pos - pos = 1 - while (match = recch.exec(str)) { + recch.lastIndex = ix + ix = 1 + while (match = recch.exec(s)) { if (match[1] && - !(match[1] === ch ? ++pos : --pos)) break + !(match[1] === ch ? ++ix : --ix)) break } - return pos ? str.length : recch.lastIndex + return ix ? s.length : recch.lastIndex } } @@ -166,7 +166,7 @@ var brackets = (function (UNDEF) { } _brackets.array = function array (pair) { - return pair ? _create(pair) : _pairs + return pair ? _create(pair) : _cache } function _reset (pair) { @@ -197,7 +197,7 @@ var brackets = (function (UNDEF) { get: function () { return _settings } }) - /* istanbul ignore next: in the node version riot is not in the scope */ + /* istanbul ignore next: in the browser riot is always in the scope */ _brackets.settings = typeof riot !== 'undefined' && riot.settings || {} _brackets.set = _reset diff --git a/dist/riot.tmpl.js b/dist/riot.tmpl.js index b0ab331..897016d 100644 --- a/dist/riot.tmpl.js +++ b/dist/riot.tmpl.js @@ -72,7 +72,7 @@ var brackets = (function (UNDEF) { arr = arr.concat(pair.replace(/(?=[[\]()*+?.^$|])/g, '\\').split(' ')) arr[4] = _rewrite(arr[1].length > 1 ? /{[\S\s]*?}/ : _pairs[4], arr) - arr[5] = _rewrite(/\\({|})/g, arr) + arr[5] = _rewrite(pair.length > 3 ? /\\({|})/g : _pairs[5], arr) arr[6] = _rewrite(_pairs[6], arr) arr[7] = RegExp('\\\\(' + arr[3] + ')|([[({])|(' + arr[3] + ')|' + S_QBLOCKS, REGLOB) arr[8] = pair @@ -104,7 +104,7 @@ var brackets = (function (UNDEF) { if (isexpr) { if (match[2]) { - re.lastIndex = skipBraces(match[2], re.lastIndex) + re.lastIndex = skipBraces(str, match[2], re.lastIndex) continue } if (!match[3]) @@ -125,25 +125,25 @@ var brackets = (function (UNDEF) { return parts - function unescapeStr (str) { + function unescapeStr (s) { if (tmpl || isexpr) - parts.push(str && str.replace(_bp[5], '$1')) + parts.push(s && s.replace(_bp[5], '$1')) else - parts.push(str) + parts.push(s) } - function skipBraces (ch, pos) { + function skipBraces (s, ch, ix) { var match, recch = FINDBRACES[ch] - recch.lastIndex = pos - pos = 1 - while (match = recch.exec(str)) { + recch.lastIndex = ix + ix = 1 + while (match = recch.exec(s)) { if (match[1] && - !(match[1] === ch ? ++pos : --pos)) break + !(match[1] === ch ? ++ix : --ix)) break } - return pos ? str.length : recch.lastIndex + return ix ? s.length : recch.lastIndex } } @@ -163,7 +163,7 @@ var brackets = (function (UNDEF) { } _brackets.array = function array (pair) { - return pair ? _create(pair) : _pairs + return pair ? _create(pair) : _cache } function _reset (pair) { @@ -194,7 +194,7 @@ var brackets = (function (UNDEF) { get: function () { return _settings } }) - /* istanbul ignore next: in the node version riot is not in the scope */ + /* istanbul ignore next: in the browser riot is always in the scope */ _brackets.settings = typeof riot !== 'undefined' && riot.settings || {} _brackets.set = _reset diff --git a/dist/tmpl.js b/dist/tmpl.js index a4d8bf5..527178c 100644 --- a/dist/tmpl.js +++ b/dist/tmpl.js @@ -71,7 +71,7 @@ arr = arr.concat(pair.replace(/(?=[[\]()*+?.^$|])/g, '\\').split(' ')) arr[4] = _rewrite(arr[1].length > 1 ? /{[\S\s]*?}/ : _pairs[4], arr) - arr[5] = _rewrite(/\\({|})/g, arr) + arr[5] = _rewrite(pair.length > 3 ? /\\({|})/g : _pairs[5], arr) arr[6] = _rewrite(_pairs[6], arr) arr[7] = RegExp('\\\\(' + arr[3] + ')|([[({])|(' + arr[3] + ')|' + S_QBLOCKS, REGLOB) arr[8] = pair @@ -103,7 +103,7 @@ if (isexpr) { if (match[2]) { - re.lastIndex = skipBraces(match[2], re.lastIndex) + re.lastIndex = skipBraces(str, match[2], re.lastIndex) continue } if (!match[3]) @@ -124,25 +124,25 @@ return parts - function unescapeStr (str) { + function unescapeStr (s) { if (tmpl || isexpr) - parts.push(str && str.replace(_bp[5], '$1')) + parts.push(s && s.replace(_bp[5], '$1')) else - parts.push(str) + parts.push(s) } - function skipBraces (ch, pos) { + function skipBraces (s, ch, ix) { var match, recch = FINDBRACES[ch] - recch.lastIndex = pos - pos = 1 - while (match = recch.exec(str)) { + recch.lastIndex = ix + ix = 1 + while (match = recch.exec(s)) { if (match[1] && - !(match[1] === ch ? ++pos : --pos)) break + !(match[1] === ch ? ++ix : --ix)) break } - return pos ? str.length : recch.lastIndex + return ix ? s.length : recch.lastIndex } } @@ -162,7 +162,7 @@ } _brackets.array = function array (pair) { - return pair ? _create(pair) : _pairs + return pair ? _create(pair) : _cache } function _reset (pair) { @@ -193,7 +193,7 @@ get: function () { return _settings } }) - /* istanbul ignore next: in the node version riot is not in the scope */ + /* istanbul ignore next: in the browser riot is always in the scope */ _brackets.settings = typeof riot !== 'undefined' && riot.settings || {} _brackets.set = _reset diff --git a/package.json b/package.json index 7b9fc24..618f10d 100644 --- a/package.json +++ b/package.json @@ -5,11 +5,10 @@ "main": "dist/tmpl.js", "jsnext:main": "dist/es6.tmpl.js", "directories": { - "lib": "lib", "doc": "doc" }, "files": [ - "lib", + "src", "doc", "dist/*.js", "test/**" @@ -29,18 +28,18 @@ "engine" ], "devDependencies": { - "coveralls": "^2.11.4", + "coveralls": "^2.11.6", "eslint": "^1.10.3", "expect.js": "^0.3.1", - "istanbul": "^0.4.1", + "istanbul": "^0.4.2", "jspreproc": "^0.2.7", - "karma": "^0.13.15", + "karma": "^0.13.19", "karma-browserstack-launcher": "^0.1.6", "karma-coverage": "^0.5.3", "karma-mocha": "^0.2.1", - "karma-phantomjs-launcher": "^0.2.1", - "mocha": "^2.3.4", - "phantomjs": "^1.9.19", + "karma-phantomjs-launcher": "^0.2.3", + "mocha": "^2.4.4", + "phantomjs": "^2.1.2", "riot-bump": "^1.0.0" }, "author": "Muut, Inc. and other contributors", diff --git a/lib/brackets.js b/src/brackets.js similarity index 97% rename from lib/brackets.js rename to src/brackets.js index 21a3c20..5efe686 100644 --- a/lib/brackets.js +++ b/src/brackets.js @@ -167,7 +167,7 @@ var brackets = (function (UNDEF) { arr = arr.concat(pair.replace(/(?=[[\]()*+?.^$|])/g, '\\').split(' ')) arr[$_RIX_TEST] = _rewrite(arr[1].length > 1 ? /{[\S\s]*?}/ : _pairs[$_RIX_TEST], arr) - arr[$_RIX_ESC] = _rewrite(/\\({|})/g, arr) + arr[$_RIX_ESC] = _rewrite(pair.length > 3 ? /\\({|})/g : _pairs[$_RIX_ESC], arr) arr[$_RIX_OPEN] = _rewrite(_pairs[$_RIX_OPEN], arr) // for _split() arr[$_RIX_CLOSE] = RegExp('\\\\(' + arr[3] + ')|([[({])|(' + arr[3] + ')|' + S_QBLOCKS, REGLOB) arr[$_RIX_PAIR] = pair @@ -314,6 +314,8 @@ var brackets = (function (UNDEF) { /** * Returns an array with brackets information, defaults to the current brackets. + * (the `brackets` module in the node version of the compiler allways defaults + * to the predefined riot brackets `{ }`). * * _This function is for internal use._ * @param {string} [pair] - If used, returns info for this brackets @@ -321,7 +323,7 @@ var brackets = (function (UNDEF) { * @private */ _brackets.array = function array (pair) { - return pair ? _create(pair) : _pairs + return pair ? _create(pair) : _cache } /** @@ -366,7 +368,7 @@ var brackets = (function (UNDEF) { get: function () { return _settings } }) - /* istanbul ignore next: in the node version riot is not in the scope */ + /* istanbul ignore next: in the browser riot is always in the scope */ _brackets.settings = typeof riot !== 'undefined' && riot.settings || {} _brackets.set = _reset diff --git a/lib/index.js b/src/index.js similarity index 100% rename from lib/index.js rename to src/index.js diff --git a/lib/tmpl.js b/src/tmpl.js similarity index 83% rename from lib/tmpl.js rename to src/tmpl.js index 937d23d..db0f845 100644 --- a/lib/tmpl.js +++ b/src/tmpl.js @@ -58,10 +58,11 @@ var tmpl = (function () { } /** - * Checks if the expression or template is marked for output raw HTML text. + * Checks if the expression or template is marked for to output raw HTML text. * * @param {string } expr - Expression to search * @returns {boolean} `true` if the expression is for raw html. + * @function */ _tmpl.haveRaw = brackets.hasRaw @@ -75,24 +76,30 @@ var tmpl = (function () { _tmpl.hasExpr = brackets.hasExpr /** - * Parse the `each` expression to detect how to map the collection data to the + * Parses the `each` expression to detect how to map the collection data to the * children tags. Used by riot browser/tag/each.js * * {key, i in items} -> { key, pos, val } * * @param {String} expr - string passed in the 'each' attribute - * @returns {Object} object needed to check how the items in the collection + * @returns {Object} The object needed to check how the items in the collection * should be mapped to the children tags. * @function */ _tmpl.loopKeys = brackets.loopKeys /** - * Function to handle errors in the evaluation of expressions. + * Holds a custom function to handle evaluation errors. + * + * This property allows to detect errors _in the evaluation_, by setting its value to a + * function that receives the generated Error object, augmented with an object `riotData` + * containing the properties `tagName` and `_riot_id` of the context at error time. + * + * Other (usually fatal) errors, such as "Parse Error" generated by the Function + * constructor, are not intercepted. * - * You can set errorHandler to one function that receives the error object - * generated, with an added "riotData" property, an object containing the - * tagName and `_riot_id` in the context at the error time. + * If this property is not set, or set to falsy, as in previous versions the error + * is silently ignored. * * @type {function} * @static @@ -104,6 +111,7 @@ var tmpl = (function () { * * @param {Error} err - The Error instance generated by the exception * @param {object} ctx - The context + * @private */ function _logErr (err, ctx) { @@ -120,8 +128,11 @@ var tmpl = (function () { /** * Creates a function instance to get a value from the received template string. * + * It'll halt the app if the expression has errors (Parse Error or SyntaxError). + * * @param {string} str - The template. Can include zero or more expressions - * @returns {Function} - An instance of Function with the compiled template. + * @returns {Function} An instance of Function with the compiled template. + * @private */ function _create (str) { @@ -136,9 +147,7 @@ var tmpl = (function () { //#endif // Now, we can create the function to return by calling the Function constructor. - // It'll halt the app if the expression has errors (Parse Error or SyntaxError). // The parameter `E` is the error handler for runtime only. - return new Function('E', expr + ';') } @@ -157,6 +166,7 @@ var tmpl = (function () { * * @param {string} str - Raw template string, without comments * @returns {string} Processed template, ready for evaluation. + * @private */ function _getTmpl (str) { var @@ -205,20 +215,6 @@ var tmpl = (function () { return expr } - // For shorthand names, riot supports a limited subset of the full w3c/html specs - // for non-quoted identifiers (closer to CSS1 that CSS2). - // This is the regex used for recognition: - // - // `-?[_A-Za-z\xA0-\xFF][-\w\xA0-\xFF]*` - // - // The regex accepts almost all ISO-8859-1 alphanumeric characters within an html - // identifier. Doesn't works with escaped codepoints. - // You can use Unicode code points beyond `\u00FF` by quoting the names (not recommended). - // - // See:
- // http://www.w3.org/TR/CSS21/grammar.html#scanner
- // http://www.w3.org/TR/CSS21/syndata.html#tokenization - var RE_BREND = { '(': /[()]/g, @@ -230,10 +226,21 @@ var tmpl = (function () { /** * Parses an individual expression `{expression}` or shorthand `{name: expression, ...}` * + * For shorthand names, riot supports a limited subset of the full w3c/html specs of + * non-quoted identifiers (closer to CSS1 that CSS2). + * + * The regex used for recognition is `-?[_A-Za-z\xA0-\xFF][-\w\xA0-\xFF]*`. + * + * This regex accepts almost all ISO-8859-1 alphanumeric characters within an html + * identifier. Doesn't works with escaped codepoints, but you can use Unicode code points + * beyond `\u00FF` by quoting the names (not recommended). + * * @param {string} expr - The expression, without brackets * @param {number} asText - 0: raw value, 1: falsy as "", except 0 * @param {Array} qstr - Where to store hidden quoted strings and regexes * @returns {string} Code to evaluate the expression. + * @see {@link http://www.w3.org/TR/CSS21/grammar.html#scanner} + * {@link http://www.w3.org/TR/CSS21/syndata.html#tokenization} * @private */ function _parseExpr (expr, asText, qstr) { @@ -319,7 +326,21 @@ var tmpl = (function () { JS_VARNAME = /[,{][$\w]+:|(^ *|[^$\w\.])(?!(?:typeof|true|false|null|undefined|in|instanceof|is(?:Finite|NaN)|void|NaN|new|Date|RegExp|Math)(?![$\w]))([$_A-Za-z][$\w]*)/g, JS_NOPROPS = /^(?=(\.[$\w]+))\1(?:[^.[(]|$)/ - // Generates code to evaluate an expression avoiding breaking on undefined vars. + /** + * Generates code to evaluate an expression avoiding breaking on undefined vars. + * + * This function include a try..catch block only if needed, if this block is not included, + * the generated code has no return statement. + * + * This `isFinite`, `isNaN`, `Date`, `RegExp`, and `Math` keywords are not wrapped + * for context detection (defaults to the global object). + * + * @param {string} expr - Normalized expression, without brackets + * @param {boolean} asText - If trueish, the output is converted to text, not raw values + * @param {string} [key] - For shorthands, the key name + * @returns {string} Compiled expression. + * @private + */ function _wrapExpr (expr, asText, key) { var tb