diff --git a/.babelrc b/.babelrc new file mode 100644 index 00000000..7790c037 --- /dev/null +++ b/.babelrc @@ -0,0 +1,19 @@ +{ + "presets": [ + ["@babel/env", { + "loose": true, + "targets": { + "browsers": ["last 2 versions", "safari >= 7", "ie 9"], + "node": "4" + } + }] + ], + "env": { + "test": { + "plugins": ["./scripts/lib/arrow-function-coverage-fix", "istanbul"] + } + }, + "ignore": [ + "scripts/lib/arrow-function-coverage-fix.js" + ] +} diff --git a/.eslintrc.js b/.eslintrc.js index 420575b5..badfd8cc 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,30 +1,52 @@ module.exports = { - 'extends': 'eslint:recommended', - 'parserOptions': { - 'sourceType': 'module', - 'ecmaVersion': 2017 + 'extends': [ + 'airbnb-base/legacy', + ], + 'parserOptions': { + 'sourceType': 'module', + 'ecmaVersion': 2017, }, 'env': { 'node': true, 'es6': true, - 'mocha': true, - 'browser': true }, - 'rules': { - 'indent': ['error', 2, { 'SwitchCase': 1 }], - 'quotes': ['error', 'single', { 'allowTemplateLiterals': true }], - 'semi': [2, 'always'], - 'brace-style': ['error', '1tbs'], - 'comma-style': ['error', 'last'], - 'comma-spacing': ['error', {'after': true, 'before': false}], - 'eol-last': ['error', 'always'], - 'func-call-spacing': ['error', 'never'], - 'semi-spacing': ['error', {'before': false, 'after': true}], - 'keyword-spacing': ['error', {'before': true, 'after': true}], + "rules": { + // The one assertion of personal preference: no spaces before parentheses + // of anonymous functions + 'space-before-function-paren': ['error', { + anonymous: 'never', + named: 'never', + asyncArrow: 'always', + }], + // Temporarily disabled rules + // + // no-use-before-define is a good rule, but it would make the diff for + // linting the code even more inscrutible than it already is. + 'no-use-before-define': 'off', + // Relax some rules + 'no-cond-assign': ['error', 'except-parens'], + 'no-unused-vars': ['error', { + 'args': 'none', + }], + // Disable some overly-strict airbnb style rules + 'no-underscore-dangle': 'off', + 'no-param-reassign': 'off', + 'class-methods-use-this': 'off', + 'function-paren-newline': 'off', + 'no-plusplus': 'off', + 'object-curly-spacing': 'off', + 'no-multi-assign': 'off', + 'no-else-return': 'off', + // While technically useless from the point of view of the regex parser, + // escaping characters inside character classes is more consistent. I + // would say that they make the regular expression more readable, if the + // idea of readable regular expressions wasn't absurd on its face. 'no-useless-escape': 'off', - 'no-constant-condition': 'off' + // I'm inclined to reverse this rule to be ['error', 'always'], but not just yet + // IE 8 is a thing of the past and trailing commas are useful. + 'comma-dangle': 'off', }, 'globals': { - 'nunjucks': false - } + 'nunjucks': false, + }, }; diff --git a/.gitignore b/.gitignore index b48fecbc..6d3aeead 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,13 @@ node_modules coverage .#* docs/_site -docs/files \ No newline at end of file +docs/files +/src/ +/index.js +/index.js.map +/tests/browser/nunjucks* +.nyc_output +/browser +/tests/browser/precompiled-templates.js +/samples/express/js/nunjucks.js +/samples/express/js/templates.js diff --git a/.npmignore b/.npmignore index 0edc7142..42f36aaa 100644 --- a/.npmignore +++ b/.npmignore @@ -1,5 +1,8 @@ node_modules coverage +.nyc_output docs tests bench +nunjucks +scripts diff --git a/.travis.yml b/.travis.yml index 34e25b36..1000b75c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,12 @@ language: node_js +sudo: false node_js: - - "7" + - "8" - "6" - - "5" - "4" +install: + - npm install + - npm install codecov +script: + - npm test + - npm run codecov diff --git a/CHANGELOG.md b/CHANGELOG.md index 42096cb9..3861dee2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,14 +2,19 @@ Changelog ========= -master (unreleased) +3.1.0 (Feb 19 2018) ------------------- +* Support nunjucks.installJinjaCompat() with slim build. Fixes + [#1019](https://github.com/mozilla/nunjucks/issues/1019) + * Fix calling render callback twice when a conditional import throws an error. Solves [#1029](https://github.com/mozilla/nunjucks/issues/1029) * Support objects created with Object.create(null). fixes [#468](https://github.com/mozilla/nunjucks/issues/468) +* Support ESNext iterators, using Array.from. Merge of + [#1058](https://github.com/mozilla/nunjucks/pull/1058) 3.0.1 (May 24 2017) ------------------- diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c108f82e..75bcdb55 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,7 +9,7 @@ Nunjucks has the following purpose: * Aim for templating feature parity with Jinja2. * Aim for templating feature parity with Twig, but only when not conflicting with Jinja2 parity. -* Works in Node >= v0.10 (as defined in [Travis test matrix]).(https://github.com/mozilla/nunjucks/blob/master/.travis.yml#L9). +* Works in Node LTS 4, 6, and >= 8. * Works in all modern browsers (with [ES5 support](http://kangax.github.io/compat-table/es5/)). * Works in IE8 with [es5-shim](https://github.com/es-shims/es5-shim). * Keep footprint browser files as small as possible (save on bandwidth, download time). diff --git a/appveyor.yml b/appveyor.yml index 51fddcf0..b44b1867 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,9 +5,8 @@ init: # Test against these versions of Node.js. environment: matrix: - - nodejs_version: "7" + - nodejs_version: "8" - nodejs_version: "6" - - nodejs_version: "5" - nodejs_version: "4" # Install scripts. (runs after repo cloning) @@ -16,6 +15,7 @@ install: - ps: Install-Product node $env:nodejs_version # install modules - npm install + - npm install codecov # Post-install test scripts. test_script: @@ -24,6 +24,7 @@ test_script: - npm --version # run tests - npm test + - npm run codecov # Don't actually build. build: off diff --git a/bin/bundle b/bin/bundle deleted file mode 100755 index 7f1f3d05..00000000 --- a/bin/bundle +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -ROOT=`dirname $0` - -$ROOT/bundle.js nunjucks.js -$ROOT/bundle.js -m nunjucks.min.js -$ROOT/bundle.js -s nunjucks-slim.js -$ROOT/bundle.js -m -s nunjucks-slim.min.js diff --git a/bin/bundle.js b/bin/bundle.js deleted file mode 100755 index 4556b61d..00000000 --- a/bin/bundle.js +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/env node -'use strict'; - -var path = require('path'); -var webpack = require('webpack'); -var fs = require('fs'); - -var VERSION = JSON.parse(fs.readFileSync('./package.json')).version; -var TYPE = ''; -var SLIM = false; -var MINIFIED = false; -var TARGET = ''; - -var args = process.argv.slice(2); -while (args.length > 0) { - if (args.length === 1) { - TARGET = args[0]; - } else { - switch (args[0]) { - case '-s': - SLIM = true; - TYPE = '(slim, only works with precompiled templates)'; - break; - case '-m': - MINIFIED = true; - break; - } - } - args.shift(); -} - -var config = { - entry: './index.js', - output: { - path: path.join(__dirname, '../browser'), - filename: TARGET, - library: 'nunjucks', - libraryTarget: 'umd' - }, - node: { - process: 'empty' - }, - plugins: [ - new webpack.NormalModuleReplacementPlugin(/(path|precompile)$/, - 'node-libs-browser/mock/empty'), - new webpack.BannerPlugin( - 'Browser bundle of nunjucks ' + VERSION + ' ' + TYPE - ), - new webpack.DefinePlugin({ - 'process.env': { - IS_BROWSER: true - } - }) - ] -}; - -if (SLIM) { - config.plugins.push( - new webpack.NormalModuleReplacementPlugin( - /(nodes|lexer|parser|transformer|compiler|loaders)$/, - 'node-libs-browser/mock/empty' - ) - ); -} else { - config.plugins.push( - new webpack.NormalModuleReplacementPlugin(/loaders\.js$/, - './web-loaders.js') - ); -} - -if (MINIFIED) { - config.plugins.push( - new webpack.optimize.UglifyJsPlugin({ - sourceMap: false - }) - ); -} - -var outputOptions = { - cached: false, - cachedAssets: false -}; - -webpack(config).run(function(err, stats) { - if (err) { - throw new Error(err); - } - console.log(stats.toString(outputOptions)); // eslint-disable-line no-console -}); diff --git a/browser/nunjucks-slim.js b/browser/nunjucks-slim.js deleted file mode 100644 index b72cb638..00000000 --- a/browser/nunjucks-slim.js +++ /dev/null @@ -1,3200 +0,0 @@ -/*! Browser bundle of nunjucks 3.0.1 (slim, only works with precompiled templates) */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["nunjucks"] = factory(); - else - root["nunjucks"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; - -/******/ // The require function -/******/ function __webpack_require__(moduleId) { - -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; - -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ exports: {}, -/******/ id: moduleId, -/******/ loaded: false -/******/ }; - -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); - -/******/ // Flag the module as loaded -/******/ module.loaded = true; - -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } - - -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; - -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; - -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; - -/******/ // Load entry module and return exports -/******/ return __webpack_require__(0); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var lib = __webpack_require__(1); - var env = __webpack_require__(2); - var Loader = __webpack_require__(15); - var loaders = __webpack_require__(3); - var precompile = __webpack_require__(3); - - module.exports = {}; - module.exports.Environment = env.Environment; - module.exports.Template = env.Template; - - module.exports.Loader = Loader; - module.exports.FileSystemLoader = loaders.FileSystemLoader; - module.exports.PrecompiledLoader = loaders.PrecompiledLoader; - module.exports.WebLoader = loaders.WebLoader; - - module.exports.compiler = __webpack_require__(3); - module.exports.parser = __webpack_require__(3); - module.exports.lexer = __webpack_require__(3); - module.exports.runtime = __webpack_require__(8); - module.exports.lib = lib; - module.exports.nodes = __webpack_require__(3); - - module.exports.installJinjaCompat = __webpack_require__(16); - - // A single instance of an environment, since this is so commonly used - - var e; - module.exports.configure = function(templatesPath, opts) { - opts = opts || {}; - if(lib.isObject(templatesPath)) { - opts = templatesPath; - templatesPath = null; - } - - var TemplateLoader; - if(loaders.FileSystemLoader) { - TemplateLoader = new loaders.FileSystemLoader(templatesPath, { - watch: opts.watch, - noCache: opts.noCache - }); - } - else if(loaders.WebLoader) { - TemplateLoader = new loaders.WebLoader(templatesPath, { - useCache: opts.web && opts.web.useCache, - async: opts.web && opts.web.async - }); - } - - e = new env.Environment(TemplateLoader, opts); - - if(opts && opts.express) { - e.express(opts.express); - } - - return e; - }; - - module.exports.compile = function(src, env, path, eagerCompile) { - if(!e) { - module.exports.configure(); - } - return new module.exports.Template(src, env, path, eagerCompile); - }; - - module.exports.render = function(name, ctx, cb) { - if(!e) { - module.exports.configure(); - } - - return e.render(name, ctx, cb); - }; - - module.exports.renderString = function(src, ctx, cb) { - if(!e) { - module.exports.configure(); - } - - return e.renderString(src, ctx, cb); - }; - - if(precompile) { - module.exports.precompile = precompile.precompile; - module.exports.precompileString = precompile.precompileString; - } - - -/***/ }), -/* 1 */ -/***/ (function(module, exports) { - - 'use strict'; - - var ArrayProto = Array.prototype; - var ObjProto = Object.prototype; - - var escapeMap = { - '&': '&', - '"': '"', - '\'': ''', - '<': '<', - '>': '>' - }; - - var escapeRegex = /[&"'<>]/g; - - var lookupEscape = function(ch) { - return escapeMap[ch]; - }; - - var exports = module.exports = {}; - - exports.prettifyError = function(path, withInternals, err) { - if (!err.Update) { - // not one of ours, cast it - err = new exports.TemplateError(err); - } - err.Update(path); - - // Unless they marked the dev flag, show them a trace from here - if (!withInternals) { - var old = err; - err = new Error(old.message); - err.name = old.name; - } - - return err; - }; - - exports.TemplateError = function(message, lineno, colno) { - var err = this; - - if (message instanceof Error) { // for casting regular js errors - err = message; - message = message.name + ': ' + message.message; - - try { - if(err.name = '') {} - } - catch(e) { - // If we can't set the name of the error object in this - // environment, don't use it - err = this; - } - } else { - if(Error.captureStackTrace) { - Error.captureStackTrace(err); - } - } - - err.name = 'Template render error'; - err.message = message; - err.lineno = lineno; - err.colno = colno; - err.firstUpdate = true; - - err.Update = function(path) { - var message = '(' + (path || 'unknown path') + ')'; - - // only show lineno + colno next to path of template - // where error occurred - if (this.firstUpdate) { - if(this.lineno && this.colno) { - message += ' [Line ' + this.lineno + ', Column ' + this.colno + ']'; - } - else if(this.lineno) { - message += ' [Line ' + this.lineno + ']'; - } - } - - message += '\n '; - if (this.firstUpdate) { - message += ' '; - } - - this.message = message + (this.message || ''); - this.firstUpdate = false; - return this; - }; - - return err; - }; - - exports.TemplateError.prototype = Error.prototype; - - exports.escape = function(val) { - return val.replace(escapeRegex, lookupEscape); - }; - - exports.isFunction = function(obj) { - return ObjProto.toString.call(obj) === '[object Function]'; - }; - - exports.isArray = Array.isArray || function(obj) { - return ObjProto.toString.call(obj) === '[object Array]'; - }; - - exports.isString = function(obj) { - return ObjProto.toString.call(obj) === '[object String]'; - }; - - exports.isObject = function(obj) { - return ObjProto.toString.call(obj) === '[object Object]'; - }; - - exports.groupBy = function(obj, val) { - var result = {}; - var iterator = exports.isFunction(val) ? val : function(obj) { return obj[val]; }; - for(var i=0; i>> 0; // Hack to convert object.length to a UInt32 - - fromIndex = +fromIndex || 0; - - if(Math.abs(fromIndex) === Infinity) { - fromIndex = 0; - } - - if(fromIndex < 0) { - fromIndex += length; - if (fromIndex < 0) { - fromIndex = 0; - } - } - - for(;fromIndex < length; fromIndex++) { - if (arr[fromIndex] === searchElement) { - return fromIndex; - } - } - - return -1; - }; - - if(!Array.prototype.map) { - Array.prototype.map = function() { - throw new Error('map is unimplemented for this js engine'); - }; - } - - exports.keys = function(obj) { - if(Object.prototype.keys) { - return obj.keys(); - } - else { - var keys = []; - for(var k in obj) { - if(obj.hasOwnProperty(k)) { - keys.push(k); - } - } - return keys; - } - }; - - exports.inOperator = function (key, val) { - if (exports.isArray(val)) { - return exports.indexOf(val, key) !== -1; - } else if (exports.isObject(val)) { - return key in val; - } else if (exports.isString(val)) { - return val.indexOf(key) !== -1; - } else { - throw new Error('Cannot use "in" operator to search for "' - + key + '" in unexpected types.'); - } - }; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var path = __webpack_require__(3); - var asap = __webpack_require__(4); - var lib = __webpack_require__(1); - var Obj = __webpack_require__(6); - var compiler = __webpack_require__(3); - var builtin_filters = __webpack_require__(7); - var builtin_loaders = __webpack_require__(3); - var runtime = __webpack_require__(8); - var globals = __webpack_require__(9); - var waterfall = __webpack_require__(10); - var Frame = runtime.Frame; - var Template; - - // Unconditionally load in this loader, even if no other ones are - // included (possible in the slim browser build) - builtin_loaders.PrecompiledLoader = __webpack_require__(14); - - // If the user is using the async API, *always* call it - // asynchronously even if the template was synchronous. - function callbackAsap(cb, err, res) { - asap(function() { cb(err, res); }); - } - - var Environment = Obj.extend({ - init: function(loaders, opts) { - // The dev flag determines the trace that'll be shown on errors. - // If set to true, returns the full trace from the error point, - // otherwise will return trace starting from Template.render - // (the full trace from within nunjucks may confuse developers using - // the library) - // defaults to false - opts = this.opts = opts || {}; - this.opts.dev = !!opts.dev; - - // The autoescape flag sets global autoescaping. If true, - // every string variable will be escaped by default. - // If false, strings can be manually escaped using the `escape` filter. - // defaults to true - this.opts.autoescape = opts.autoescape != null ? opts.autoescape : true; - - // If true, this will make the system throw errors if trying - // to output a null or undefined value - this.opts.throwOnUndefined = !!opts.throwOnUndefined; - this.opts.trimBlocks = !!opts.trimBlocks; - this.opts.lstripBlocks = !!opts.lstripBlocks; - - this.loaders = []; - - if(!loaders) { - // The filesystem loader is only available server-side - if(builtin_loaders.FileSystemLoader) { - this.loaders = [new builtin_loaders.FileSystemLoader('views')]; - } - else if(builtin_loaders.WebLoader) { - this.loaders = [new builtin_loaders.WebLoader('/views')]; - } - } - else { - this.loaders = lib.isArray(loaders) ? loaders : [loaders]; - } - - // It's easy to use precompiled templates: just include them - // before you configure nunjucks and this will automatically - // pick it up and use it - if((true) && window.nunjucksPrecompiled) { - this.loaders.unshift( - new builtin_loaders.PrecompiledLoader(window.nunjucksPrecompiled) - ); - } - - this.initCache(); - - this.globals = globals(); - this.filters = {}; - this.asyncFilters = []; - this.extensions = {}; - this.extensionsList = []; - - for(var name in builtin_filters) { - this.addFilter(name, builtin_filters[name]); - } - }, - - initCache: function() { - // Caching and cache busting - lib.each(this.loaders, function(loader) { - loader.cache = {}; - - if(typeof loader.on === 'function') { - loader.on('update', function(template) { - loader.cache[template] = null; - }); - } - }); - }, - - addExtension: function(name, extension) { - extension._name = name; - this.extensions[name] = extension; - this.extensionsList.push(extension); - return this; - }, - - removeExtension: function(name) { - var extension = this.getExtension(name); - if (!extension) return; - - this.extensionsList = lib.without(this.extensionsList, extension); - delete this.extensions[name]; - }, - - getExtension: function(name) { - return this.extensions[name]; - }, - - hasExtension: function(name) { - return !!this.extensions[name]; - }, - - addGlobal: function(name, value) { - this.globals[name] = value; - return this; - }, - - getGlobal: function(name) { - if(typeof this.globals[name] === 'undefined') { - throw new Error('global not found: ' + name); - } - return this.globals[name]; - }, - - addFilter: function(name, func, async) { - var wrapped = func; - - if(async) { - this.asyncFilters.push(name); - } - this.filters[name] = wrapped; - return this; - }, - - getFilter: function(name) { - if(!this.filters[name]) { - throw new Error('filter not found: ' + name); - } - return this.filters[name]; - }, - - resolveTemplate: function(loader, parentName, filename) { - var isRelative = (loader.isRelative && parentName)? loader.isRelative(filename) : false; - return (isRelative && loader.resolve)? loader.resolve(parentName, filename) : filename; - }, - - getTemplate: function(name, eagerCompile, parentName, ignoreMissing, cb) { - var that = this; - var tmpl = null; - if(name && name.raw) { - // this fixes autoescape for templates referenced in symbols - name = name.raw; - } - - if(lib.isFunction(parentName)) { - cb = parentName; - parentName = null; - eagerCompile = eagerCompile || false; - } - - if(lib.isFunction(eagerCompile)) { - cb = eagerCompile; - eagerCompile = false; - } - - if (name instanceof Template) { - tmpl = name; - } - else if(typeof name !== 'string') { - throw new Error('template names must be a string: ' + name); - } - else { - for (var i = 0; i < this.loaders.length; i++) { - var _name = this.resolveTemplate(this.loaders[i], parentName, name); - tmpl = this.loaders[i].cache[_name]; - if (tmpl) break; - } - } - - if(tmpl) { - if(eagerCompile) { - tmpl.compile(); - } - - if(cb) { - cb(null, tmpl); - } - else { - return tmpl; - } - } else { - var syncResult; - var _this = this; - - var createTemplate = function(err, info) { - if(!info && !err) { - if(!ignoreMissing) { - err = new Error('template not found: ' + name); - } - } - - if (err) { - if(cb) { - cb(err); - } - else { - throw err; - } - } - else { - var tmpl; - if(info) { - tmpl = new Template(info.src, _this, - info.path, eagerCompile); - - if(!info.noCache) { - info.loader.cache[name] = tmpl; - } - } - else { - tmpl = new Template('', _this, - '', eagerCompile); - } - - if(cb) { - cb(null, tmpl); - } - else { - syncResult = tmpl; - } - } - }; - - lib.asyncIter(this.loaders, function(loader, i, next, done) { - function handle(err, src) { - if(err) { - done(err); - } - else if(src) { - src.loader = loader; - done(null, src); - } - else { - next(); - } - } - - // Resolve name relative to parentName - name = that.resolveTemplate(loader, parentName, name); - - if(loader.async) { - loader.getSource(name, handle); - } - else { - handle(null, loader.getSource(name)); - } - }, createTemplate); - - return syncResult; - } - }, - - express: function(app) { - var env = this; - - function NunjucksView(name, opts) { - this.name = name; - this.path = name; - this.defaultEngine = opts.defaultEngine; - this.ext = path.extname(name); - if (!this.ext && !this.defaultEngine) throw new Error('No default engine was specified and no extension was provided.'); - if (!this.ext) this.name += (this.ext = ('.' !== this.defaultEngine[0] ? '.' : '') + this.defaultEngine); - } - - NunjucksView.prototype.render = function(opts, cb) { - env.render(this.name, opts, cb); - }; - - app.set('view', NunjucksView); - app.set('nunjucksEnv', this); - return this; - }, - - render: function(name, ctx, cb) { - if(lib.isFunction(ctx)) { - cb = ctx; - ctx = null; - } - - // We support a synchronous API to make it easier to migrate - // existing code to async. This works because if you don't do - // anything async work, the whole thing is actually run - // synchronously. - var syncResult = null; - - this.getTemplate(name, function(err, tmpl) { - if(err && cb) { - callbackAsap(cb, err); - } - else if(err) { - throw err; - } - else { - syncResult = tmpl.render(ctx, cb); - } - }); - - return syncResult; - }, - - renderString: function(src, ctx, opts, cb) { - if(lib.isFunction(opts)) { - cb = opts; - opts = {}; - } - opts = opts || {}; - - var tmpl = new Template(src, this, opts.path); - return tmpl.render(ctx, cb); - }, - - waterfall: waterfall - }); - - var Context = Obj.extend({ - init: function(ctx, blocks, env) { - // Has to be tied to an environment so we can tap into its globals. - this.env = env || new Environment(); - - // Make a duplicate of ctx - this.ctx = {}; - for(var k in ctx) { - if(ctx.hasOwnProperty(k)) { - this.ctx[k] = ctx[k]; - } - } - - this.blocks = {}; - this.exported = []; - - for(var name in blocks) { - this.addBlock(name, blocks[name]); - } - }, - - lookup: function(name) { - // This is one of the most called functions, so optimize for - // the typical case where the name isn't in the globals - if(name in this.env.globals && !(name in this.ctx)) { - return this.env.globals[name]; - } - else { - return this.ctx[name]; - } - }, - - setVariable: function(name, val) { - this.ctx[name] = val; - }, - - getVariables: function() { - return this.ctx; - }, - - addBlock: function(name, block) { - this.blocks[name] = this.blocks[name] || []; - this.blocks[name].push(block); - return this; - }, - - getBlock: function(name) { - if(!this.blocks[name]) { - throw new Error('unknown block "' + name + '"'); - } - - return this.blocks[name][0]; - }, - - getSuper: function(env, name, block, frame, runtime, cb) { - var idx = lib.indexOf(this.blocks[name] || [], block); - var blk = this.blocks[name][idx + 1]; - var context = this; - - if(idx === -1 || !blk) { - throw new Error('no super block available for "' + name + '"'); - } - - blk(env, context, frame, runtime, cb); - }, - - addExport: function(name) { - this.exported.push(name); - }, - - getExported: function() { - var exported = {}; - for(var i=0; i capacity) { - // Manually shift all values starting at the index back to the - // beginning of the queue. - for (var scan = 0, newLength = queue.length - index; scan < newLength; scan++) { - queue[scan] = queue[scan + index]; - } - queue.length -= index; - index = 0; - } - } - queue.length = 0; - index = 0; - flushing = false; - } - - // `requestFlush` is implemented using a strategy based on data collected from - // every available SauceLabs Selenium web driver worker at time of writing. - // https://docs.google.com/spreadsheets/d/1mG-5UYGup5qxGdEMWkhP6BWCz053NUb2E1QoUTU16uA/edit#gid=783724593 - - // Safari 6 and 6.1 for desktop, iPad, and iPhone are the only browsers that - // have WebKitMutationObserver but not un-prefixed MutationObserver. - // Must use `global` or `self` instead of `window` to work in both frames and web - // workers. `global` is a provision of Browserify, Mr, Mrs, or Mop. - - /* globals self */ - var scope = typeof global !== "undefined" ? global : self; - var BrowserMutationObserver = scope.MutationObserver || scope.WebKitMutationObserver; - - // MutationObservers are desirable because they have high priority and work - // reliably everywhere they are implemented. - // They are implemented in all modern browsers. - // - // - Android 4-4.3 - // - Chrome 26-34 - // - Firefox 14-29 - // - Internet Explorer 11 - // - iPad Safari 6-7.1 - // - iPhone Safari 7-7.1 - // - Safari 6-7 - if (typeof BrowserMutationObserver === "function") { - requestFlush = makeRequestCallFromMutationObserver(flush); - - // MessageChannels are desirable because they give direct access to the HTML - // task queue, are implemented in Internet Explorer 10, Safari 5.0-1, and Opera - // 11-12, and in web workers in many engines. - // Although message channels yield to any queued rendering and IO tasks, they - // would be better than imposing the 4ms delay of timers. - // However, they do not work reliably in Internet Explorer or Safari. - - // Internet Explorer 10 is the only browser that has setImmediate but does - // not have MutationObservers. - // Although setImmediate yields to the browser's renderer, it would be - // preferrable to falling back to setTimeout since it does not have - // the minimum 4ms penalty. - // Unfortunately there appears to be a bug in Internet Explorer 10 Mobile (and - // Desktop to a lesser extent) that renders both setImmediate and - // MessageChannel useless for the purposes of ASAP. - // https://github.com/kriskowal/q/issues/396 - - // Timers are implemented universally. - // We fall back to timers in workers in most engines, and in foreground - // contexts in the following browsers. - // However, note that even this simple case requires nuances to operate in a - // broad spectrum of browsers. - // - // - Firefox 3-13 - // - Internet Explorer 6-9 - // - iPad Safari 4.3 - // - Lynx 2.8.7 - } else { - requestFlush = makeRequestCallFromTimer(flush); - } - - // `requestFlush` requests that the high priority event queue be flushed as - // soon as possible. - // This is useful to prevent an error thrown in a task from stalling the event - // queue if the exception handled by Node.js’s - // `process.on("uncaughtException")` or by a domain. - rawAsap.requestFlush = requestFlush; - - // To request a high priority event, we induce a mutation observer by toggling - // the text of a text node between "1" and "-1". - function makeRequestCallFromMutationObserver(callback) { - var toggle = 1; - var observer = new BrowserMutationObserver(callback); - var node = document.createTextNode(""); - observer.observe(node, {characterData: true}); - return function requestCall() { - toggle = -toggle; - node.data = toggle; - }; - } - - // The message channel technique was discovered by Malte Ubl and was the - // original foundation for this library. - // http://www.nonblocking.io/2011/06/windownexttick.html - - // Safari 6.0.5 (at least) intermittently fails to create message ports on a - // page's first load. Thankfully, this version of Safari supports - // MutationObservers, so we don't need to fall back in that case. - - // function makeRequestCallFromMessageChannel(callback) { - // var channel = new MessageChannel(); - // channel.port1.onmessage = callback; - // return function requestCall() { - // channel.port2.postMessage(0); - // }; - // } - - // For reasons explained above, we are also unable to use `setImmediate` - // under any circumstances. - // Even if we were, there is another bug in Internet Explorer 10. - // It is not sufficient to assign `setImmediate` to `requestFlush` because - // `setImmediate` must be called *by name* and therefore must be wrapped in a - // closure. - // Never forget. - - // function makeRequestCallFromSetImmediate(callback) { - // return function requestCall() { - // setImmediate(callback); - // }; - // } - - // Safari 6.0 has a problem where timers will get lost while the user is - // scrolling. This problem does not impact ASAP because Safari 6.0 supports - // mutation observers, so that implementation is used instead. - // However, if we ever elect to use timers in Safari, the prevalent work-around - // is to add a scroll event listener that calls for a flush. - - // `setTimeout` does not call the passed callback if the delay is less than - // approximately 7 in web workers in Firefox 8 through 18, and sometimes not - // even then. - - function makeRequestCallFromTimer(callback) { - return function requestCall() { - // We dispatch a timeout with a specified delay of 0 for engines that - // can reliably accommodate that request. This will usually be snapped - // to a 4 milisecond delay, but once we're flushing, there's no delay - // between events. - var timeoutHandle = setTimeout(handleTimer, 0); - // However, since this timer gets frequently dropped in Firefox - // workers, we enlist an interval handle that will try to fire - // an event 20 times per second until it succeeds. - var intervalHandle = setInterval(handleTimer, 50); - - function handleTimer() { - // Whichever timer succeeds will cancel both timers and - // execute the callback. - clearTimeout(timeoutHandle); - clearInterval(intervalHandle); - callback(); - } - }; - } - - // This is for `asap.js` only. - // Its name will be periodically randomized to break any code that depends on - // its existence. - rawAsap.makeRequestCallFromTimer = makeRequestCallFromTimer; - - // ASAP was originally a nextTick shim included in Q. This was factored out - // into this ASAP package. It was later adapted to RSVP which made further - // amendments. These decisions, particularly to marginalize MessageChannel and - // to capture the MutationObserver implementation in a closure, were integrated - // back into ASAP proper. - // https://github.com/tildeio/rsvp.js/blob/cddf7232546a9cf858524b75cde6f9edf72620a7/lib/rsvp/asap.js - - /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports) { - - 'use strict'; - - // A simple class system, more documentation to come - - function extend(cls, name, props) { - // This does that same thing as Object.create, but with support for IE8 - var F = function() {}; - F.prototype = cls.prototype; - var prototype = new F(); - - var fnTest = /xyz/.test(function(){ xyz; }) ? /\bparent\b/ : /.*/; - props = props || {}; - - for(var k in props) { - var src = props[k]; - var parent = prototype[k]; - - if(typeof parent === 'function' && - typeof src === 'function' && - fnTest.test(src)) { - prototype[k] = (function (src, parent) { - return function() { - // Save the current parent method - var tmp = this.parent; - - // Set parent to the previous method, call, and restore - this.parent = parent; - var res = src.apply(this, arguments); - this.parent = tmp; - - return res; - }; - })(src, parent); - } - else { - prototype[k] = src; - } - } - - prototype.typename = name; - - var new_cls = function() { - if(prototype.init) { - prototype.init.apply(this, arguments); - } - }; - - new_cls.prototype = prototype; - new_cls.prototype.constructor = new_cls; - - new_cls.extend = function(name, props) { - if(typeof name === 'object') { - props = name; - name = 'anonymous'; - } - return extend(new_cls, name, props); - }; - - return new_cls; - } - - module.exports = extend(Object, 'Object', {}); - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var lib = __webpack_require__(1); - var r = __webpack_require__(8); - - function normalize(value, defaultValue) { - if(value === null || value === undefined || value === false) { - return defaultValue; - } - return value; - } - - var filters = { - abs: Math.abs, - - batch: function(arr, linecount, fill_with) { - var i; - var res = []; - var tmp = []; - - for(i = 0; i < arr.length; i++) { - if(i % linecount === 0 && tmp.length) { - res.push(tmp); - tmp = []; - } - - tmp.push(arr[i]); - } - - if(tmp.length) { - if(fill_with) { - for(i = tmp.length; i < linecount; i++) { - tmp.push(fill_with); - } - } - - res.push(tmp); - } - - return res; - }, - - capitalize: function(str) { - str = normalize(str, ''); - var ret = str.toLowerCase(); - return r.copySafeness(str, ret.charAt(0).toUpperCase() + ret.slice(1)); - }, - - center: function(str, width) { - str = normalize(str, ''); - width = width || 80; - - if(str.length >= width) { - return str; - } - - var spaces = width - str.length; - var pre = lib.repeat(' ', spaces/2 - spaces % 2); - var post = lib.repeat(' ', spaces/2); - return r.copySafeness(str, pre + str + post); - }, - - 'default': function(val, def, bool) { - if(bool) { - return val ? val : def; - } - else { - return (val !== undefined) ? val : def; - } - }, - - dictsort: function(val, case_sensitive, by) { - if (!lib.isObject(val)) { - throw new lib.TemplateError('dictsort filter: val must be an object'); - } - - var array = []; - for (var k in val) { - // deliberately include properties from the object's prototype - array.push([k,val[k]]); - } - - var si; - if (by === undefined || by === 'key') { - si = 0; - } else if (by === 'value') { - si = 1; - } else { - throw new lib.TemplateError( - 'dictsort filter: You can only sort by either key or value'); - } - - array.sort(function(t1, t2) { - var a = t1[si]; - var b = t2[si]; - - if (!case_sensitive) { - if (lib.isString(a)) { - a = a.toUpperCase(); - } - if (lib.isString(b)) { - b = b.toUpperCase(); - } - } - - return a > b ? 1 : (a === b ? 0 : -1); - }); - - return array; - }, - - dump: function(obj, spaces) { - return JSON.stringify(obj, null, spaces); - }, - - escape: function(str) { - if(str instanceof r.SafeString) { - return str; - } - str = (str === null || str === undefined) ? '' : str; - return r.markSafe(lib.escape(str.toString())); - }, - - safe: function(str) { - if (str instanceof r.SafeString) { - return str; - } - str = (str === null || str === undefined) ? '' : str; - return r.markSafe(str.toString()); - }, - - first: function(arr) { - return arr[0]; - }, - - groupby: function(arr, attr) { - return lib.groupBy(arr, attr); - }, - - indent: function(str, width, indentfirst) { - str = normalize(str, ''); - - if (str === '') return ''; - - width = width || 4; - var res = ''; - var lines = str.split('\n'); - var sp = lib.repeat(' ', width); - - for(var i=0; i\n')); - }, - - random: function(arr) { - return arr[Math.floor(Math.random() * arr.length)]; - }, - - rejectattr: function(arr, attr) { - return arr.filter(function (item) { - return !item[attr]; - }); - }, - - selectattr: function(arr, attr) { - return arr.filter(function (item) { - return !!item[attr]; - }); - }, - - replace: function(str, old, new_, maxCount) { - var originalStr = str; - - if (old instanceof RegExp) { - return str.replace(old, new_); - } - - if(typeof maxCount === 'undefined'){ - maxCount = -1; - } - - var res = ''; // Output - - // Cast Numbers in the search term to string - if(typeof old === 'number'){ - old = old + ''; - } - else if(typeof old !== 'string') { - // If it is something other than number or string, - // return the original string - return str; - } - - // Cast numbers in the replacement to string - if(typeof str === 'number'){ - str = str + ''; - } - - // If by now, we don't have a string, throw it back - if(typeof str !== 'string' && !(str instanceof r.SafeString)){ - return str; - } - - // ShortCircuits - if(old === ''){ - // Mimic the python behaviour: empty string is replaced - // by replacement e.g. "abc"|replace("", ".") -> .a.b.c. - res = new_ + str.split('').join(new_) + new_; - return r.copySafeness(str, res); - } - - var nextIndex = str.indexOf(old); - // if # of replacements to perform is 0, or the string to does - // not contain the old value, return the string - if(maxCount === 0 || nextIndex === -1){ - return str; - } - - var pos = 0; - var count = 0; // # of replacements made - - while(nextIndex > -1 && (maxCount === -1 || count < maxCount)){ - // Grab the next chunk of src string and add it with the - // replacement, to the result - res += str.substring(pos, nextIndex) + new_; - // Increment our pointer in the src string - pos = nextIndex + old.length; - count++; - // See if there are any more replacements to be made - nextIndex = str.indexOf(old, pos); - } - - // We've either reached the end, or done the max # of - // replacements, tack on any remaining string - if(pos < str.length) { - res += str.substring(pos); - } - - return r.copySafeness(originalStr, res); - }, - - reverse: function(val) { - var arr; - if(lib.isString(val)) { - arr = filters.list(val); - } - else { - // Copy it - arr = lib.map(val, function(v) { return v; }); - } - - arr.reverse(); - - if(lib.isString(val)) { - return r.copySafeness(val, arr.join('')); - } - return arr; - }, - - round: function(val, precision, method) { - precision = precision || 0; - var factor = Math.pow(10, precision); - var rounder; - - if(method === 'ceil') { - rounder = Math.ceil; - } - else if(method === 'floor') { - rounder = Math.floor; - } - else { - rounder = Math.round; - } - - return rounder(val * factor) / factor; - }, - - slice: function(arr, slices, fillWith) { - var sliceLength = Math.floor(arr.length / slices); - var extra = arr.length % slices; - var offset = 0; - var res = []; - - for(var i=0; i= extra) { - slice.push(fillWith); - } - res.push(slice); - } - - return res; - }, - - sum: function(arr, attr, start) { - var sum = 0; - - if(typeof start === 'number'){ - sum += start; - } - - if(attr) { - arr = lib.map(arr, function(v) { - return v[attr]; - }); - } - - for(var i = 0; i < arr.length; i++) { - sum += arr[i]; - } - - return sum; - }, - - sort: r.makeMacro(['value', 'reverse', 'case_sensitive', 'attribute'], [], function(arr, reverse, caseSens, attr) { - // Copy it - arr = lib.map(arr, function(v) { return v; }); - - arr.sort(function(a, b) { - var x, y; - - if(attr) { - x = a[attr]; - y = b[attr]; - } - else { - x = a; - y = b; - } - - if(!caseSens && lib.isString(x) && lib.isString(y)) { - x = x.toLowerCase(); - y = y.toLowerCase(); - } - - if(x < y) { - return reverse ? 1 : -1; - } - else if(x > y) { - return reverse ? -1: 1; - } - else { - return 0; - } - }); - - return arr; - }), - - string: function(obj) { - return r.copySafeness(obj, obj); - }, - - striptags: function(input, preserve_linebreaks) { - input = normalize(input, ''); - preserve_linebreaks = preserve_linebreaks || false; - var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>|/gi; - var trimmedInput = filters.trim(input.replace(tags, '')); - var res = ''; - if (preserve_linebreaks) { - res = trimmedInput - .replace(/^ +| +$/gm, '') // remove leading and trailing spaces - .replace(/ +/g, ' ') // squash adjacent spaces - .replace(/(\r\n)/g, '\n') // normalize linebreaks (CRLF -> LF) - .replace(/\n\n\n+/g, '\n\n'); // squash abnormal adjacent linebreaks - } else { - res = trimmedInput.replace(/\s+/gi, ' '); - } - return r.copySafeness(input, res); - }, - - title: function(str) { - str = normalize(str, ''); - var words = str.split(' '); - for(var i = 0; i < words.length; i++) { - words[i] = filters.capitalize(words[i]); - } - return r.copySafeness(str, words.join(' ')); - }, - - trim: function(str) { - return r.copySafeness(str, str.replace(/^\s*|\s*$/g, '')); - }, - - truncate: function(input, length, killwords, end) { - var orig = input; - input = normalize(input, ''); - length = length || 255; - - if (input.length <= length) - return input; - - if (killwords) { - input = input.substring(0, length); - } else { - var idx = input.lastIndexOf(' ', length); - if(idx === -1) { - idx = length; - } - - input = input.substring(0, idx); - } - - input += (end !== undefined && end !== null) ? end : '...'; - return r.copySafeness(orig, input); - }, - - upper: function(str) { - str = normalize(str, ''); - return str.toUpperCase(); - }, - - urlencode: function(obj) { - var enc = encodeURIComponent; - if (lib.isString(obj)) { - return enc(obj); - } else { - var parts; - if (lib.isArray(obj)) { - parts = obj.map(function(item) { - return enc(item[0]) + '=' + enc(item[1]); - }); - } else { - parts = []; - for (var k in obj) { - if (obj.hasOwnProperty(k)) { - parts.push(enc(k) + '=' + enc(obj[k])); - } - } - } - return parts.join('&'); - } - }, - - urlize: function(str, length, nofollow) { - if (isNaN(length)) length = Infinity; - - var noFollowAttr = (nofollow === true ? ' rel="nofollow"' : ''); - - // For the jinja regexp, see - // https://github.com/mitsuhiko/jinja2/blob/f15b814dcba6aa12bc74d1f7d0c881d55f7126be/jinja2/utils.py#L20-L23 - var puncRE = /^(?:\(|<|<)?(.*?)(?:\.|,|\)|\n|>)?$/; - // from http://blog.gerv.net/2011/05/html5_email_address_regexp/ - var emailRE = /^[\w.!#$%&'*+\-\/=?\^`{|}~]+@[a-z\d\-]+(\.[a-z\d\-]+)+$/i; - var httpHttpsRE = /^https?:\/\/.*$/; - var wwwRE = /^www\./; - var tldRE = /\.(?:org|net|com)(?:\:|\/|$)/; - - var words = str.split(/(\s+)/).filter(function(word) { - // If the word has no length, bail. This can happen for str with - // trailing whitespace. - return word && word.length; - }).map(function(word) { - var matches = word.match(puncRE); - var possibleUrl = matches && matches[1] || word; - - // url that starts with http or https - if (httpHttpsRE.test(possibleUrl)) - return '' + possibleUrl.substr(0, length) + ''; - - // url that starts with www. - if (wwwRE.test(possibleUrl)) - return '' + possibleUrl.substr(0, length) + ''; - - // an email address of the form username@domain.tld - if (emailRE.test(possibleUrl)) - return '' + possibleUrl + ''; - - // url that ends in .com, .org or .net that is not an email address - if (tldRE.test(possibleUrl)) - return '' + possibleUrl.substr(0, length) + ''; - - return word; - - }); - - return words.join(''); - }, - - wordcount: function(str) { - str = normalize(str, ''); - var words = (str) ? str.match(/\w+/g) : null; - return (words) ? words.length : null; - }, - - 'float': function(val, def) { - var res = parseFloat(val); - return isNaN(res) ? def : res; - }, - - 'int': function(val, def) { - var res = parseInt(val, 10); - return isNaN(res) ? def : res; - } - }; - - // Aliases - filters.d = filters['default']; - filters.e = filters.escape; - - module.exports = filters; - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var lib = __webpack_require__(1); - var Obj = __webpack_require__(6); - - // Frames keep track of scoping both at compile-time and run-time so - // we know how to access variables. Block tags can introduce special - // variables, for example. - var Frame = Obj.extend({ - init: function(parent, isolateWrites) { - this.variables = {}; - this.parent = parent; - this.topLevel = false; - // if this is true, writes (set) should never propagate upwards past - // this frame to its parent (though reads may). - this.isolateWrites = isolateWrites; - }, - - set: function(name, val, resolveUp) { - // Allow variables with dots by automatically creating the - // nested structure - var parts = name.split('.'); - var obj = this.variables; - var frame = this; - - if(resolveUp) { - if((frame = this.resolve(parts[0], true))) { - frame.set(name, val); - return; - } - } - - for(var i=0; i argNames.length) { - args = Array.prototype.slice.call(arguments, 0, argNames.length); - - // Positional arguments that should be passed in as - // keyword arguments (essentially default values) - var vals = Array.prototype.slice.call(arguments, args.length, argCount); - for(i = 0; i < vals.length; i++) { - if(i < kwargNames.length) { - kwargs[kwargNames[i]] = vals[i]; - } - } - - args.push(kwargs); - } - else if(argCount < argNames.length) { - args = Array.prototype.slice.call(arguments, 0, argCount); - - for(i = argCount; i < argNames.length; i++) { - var arg = argNames[i]; - - // Keyword arguments that should be passed as - // positional arguments, i.e. the caller explicitly - // used the name of a positional arg - args.push(kwargs[arg]); - delete kwargs[arg]; - } - - args.push(kwargs); - } - else { - args = arguments; - } - - return func.apply(this, args); - }; - } - - function makeKeywordArgs(obj) { - obj.__keywords = true; - return obj; - } - - function getKeywordArgs(args) { - var len = args.length; - if(len) { - var lastArg = args[len - 1]; - if(lastArg && lastArg.hasOwnProperty('__keywords')) { - return lastArg; - } - } - return {}; - } - - function numArgs(args) { - var len = args.length; - if(len === 0) { - return 0; - } - - var lastArg = args[len - 1]; - if(lastArg && lastArg.hasOwnProperty('__keywords')) { - return len - 1; - } - else { - return len; - } - } - - // A SafeString object indicates that the string should not be - // autoescaped. This happens magically because autoescaping only - // occurs on primitive string objects. - function SafeString(val) { - if(typeof val !== 'string') { - return val; - } - - this.val = val; - this.length = val.length; - } - - SafeString.prototype = Object.create(String.prototype, { - length: { writable: true, configurable: true, value: 0 } - }); - SafeString.prototype.valueOf = function() { - return this.val; - }; - SafeString.prototype.toString = function() { - return this.val; - }; - - function copySafeness(dest, target) { - if(dest instanceof SafeString) { - return new SafeString(target); - } - return target.toString(); - } - - function markSafe(val) { - var type = typeof val; - - if(type === 'string') { - return new SafeString(val); - } - else if(type !== 'function') { - return val; - } - else { - return function() { - var ret = val.apply(this, arguments); - - if(typeof ret === 'string') { - return new SafeString(ret); - } - - return ret; - }; - } - } - - function suppressValue(val, autoescape) { - val = (val !== undefined && val !== null) ? val : ''; - - if(autoescape && !(val instanceof SafeString)) { - val = lib.escape(val.toString()); - } - - return val; - } - - function ensureDefined(val, lineno, colno) { - if(val === null || val === undefined) { - throw new lib.TemplateError( - 'attempted to output null or undefined value', - lineno + 1, - colno + 1 - ); - } - return val; - } - - function memberLookup(obj, val) { - obj = obj || {}; - - if(typeof obj[val] === 'function') { - return function() { - return obj[val].apply(obj, arguments); - }; - } - - return obj[val]; - } - - function callWrap(obj, name, context, args) { - if(!obj) { - throw new Error('Unable to call `' + name + '`, which is undefined or falsey'); - } - else if(typeof obj !== 'function') { - throw new Error('Unable to call `' + name + '`, which is not a function'); - } - - return obj.apply(context, args); - } - - function contextOrFrameLookup(context, frame, name) { - var val = frame.lookup(name); - return (val !== undefined) ? - val : - context.lookup(name); - } - - function handleError(error, lineno, colno) { - if(error.lineno) { - return error; - } - else { - return new lib.TemplateError(error, lineno, colno); - } - } - - function asyncEach(arr, dimen, iter, cb) { - if(lib.isArray(arr)) { - var len = arr.length; - - lib.asyncIter(arr, function(item, i, next) { - switch(dimen) { - case 1: iter(item, i, len, next); break; - case 2: iter(item[0], item[1], i, len, next); break; - case 3: iter(item[0], item[1], item[2], i, len, next); break; - default: - item.push(i, next); - iter.apply(this, item); - } - }, cb); - } - else { - lib.asyncFor(arr, function(key, val, i, len, next) { - iter(key, val, i, len, next); - }, cb); - } - } - - function asyncAll(arr, dimen, func, cb) { - var finished = 0; - var len, i; - var outputArr; - - function done(i, output) { - finished++; - outputArr[i] = output; - - if(finished === len) { - cb(null, outputArr.join('')); - } - } - - if(lib.isArray(arr)) { - len = arr.length; - outputArr = new Array(len); - - if(len === 0) { - cb(null, ''); - } - else { - for(i = 0; i < arr.length; i++) { - var item = arr[i]; - - switch(dimen) { - case 1: func(item, i, len, done); break; - case 2: func(item[0], item[1], i, len, done); break; - case 3: func(item[0], item[1], item[2], i, len, done); break; - default: - item.push(i, done); - func.apply(this, item); - } - } - } - } - else { - var keys = lib.keys(arr); - len = keys.length; - outputArr = new Array(len); - - if(len === 0) { - cb(null, ''); - } - else { - for(i = 0; i < keys.length; i++) { - var k = keys[i]; - func(k, arr[k], i, len, done); - } - } - } - } - - module.exports = { - Frame: Frame, - makeMacro: makeMacro, - makeKeywordArgs: makeKeywordArgs, - numArgs: numArgs, - suppressValue: suppressValue, - ensureDefined: ensureDefined, - memberLookup: memberLookup, - contextOrFrameLookup: contextOrFrameLookup, - callWrap: callWrap, - handleError: handleError, - isArray: lib.isArray, - keys: lib.keys, - SafeString: SafeString, - copySafeness: copySafeness, - markSafe: markSafe, - asyncEach: asyncEach, - asyncAll: asyncAll, - inOperator: lib.inOperator - }; - - -/***/ }), -/* 9 */ -/***/ (function(module, exports) { - - 'use strict'; - - function cycler(items) { - var index = -1; - - return { - current: null, - reset: function() { - index = -1; - this.current = null; - }, - - next: function() { - index++; - if(index >= items.length) { - index = 0; - } - - this.current = items[index]; - return this.current; - }, - }; - - } - - function joiner(sep) { - sep = sep || ','; - var first = true; - - return function() { - var val = first ? '' : sep; - first = false; - return val; - }; - } - - // Making this a function instead so it returns a new object - // each time it's called. That way, if something like an environment - // uses it, they will each have their own copy. - function globals() { - return { - range: function(start, stop, step) { - if(typeof stop === 'undefined') { - stop = start; - start = 0; - step = 1; - } - else if(!step) { - step = 1; - } - - var arr = []; - var i; - if (step > 0) { - for (i=start; istop; i+=step) { - arr.push(i); - } - } - return arr; - }, - - // lipsum: function(n, html, min, max) { - // }, - - cycler: function() { - return cycler(Array.prototype.slice.call(arguments)); - }, - - joiner: function(sep) { - return joiner(sep); - } - }; - } - - module.exports = globals; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - - var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/* WEBPACK VAR INJECTION */(function(setImmediate, process) {// MIT license (by Elan Shanker). - (function(globals) { - 'use strict'; - - var executeSync = function(){ - var args = Array.prototype.slice.call(arguments); - if (typeof args[0] === 'function'){ - args[0].apply(null, args.splice(1)); - } - }; - - var executeAsync = function(fn){ - if (typeof setImmediate === 'function') { - setImmediate(fn); - } else if (typeof process !== 'undefined' && process.nextTick) { - process.nextTick(fn); - } else { - setTimeout(fn, 0); - } - }; - - var makeIterator = function (tasks) { - var makeCallback = function (index) { - var fn = function () { - if (tasks.length) { - tasks[index].apply(null, arguments); - } - return fn.next(); - }; - fn.next = function () { - return (index < tasks.length - 1) ? makeCallback(index + 1): null; - }; - return fn; - }; - return makeCallback(0); - }; - - var _isArray = Array.isArray || function(maybeArray){ - return Object.prototype.toString.call(maybeArray) === '[object Array]'; - }; - - var waterfall = function (tasks, callback, forceAsync) { - var nextTick = forceAsync ? executeAsync : executeSync; - callback = callback || function () {}; - if (!_isArray(tasks)) { - var err = new Error('First argument to waterfall must be an array of functions'); - return callback(err); - } - if (!tasks.length) { - return callback(); - } - var wrapIterator = function (iterator) { - return function (err) { - if (err) { - callback.apply(null, arguments); - callback = function () {}; - } else { - var args = Array.prototype.slice.call(arguments, 1); - var next = iterator.next(); - if (next) { - args.push(wrapIterator(next)); - } else { - args.push(callback); - } - nextTick(function () { - iterator.apply(null, args); - }); - } - }; - }; - wrapIterator(makeIterator(tasks))(); - }; - - if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { - return waterfall; - }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); // RequireJS - } else if (typeof module !== 'undefined' && module.exports) { - module.exports = waterfall; // CommonJS - } else { - globals.waterfall = waterfall; // - + + - + diff --git a/tests/browser/mocha.css b/tests/browser/mocha.css deleted file mode 100644 index 883d44bb..00000000 --- a/tests/browser/mocha.css +++ /dev/null @@ -1,246 +0,0 @@ -@charset "utf-8"; - -body { - font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; - padding: 60px 50px; -} - -#mocha ul, #mocha li { - margin: 0; - padding: 0; -} - -#mocha ul { - list-style: none; -} - -#mocha h1, #mocha h2 { - margin: 0; -} - -#mocha h1 { - margin-top: 15px; - font-size: 1em; - font-weight: 200; -} - -#mocha h1 a { - text-decoration: none; - color: inherit; -} - -#mocha h1 a:hover { - text-decoration: underline; -} - -#mocha .suite .suite h1 { - margin-top: 0; - font-size: .8em; -} - -.hidden { - display: none; -} - -#mocha h2 { - font-size: 12px; - font-weight: normal; - cursor: pointer; -} - -#mocha .suite { - margin-left: 15px; -} - -#mocha .test { - margin-left: 15px; - overflow: hidden; -} - -#mocha .test.pending:hover h2::after { - content: '(pending)'; - font-family: arial; -} - -#mocha .test.pass.medium .duration { - background: #C09853; -} - -#mocha .test.pass.slow .duration { - background: #B94A48; -} - -#mocha .test.pass::before { - content: '✓'; - font-size: 12px; - display: block; - float: left; - margin-right: 5px; - color: #00d6b2; -} - -#mocha .test.pass .duration { - font-size: 9px; - margin-left: 5px; - padding: 2px 5px; - color: white; - -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); - -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); - box-shadow: inset 0 1px 1px rgba(0,0,0,.2); - -webkit-border-radius: 5px; - -moz-border-radius: 5px; - -ms-border-radius: 5px; - -o-border-radius: 5px; - border-radius: 5px; -} - -#mocha .test.pass.fast .duration { - display: none; -} - -#mocha .test.pending { - color: #0b97c4; -} - -#mocha .test.pending::before { - content: '◦'; - color: #0b97c4; -} - -#mocha .test.fail { - color: #c00; -} - -#mocha .test.fail pre { - color: black; -} - -#mocha .test.fail::before { - content: '✖'; - font-size: 12px; - display: block; - float: left; - margin-right: 5px; - color: #c00; -} - -#mocha .test pre.error { - color: #c00; - max-height: 300px; - overflow: auto; -} - -#mocha .test pre { - display: block; - float: left; - clear: left; - font: 12px/1.5 monaco, monospace; - margin: 5px; - padding: 15px; - border: 1px solid #eee; - border-bottom-color: #ddd; - -webkit-border-radius: 3px; - -webkit-box-shadow: 0 1px 3px #eee; - -moz-border-radius: 3px; - -moz-box-shadow: 0 1px 3px #eee; -} - -#mocha .test h2 { - position: relative; -} - -#mocha .test a.replay { - position: absolute; - top: 3px; - right: 0; - text-decoration: none; - vertical-align: middle; - display: block; - width: 15px; - height: 15px; - line-height: 15px; - text-align: center; - background: #eee; - font-size: 15px; - -moz-border-radius: 15px; - border-radius: 15px; - -webkit-transition: opacity 200ms; - -moz-transition: opacity 200ms; - transition: opacity 200ms; - opacity: 0.3; - color: #888; -} - -#mocha .test:hover a.replay { - opacity: 1; -} - -#mocha-report.pass .test.fail { - display: none; -} - -#mocha-report.fail .test.pass { - display: none; -} - -#mocha-error { - color: #c00; - font-size: 1.5 em; - font-weight: 100; - letter-spacing: 1px; -} - -#mocha-stats { - position: fixed; - top: 15px; - right: 10px; - font-size: 12px; - margin: 0; - color: #888; -} - -#mocha-stats .progress { - float: right; - padding-top: 0; -} - -#mocha-stats em { - color: black; -} - -#mocha-stats a { - text-decoration: none; - color: inherit; -} - -#mocha-stats a:hover { - border-bottom: 1px solid #eee; -} - -#mocha-stats li { - display: inline-block; - margin: 0 5px; - list-style: none; - padding-top: 11px; -} - -#mocha-stats canvas { - width: 40px; - height: 40px; -} - -code .comment { color: #ddd } -code .init { color: #2F6FAD } -code .string { color: #5890AD } -code .keyword { color: #8A6343 } -code .number { color: #2F6FAD } - -@media screen and (max-device-width: 480px) { - body { - padding: 60px 0px; - } - - #stats { - position: absolute; - } -} diff --git a/tests/browser/mocha.js b/tests/browser/mocha.js deleted file mode 100644 index ede26aa8..00000000 --- a/tests/browser/mocha.js +++ /dev/null @@ -1,13346 +0,0 @@ -(function e(t, n, r) { - function s(o, u) { - if (!n[o]) { - if (!t[o]) { - var a = typeof require == "function" && require; - if (!u && a) { - return a(o, !0); - } - if (i) { - return i(o, !0); - } - var f = new Error("Cannot find module '" + o + "'"); - throw f.code = "MODULE_NOT_FOUND", f - } - var l = n[o] = { - exports: {} - }; - t[o][0].call(l.exports, function(e) { - var n = t[o][1][e]; - return s(n ? n : e) - }, l, l.exports, e, t, n, r) - } - return n[o].exports - } - var i = typeof require == "function" && require; - for (var o = 0; o < r.length; o++) { - s(r[o]); - } - return s -})({ - 1: [function(require, module, exports) { - (function(process) { - module.exports = process.env.COV - ? require('./lib-cov/mocha') - : require('./lib/mocha'); - - }).call(this, require('_process')) - }, { - "./lib-cov/mocha": undefined, - "./lib/mocha": 14, - "_process": 51 - }], - 2: [function(require, module, exports) { - /* eslint-disable no-unused-vars */ - module.exports = function(type) { - return function() {}; - }; - - }, {}], - 3: [function(require, module, exports) { - /** - * Module exports. - */ - - exports.EventEmitter = EventEmitter; - - /** - * Object#hasOwnProperty reference. - */ - var objToString = Object.prototype.toString; - - /** - * Check if a value is an array. - * - * @api private - * @param {*} val The value to test. - * @return {boolean} true if the value is a boolean, otherwise false. - */ - function isArray(val) { - return objToString.call(val) === '[object Array]'; - } - - /** - * Event emitter constructor. - * - * @api public - */ - function EventEmitter() { - } - - /** - * Add a listener. - * - * @api public - * @param {string} name Event name. - * @param {Function} fn Event handler. - * @return {EventEmitter} Emitter instance. - */ - EventEmitter.prototype.on = function(name, fn) { - if (!this.$events) { - this.$events = {}; - } - - if (!this.$events[name]) { - this.$events[name] = fn; - } else if (isArray(this.$events[name])) { - this.$events[name].push(fn); - } else { - this.$events[name] = [this.$events[name], fn]; - } - - return this; - }; - - EventEmitter.prototype.addListener = EventEmitter.prototype.on; - - /** - * Adds a volatile listener. - * - * @api public - * @param {string} name Event name. - * @param {Function} fn Event handler. - * @return {EventEmitter} Emitter instance. - */ - EventEmitter.prototype.once = function(name, fn) { - var self = this; - - function on() { - self.removeListener(name, on); - fn.apply(this, arguments); - } - - on.listener = fn; - this.on(name, on); - - return this; - }; - - /** - * Remove a listener. - * - * @api public - * @param {string} name Event name. - * @param {Function} fn Event handler. - * @return {EventEmitter} Emitter instance. - */ - EventEmitter.prototype.removeListener = function(name, fn) { - if (this.$events && this.$events[name]) { - var list = this.$events[name]; - - if (isArray(list)) { - var pos = -1; - - for (var i = 0, l = list.length; i < l; i++) { - if (list[i] === fn || (list[i].listener && list[i].listener === fn)) { - pos = i; - break; - } - } - - if (pos < 0) { - return this; - } - - list.splice(pos, 1); - - if (!list.length) { - delete this.$events[name]; - } - } else if (list === fn || (list.listener && list.listener === fn)) { - delete this.$events[name]; - } - } - - return this; - }; - - /** - * Remove all listeners for an event. - * - * @api public - * @param {string} name Event name. - * @return {EventEmitter} Emitter instance. - */ - EventEmitter.prototype.removeAllListeners = function(name) { - if (name === undefined) { - this.$events = {}; - return this; - } - - if (this.$events && this.$events[name]) { - this.$events[name] = null; - } - - return this; - }; - - /** - * Get all listeners for a given event. - * - * @api public - * @param {string} name Event name. - * @return {EventEmitter} Emitter instance. - */ - EventEmitter.prototype.listeners = function(name) { - if (!this.$events) { - this.$events = {}; - } - - if (!this.$events[name]) { - this.$events[name] = []; - } - - if (!isArray(this.$events[name])) { - this.$events[name] = [this.$events[name]]; - } - - return this.$events[name]; - }; - - /** - * Emit an event. - * - * @api public - * @param {string} name Event name. - * @return {boolean} true if at least one handler was invoked, else false. - */ - EventEmitter.prototype.emit = function(name) { - if (!this.$events) { - return false; - } - - var handler = this.$events[name]; - - if (!handler) { - return false; - } - - var args = Array.prototype.slice.call(arguments, 1); - - if (typeof handler === 'function') { - handler.apply(this, args); - } else if (isArray(handler)) { - var listeners = handler.slice(); - - for (var i = 0, l = listeners.length; i < l; i++) { - listeners[i].apply(this, args); - } - } else { - return false; - } - - return true; - }; - - }, {}], - 4: [function(require, module, exports) { - /** - * Expose `Progress`. - */ - - module.exports = Progress; - - /** - * Initialize a new `Progress` indicator. - */ - function Progress() { - this.percent = 0; - this.size(0); - this.fontSize(11); - this.font('helvetica, arial, sans-serif'); - } - - /** - * Set progress size to `size`. - * - * @api public - * @param {number} size - * @return {Progress} Progress instance. - */ - Progress.prototype.size = function(size) { - this._size = size; - return this; - }; - - /** - * Set text to `text`. - * - * @api public - * @param {string} text - * @return {Progress} Progress instance. - */ - Progress.prototype.text = function(text) { - this._text = text; - return this; - }; - - /** - * Set font size to `size`. - * - * @api public - * @param {number} size - * @return {Progress} Progress instance. - */ - Progress.prototype.fontSize = function(size) { - this._fontSize = size; - return this; - }; - - /** - * Set font to `family`. - * - * @param {string} family - * @return {Progress} Progress instance. - */ - Progress.prototype.font = function(family) { - this._font = family; - return this; - }; - - /** - * Update percentage to `n`. - * - * @param {number} n - * @return {Progress} Progress instance. - */ - Progress.prototype.update = function(n) { - this.percent = n; - return this; - }; - - /** - * Draw on `ctx`. - * - * @param {CanvasRenderingContext2d} ctx - * @return {Progress} Progress instance. - */ - Progress.prototype.draw = function(ctx) { - try { - var percent = Math.min(this.percent, 100); - var size = this._size; - var half = size / 2; - var x = half; - var y = half; - var rad = half - 1; - var fontSize = this._fontSize; - - ctx.font = fontSize + 'px ' + this._font; - - var angle = Math.PI * 2 * (percent / 100); - ctx.clearRect(0, 0, size, size); - - // outer circle - ctx.strokeStyle = '#9f9f9f'; - ctx.beginPath(); - ctx.arc(x, y, rad, 0, angle, false); - ctx.stroke(); - - // inner circle - ctx.strokeStyle = '#eee'; - ctx.beginPath(); - ctx.arc(x, y, rad - 1, 0, angle, true); - ctx.stroke(); - - // text - var text = this._text || (percent | 0) + '%'; - var w = ctx.measureText(text).width; - - ctx.fillText(text, x - w / 2 + 1, y + fontSize / 2 - 1); - } catch (err) { - // don't fail if we can't render progress - } - return this; - }; - - }, {}], - 5: [function(require, module, exports) { - (function(global) { - exports.isatty = function isatty() { - return true; - }; - - exports.getWindowSize = function getWindowSize() { - if ('innerHeight' in global) { - return [global.innerHeight, global.innerWidth]; - } - // In a Web Worker, the DOM Window is not available. - return [640, 480]; - }; - - }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) - }, {}], - 6: [function(require, module, exports) { - /** - * Expose `Context`. - */ - - module.exports = Context; - - /** - * Initialize a new `Context`. - * - * @api private - */ - function Context() { - } - - /** - * Set or get the context `Runnable` to `runnable`. - * - * @api private - * @param {Runnable} runnable - * @return {Context} - */ - Context.prototype.runnable = function(runnable) { - if (!arguments.length) { - return this._runnable; - } - this.test = this._runnable = runnable; - return this; - }; - - /** - * Set test timeout `ms`. - * - * @api private - * @param {number} ms - * @return {Context} self - */ - Context.prototype.timeout = function(ms) { - if (!arguments.length) { - return this.runnable().timeout(); - } - this.runnable().timeout(ms); - return this; - }; - - /** - * Set test timeout `enabled`. - * - * @api private - * @param {boolean} enabled - * @return {Context} self - */ - Context.prototype.enableTimeouts = function(enabled) { - this.runnable().enableTimeouts(enabled); - return this; - }; - - /** - * Set test slowness threshold `ms`. - * - * @api private - * @param {number} ms - * @return {Context} self - */ - Context.prototype.slow = function(ms) { - this.runnable().slow(ms); - return this; - }; - - /** - * Mark a test as skipped. - * - * @api private - * @return {Context} self - */ - Context.prototype.skip = function() { - this.runnable().skip(); - return this; - }; - - /** - * Inspect the context void of `._runnable`. - * - * @api private - * @return {string} - */ - Context.prototype.inspect = function() { - return JSON.stringify(this, function(key, val) { - return key === 'runnable' || key === 'test' ? undefined : val; - }, 2); - }; - - }, {}], - 7: [function(require, module, exports) { - /** - * Module dependencies. - */ - - var Runnable = require('./runnable'); - var inherits = require('./utils').inherits; - - /** - * Expose `Hook`. - */ - - module.exports = Hook; - - /** - * Initialize a new `Hook` with the given `title` and callback `fn`. - * - * @param {String} title - * @param {Function} fn - * @api private - */ - function Hook(title, fn) { - Runnable.call(this, title, fn); - this.type = 'hook'; - } - - /** - * Inherit from `Runnable.prototype`. - */ - inherits(Hook, Runnable); - - /** - * Get or set the test `err`. - * - * @param {Error} err - * @return {Error} - * @api public - */ - Hook.prototype.error = function(err) { - if (!arguments.length) { - err = this._error; - this._error = null; - return err; - } - - this._error = err; - }; - - }, { - "./runnable": 35, - "./utils": 39 - }], - 8: [function(require, module, exports) { - /** - * Module dependencies. - */ - - var Suite = require('../suite'); - var Test = require('../test'); - var escapeRe = require('escape-string-regexp'); - - /** - * BDD-style interface: - * - * describe('Array', function() { - * describe('#indexOf()', function() { - * it('should return -1 when not present', function() { - * // ... - * }); - * - * it('should return the index when present', function() { - * // ... - * }); - * }); - * }); - * - * @param {Suite} suite Root suite. - */ - module.exports = function(suite) { - var suites = [suite]; - - suite.on('pre-require', function(context, file, mocha) { - var common = require('./common')(suites, context); - - context.before = common.before; - context.after = common.after; - context.beforeEach = common.beforeEach; - context.afterEach = common.afterEach; - context.run = mocha.options.delay && common.runWithSuite(suite); - /** - * Describe a "suite" with the given `title` - * and callback `fn` containing nested suites - * and/or tests. - */ - - context.describe = context.context = function(title, fn) { - var suite = Suite.create(suites[0], title); - suite.file = file; - suites.unshift(suite); - fn.call(suite); - suites.shift(); - return suite; - }; - - /** - * Pending describe. - */ - - context.xdescribe = context.xcontext = context.describe.skip = function(title, fn) { - var suite = Suite.create(suites[0], title); - suite.pending = true; - suites.unshift(suite); - fn.call(suite); - suites.shift(); - }; - - /** - * Exclusive suite. - */ - - context.describe.only = function(title, fn) { - var suite = context.describe(title, fn); - mocha.grep(suite.fullTitle()); - return suite; - }; - - /** - * Describe a specification or test-case - * with the given `title` and callback `fn` - * acting as a thunk. - */ - - context.it = context.specify = function(title, fn) { - var suite = suites[0]; - if (suite.pending) { - fn = null; - } - var test = new Test(title, fn); - test.file = file; - suite.addTest(test); - return test; - }; - - /** - * Exclusive test-case. - */ - - context.it.only = function(title, fn) { - var test = context.it(title, fn); - var reString = '^' + escapeRe(test.fullTitle()) + '$'; - mocha.grep(new RegExp(reString)); - return test; - }; - - /** - * Pending test case. - */ - - context.xit = context.xspecify = context.it.skip = function(title) { - context.it(title); - }; - }); - }; - - }, { - "../suite": 37, - "../test": 38, - "./common": 9, - "escape-string-regexp": 68 - }], - 9: [function(require, module, exports) { - 'use strict'; - - /** - * Functions common to more than one interface. - * - * @param {Suite[]} suites - * @param {Context} context - * @return {Object} An object containing common functions. - */ - module.exports = function(suites, context) { - return { - /** - * This is only present if flag --delay is passed into Mocha. It triggers - * root suite execution. - * - * @param {Suite} suite The root wuite. - * @return {Function} A function which runs the root suite - */ - runWithSuite: function runWithSuite(suite) { - return function run() { - suite.run(); - }; - }, - - /** - * Execute before running tests. - * - * @param {string} name - * @param {Function} fn - */ - before: function(name, fn) { - suites[0].beforeAll(name, fn); - }, - - /** - * Execute after running tests. - * - * @param {string} name - * @param {Function} fn - */ - after: function(name, fn) { - suites[0].afterAll(name, fn); - }, - - /** - * Execute before each test case. - * - * @param {string} name - * @param {Function} fn - */ - beforeEach: function(name, fn) { - suites[0].beforeEach(name, fn); - }, - - /** - * Execute after each test case. - * - * @param {string} name - * @param {Function} fn - */ - afterEach: function(name, fn) { - suites[0].afterEach(name, fn); - }, - - test: { - /** - * Pending test case. - * - * @param {string} title - */ - skip: function(title) { - context.test(title); - } - } - }; - }; - - }, {}], - 10: [function(require, module, exports) { - /** - * Module dependencies. - */ - - var Suite = require('../suite'); - var Test = require('../test'); - - /** - * TDD-style interface: - * - * exports.Array = { - * '#indexOf()': { - * 'should return -1 when the value is not present': function() { - * - * }, - * - * 'should return the correct index when the value is present': function() { - * - * } - * } - * }; - * - * @param {Suite} suite Root suite. - */ - module.exports = function(suite) { - var suites = [suite]; - - suite.on('require', visit); - - function visit(obj, file) { - var suite; - for (var key in obj) { - if (typeof obj[key] === 'function') { - var fn = obj[key]; - switch (key) { - case 'before': - suites[0].beforeAll(fn); - break; - case 'after': - suites[0].afterAll(fn); - break; - case 'beforeEach': - suites[0].beforeEach(fn); - break; - case 'afterEach': - suites[0].afterEach(fn); - break; - default: - var test = new Test(key, fn); - test.file = file; - suites[0].addTest(test); - } - } else { - suite = Suite.create(suites[0], key); - suites.unshift(suite); - visit(obj[key]); - suites.shift(); - } - } - } - }; - - }, { - "../suite": 37, - "../test": 38 - }], - 11: [function(require, module, exports) { - exports.bdd = require('./bdd'); - exports.tdd = require('./tdd'); - exports.qunit = require('./qunit'); - exports.exports = require('./exports'); - - }, { - "./bdd": 8, - "./exports": 10, - "./qunit": 12, - "./tdd": 13 - }], - 12: [function(require, module, exports) { - /** - * Module dependencies. - */ - - var Suite = require('../suite'); - var Test = require('../test'); - var escapeRe = require('escape-string-regexp'); - - /** - * QUnit-style interface: - * - * suite('Array'); - * - * test('#length', function() { - * var arr = [1,2,3]; - * ok(arr.length == 3); - * }); - * - * test('#indexOf()', function() { - * var arr = [1,2,3]; - * ok(arr.indexOf(1) == 0); - * ok(arr.indexOf(2) == 1); - * ok(arr.indexOf(3) == 2); - * }); - * - * suite('String'); - * - * test('#length', function() { - * ok('foo'.length == 3); - * }); - * - * @param {Suite} suite Root suite. - */ - module.exports = function(suite) { - var suites = [suite]; - - suite.on('pre-require', function(context, file, mocha) { - var common = require('./common')(suites, context); - - context.before = common.before; - context.after = common.after; - context.beforeEach = common.beforeEach; - context.afterEach = common.afterEach; - context.run = mocha.options.delay && common.runWithSuite(suite); - /** - * Describe a "suite" with the given `title`. - */ - - context.suite = function(title) { - if (suites.length > 1) { - suites.shift(); - } - var suite = Suite.create(suites[0], title); - suite.file = file; - suites.unshift(suite); - return suite; - }; - - /** - * Exclusive test-case. - */ - - context.suite.only = function(title, fn) { - var suite = context.suite(title, fn); - mocha.grep(suite.fullTitle()); - }; - - /** - * Describe a specification or test-case - * with the given `title` and callback `fn` - * acting as a thunk. - */ - - context.test = function(title, fn) { - var test = new Test(title, fn); - test.file = file; - suites[0].addTest(test); - return test; - }; - - /** - * Exclusive test-case. - */ - - context.test.only = function(title, fn) { - var test = context.test(title, fn); - var reString = '^' + escapeRe(test.fullTitle()) + '$'; - mocha.grep(new RegExp(reString)); - }; - - context.test.skip = common.test.skip; - }); - }; - - }, { - "../suite": 37, - "../test": 38, - "./common": 9, - "escape-string-regexp": 68 - }], - 13: [function(require, module, exports) { - /** - * Module dependencies. - */ - - var Suite = require('../suite'); - var Test = require('../test'); - var escapeRe = require('escape-string-regexp'); - - /** - * TDD-style interface: - * - * suite('Array', function() { - * suite('#indexOf()', function() { - * suiteSetup(function() { - * - * }); - * - * test('should return -1 when not present', function() { - * - * }); - * - * test('should return the index when present', function() { - * - * }); - * - * suiteTeardown(function() { - * - * }); - * }); - * }); - * - * @param {Suite} suite Root suite. - */ - module.exports = function(suite) { - var suites = [suite]; - - suite.on('pre-require', function(context, file, mocha) { - var common = require('./common')(suites, context); - - context.setup = common.beforeEach; - context.teardown = common.afterEach; - context.suiteSetup = common.before; - context.suiteTeardown = common.after; - context.run = mocha.options.delay && common.runWithSuite(suite); - - /** - * Describe a "suite" with the given `title` and callback `fn` containing - * nested suites and/or tests. - */ - context.suite = function(title, fn) { - var suite = Suite.create(suites[0], title); - suite.file = file; - suites.unshift(suite); - fn.call(suite); - suites.shift(); - return suite; - }; - - /** - * Pending suite. - */ - context.suite.skip = function(title, fn) { - var suite = Suite.create(suites[0], title); - suite.pending = true; - suites.unshift(suite); - fn.call(suite); - suites.shift(); - }; - - /** - * Exclusive test-case. - */ - context.suite.only = function(title, fn) { - var suite = context.suite(title, fn); - mocha.grep(suite.fullTitle()); - }; - - /** - * Describe a specification or test-case with the given `title` and - * callback `fn` acting as a thunk. - */ - context.test = function(title, fn) { - var suite = suites[0]; - if (suite.pending) { - fn = null; - } - var test = new Test(title, fn); - test.file = file; - suite.addTest(test); - return test; - }; - - /** - * Exclusive test-case. - */ - - context.test.only = function(title, fn) { - var test = context.test(title, fn); - var reString = '^' + escapeRe(test.fullTitle()) + '$'; - mocha.grep(new RegExp(reString)); - }; - - context.test.skip = common.test.skip; - }); - }; - - }, { - "../suite": 37, - "../test": 38, - "./common": 9, - "escape-string-regexp": 68 - }], - 14: [function(require, module, exports) { - (function(process, global, __dirname) { - /*! - * mocha - * Copyright(c) 2011 TJ Holowaychuk - * MIT Licensed - */ - - /** - * Module dependencies. - */ - - var escapeRe = require('escape-string-regexp'); - var path = require('path'); - var reporters = require('./reporters'); - var utils = require('./utils'); - - /** - * Expose `Mocha`. - */ - - exports = module.exports = Mocha; - - /** - * To require local UIs and reporters when running in node. - */ - - if (!process.browser) { - var cwd = process.cwd(); - module.paths.push(cwd, path.join(cwd, 'node_modules')); - } - - /** - * Expose internals. - */ - - exports.utils = utils; - exports.interfaces = require('./interfaces'); - exports.reporters = reporters; - exports.Runnable = require('./runnable'); - exports.Context = require('./context'); - exports.Runner = require('./runner'); - exports.Suite = require('./suite'); - exports.Hook = require('./hook'); - exports.Test = require('./test'); - - /** - * Return image `name` path. - * - * @api private - * @param {string} name - * @return {string} - */ - function image(name) { - return path.join(__dirname, '../images', name + '.png'); - } - - /** - * Set up mocha with `options`. - * - * Options: - * - * - `ui` name "bdd", "tdd", "exports" etc - * - `reporter` reporter instance, defaults to `mocha.reporters.spec` - * - `globals` array of accepted globals - * - `timeout` timeout in milliseconds - * - `bail` bail on the first test failure - * - `slow` milliseconds to wait before considering a test slow - * - `ignoreLeaks` ignore global leaks - * - `fullTrace` display the full stack-trace on failing - * - `grep` string or regexp to filter tests with - * - * @param {Object} options - * @api public - */ - function Mocha(options) { - options = options || {}; - this.files = []; - this.options = options; - if (options.grep) { - this.grep(new RegExp(options.grep)); - } - if (options.fgrep) { - this.grep(options.fgrep); - } - this.suite = new exports.Suite('', new exports.Context()); - this.ui(options.ui); - this.bail(options.bail); - this.reporter(options.reporter, options.reporterOptions); - if (typeof options.timeout !== 'undefined' && options.timeout !== null) { - this.timeout(options.timeout); - } - this.useColors(options.useColors); - if (options.enableTimeouts !== null) { - this.enableTimeouts(options.enableTimeouts); - } - if (options.slow) { - this.slow(options.slow); - } - - this.suite.on('pre-require', function(context) { - exports.afterEach = context.afterEach || context.teardown; - exports.after = context.after || context.suiteTeardown; - exports.beforeEach = context.beforeEach || context.setup; - exports.before = context.before || context.suiteSetup; - exports.describe = context.describe || context.suite; - exports.it = context.it || context.test; - exports.setup = context.setup || context.beforeEach; - exports.suiteSetup = context.suiteSetup || context.before; - exports.suiteTeardown = context.suiteTeardown || context.after; - exports.suite = context.suite || context.describe; - exports.teardown = context.teardown || context.afterEach; - exports.test = context.test || context.it; - exports.run = context.run; - }); - } - - /** - * Enable or disable bailing on the first failure. - * - * @api public - * @param {boolean} [bail] - */ - Mocha.prototype.bail = function(bail) { - if (!arguments.length) { - bail = true; - } - this.suite.bail(bail); - return this; - }; - - /** - * Add test `file`. - * - * @api public - * @param {string} file - */ - Mocha.prototype.addFile = function(file) { - this.files.push(file); - return this; - }; - - /** - * Set reporter to `reporter`, defaults to "spec". - * - * @param {String|Function} reporter name or constructor - * @param {Object} reporterOptions optional options - * @api public - * @param {string|Function} reporter name or constructor - * @param {Object} reporterOptions optional options - */ - Mocha.prototype.reporter = function(reporter, reporterOptions) { - if (typeof reporter === 'function') { - this._reporter = reporter; - } else { - reporter = reporter || 'spec'; - var _reporter; - // Try to load a built-in reporter. - if (reporters[reporter]) { - _reporter = reporters[reporter]; - } - // Try to load reporters from process.cwd() and node_modules - if (!_reporter) { - try { - _reporter = require(reporter); - } catch (err) { - err.message.indexOf('Cannot find module') !== -1 - ? console.warn('"' + reporter + '" reporter not found') - : console.warn('"' + reporter + '" reporter blew up with error:\n' + err.stack); - } - } - if (!_reporter && reporter === 'teamcity') { - console.warn('The Teamcity reporter was moved to a package named ' - + 'mocha-teamcity-reporter ' - + '(https://npmjs.org/package/mocha-teamcity-reporter).'); - } - if (!_reporter) { - throw new Error('invalid reporter "' + reporter + '"'); - } - this._reporter = _reporter; - } - this.options.reporterOptions = reporterOptions; - return this; - }; - - /** - * Set test UI `name`, defaults to "bdd". - * - * @api public - * @param {string} bdd - */ - Mocha.prototype.ui = function(name) { - name = name || 'bdd'; - this._ui = exports.interfaces[name]; - if (!this._ui) { - try { - this._ui = require(name); - } catch (err) { - throw new Error('invalid interface "' + name + '"'); - } - } - this._ui = this._ui(this.suite); - return this; - }; - - /** - * Load registered files. - * - * @api private - */ - Mocha.prototype.loadFiles = function(fn) { - var self = this; - var suite = this.suite; - var pending = this.files.length; - this.files.forEach(function(file) { - file = path.resolve(file); - suite.emit('pre-require', global, file, self); - suite.emit('require', require(file), file, self); - suite.emit('post-require', global, file, self); - --pending || (fn && fn()); - }); - }; - - /** - * Enable growl support. - * - * @api private - */ - Mocha.prototype._growl = function(runner, reporter) { - var notify = require('growl'); - - runner.on('end', function() { - var stats = reporter.stats; - if (stats.failures) { - var msg = stats.failures + ' of ' + runner.total + ' tests failed'; - notify(msg, { - name: 'mocha', - title: 'Failed', - image: image('error') - }); - } else { - notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', { - name: 'mocha', - title: 'Passed', - image: image('ok') - }); - } - }); - }; - - /** - * Add regexp to grep, if `re` is a string it is escaped. - * - * @param {RegExp|String} re - * @return {Mocha} - * @api public - * @param {RegExp|string} re - * @return {Mocha} - */ - Mocha.prototype.grep = function(re) { - this.options.grep = typeof re === 'string' ? new RegExp(escapeRe(re)) : re; - return this; - }; - - /** - * Invert `.grep()` matches. - * - * @return {Mocha} - * @api public - */ - Mocha.prototype.invert = function() { - this.options.invert = true; - return this; - }; - - /** - * Ignore global leaks. - * - * @param {Boolean} ignore - * @return {Mocha} - * @api public - * @param {boolean} ignore - * @return {Mocha} - */ - Mocha.prototype.ignoreLeaks = function(ignore) { - this.options.ignoreLeaks = Boolean(ignore); - return this; - }; - - /** - * Enable global leak checking. - * - * @return {Mocha} - * @api public - */ - Mocha.prototype.checkLeaks = function() { - this.options.ignoreLeaks = false; - return this; - }; - - /** - * Display long stack-trace on failing - * - * @return {Mocha} - * @api public - */ - Mocha.prototype.fullTrace = function() { - this.options.fullStackTrace = true; - return this; - }; - - /** - * Enable growl support. - * - * @return {Mocha} - * @api public - */ - Mocha.prototype.growl = function() { - this.options.growl = true; - return this; - }; - - /** - * Ignore `globals` array or string. - * - * @param {Array|String} globals - * @return {Mocha} - * @api public - * @param {Array|string} globals - * @return {Mocha} - */ - Mocha.prototype.globals = function(globals) { - this.options.globals = (this.options.globals || []).concat(globals); - return this; - }; - - /** - * Emit color output. - * - * @param {Boolean} colors - * @return {Mocha} - * @api public - * @param {boolean} colors - * @return {Mocha} - */ - Mocha.prototype.useColors = function(colors) { - if (colors !== undefined) { - this.options.useColors = colors; - } - return this; - }; - - /** - * Use inline diffs rather than +/-. - * - * @param {Boolean} inlineDiffs - * @return {Mocha} - * @api public - * @param {boolean} inlineDiffs - * @return {Mocha} - */ - Mocha.prototype.useInlineDiffs = function(inlineDiffs) { - this.options.useInlineDiffs = inlineDiffs !== undefined && inlineDiffs; - return this; - }; - - /** - * Set the timeout in milliseconds. - * - * @param {Number} timeout - * @return {Mocha} - * @api public - * @param {number} timeout - * @return {Mocha} - */ - Mocha.prototype.timeout = function(timeout) { - this.suite.timeout(timeout); - return this; - }; - - /** - * Set slowness threshold in milliseconds. - * - * @param {Number} slow - * @return {Mocha} - * @api public - * @param {number} slow - * @return {Mocha} - */ - Mocha.prototype.slow = function(slow) { - this.suite.slow(slow); - return this; - }; - - /** - * Enable timeouts. - * - * @param {Boolean} enabled - * @return {Mocha} - * @api public - * @param {boolean} enabled - * @return {Mocha} - */ - Mocha.prototype.enableTimeouts = function(enabled) { - this.suite.enableTimeouts(arguments.length && enabled !== undefined ? enabled : true); - return this; - }; - - /** - * Makes all tests async (accepting a callback) - * - * @return {Mocha} - * @api public - */ - Mocha.prototype.asyncOnly = function() { - this.options.asyncOnly = true; - return this; - }; - - /** - * Disable syntax highlighting (in browser). - * - * @api public - */ - Mocha.prototype.noHighlighting = function() { - this.options.noHighlighting = true; - return this; - }; - - /** - * Enable uncaught errors to propagate (in browser). - * - * @return {Mocha} - * @api public - */ - Mocha.prototype.allowUncaught = function() { - this.options.allowUncaught = true; - return this; - }; - - /** - * Delay root suite execution. - * @returns {Mocha} - */ - Mocha.prototype.delay = function delay() { - this.options.delay = true; - return this; - }; - - /** - * Run tests and invoke `fn()` when complete. - * - * @api public - * @param {Function} fn - * @return {Runner} - */ - Mocha.prototype.run = function(fn) { - if (this.files.length) { - this.loadFiles(); - } - var suite = this.suite; - var options = this.options; - options.files = this.files; - var runner = new exports.Runner(suite, options.delay); - var reporter = new this._reporter(runner, options); - runner.ignoreLeaks = options.ignoreLeaks !== false; - runner.fullStackTrace = options.fullStackTrace; - runner.asyncOnly = options.asyncOnly; - runner.allowUncaught = options.allowUncaught; - if (options.grep) { - runner.grep(options.grep, options.invert); - } - if (options.globals) { - runner.globals(options.globals); - } - if (options.growl) { - this._growl(runner, reporter); - } - if (options.useColors !== undefined) { - exports.reporters.Base.useColors = options.useColors; - } - exports.reporters.Base.inlineDiffs = options.useInlineDiffs; - - function done(failures) { - if (reporter.done) { - reporter.done(failures, fn); - } else { - fn && fn(failures); - } - } - - return runner.run(done); - }; - - }).call(this, require('_process'), typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}, "/lib") - }, { - "./context": 6, - "./hook": 7, - "./interfaces": 11, - "./reporters": 22, - "./runnable": 35, - "./runner": 36, - "./suite": 37, - "./test": 38, - "./utils": 39, - "_process": 51, - "escape-string-regexp": 68, - "growl": 69, - "path": 41 - }], - 15: [function(require, module, exports) { - /** - * Helpers. - */ - - var s = 1000; - var m = s * 60; - var h = m * 60; - var d = h * 24; - var y = d * 365.25; - - /** - * Parse or format the given `val`. - * - * Options: - * - * - `long` verbose formatting [false] - * - * @api public - * @param {string|number} val - * @param {Object} options - * @return {string|number} - */ - module.exports = function(val, options) { - options = options || {}; - if (typeof val === 'string') { - return parse(val); - } - // https://github.com/mochajs/mocha/pull/1035 - return options['long'] ? longFormat(val) : shortFormat(val); - }; - - /** - * Parse the given `str` and return milliseconds. - * - * @api private - * @param {string} str - * @return {number} - */ - function parse(str) { - var match = (/^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i).exec(str); - if (!match) { - return; - } - var n = parseFloat(match[1]); - var type = (match[2] || 'ms').toLowerCase(); - switch (type) { - case 'years': - case 'year': - case 'y': - return n * y; - case 'days': - case 'day': - case 'd': - return n * d; - case 'hours': - case 'hour': - case 'h': - return n * h; - case 'minutes': - case 'minute': - case 'm': - return n * m; - case 'seconds': - case 'second': - case 's': - return n * s; - case 'ms': - return n; - default: - // No default case - } - } - - /** - * Short format for `ms`. - * - * @api private - * @param {number} ms - * @return {string} - */ - function shortFormat(ms) { - if (ms >= d) { - return Math.round(ms / d) + 'd'; - } - if (ms >= h) { - return Math.round(ms / h) + 'h'; - } - if (ms >= m) { - return Math.round(ms / m) + 'm'; - } - if (ms >= s) { - return Math.round(ms / s) + 's'; - } - return ms + 'ms'; - } - - /** - * Long format for `ms`. - * - * @api private - * @param {number} ms - * @return {string} - */ - function longFormat(ms) { - return plural(ms, d, 'day') - || plural(ms, h, 'hour') - || plural(ms, m, 'minute') - || plural(ms, s, 'second') - || ms + ' ms'; - } - - /** - * Pluralization helper. - * - * @api private - * @param {number} ms - * @param {number} n - * @param {string} name - */ - function plural(ms, n, name) { - if (ms < n) { - return; - } - if (ms < n * 1.5) { - return Math.floor(ms / n) + ' ' + name; - } - return Math.ceil(ms / n) + ' ' + name + 's'; - } - - }, {}], - 16: [function(require, module, exports) { - - /** - * Expose `Pending`. - */ - - module.exports = Pending; - - /** - * Initialize a new `Pending` error with the given message. - * - * @param {string} message - */ - function Pending(message) { - this.message = message; - } - - }, {}], - 17: [function(require, module, exports) { - (function(process, global) { - /** - * Module dependencies. - */ - - var tty = require('tty'); - var diff = require('diff'); - var ms = require('../ms'); - var utils = require('../utils'); - var supportsColor = process.browser ? null : require('supports-color'); - - /** - * Expose `Base`. - */ - - exports = module.exports = Base; - - /** - * Save timer references to avoid Sinon interfering. - * See: https://github.com/mochajs/mocha/issues/237 - */ - - /* eslint-disable no-unused-vars, no-native-reassign */ - var Date = global.Date; - var setTimeout = global.setTimeout; - var setInterval = global.setInterval; - var clearTimeout = global.clearTimeout; - var clearInterval = global.clearInterval; - /* eslint-enable no-unused-vars, no-native-reassign */ - - /** - * Check if both stdio streams are associated with a tty. - */ - - var isatty = tty.isatty(1) && tty.isatty(2); - - /** - * Enable coloring by default, except in the browser interface. - */ - - exports.useColors = !process.browser && (supportsColor || (process.env.MOCHA_COLORS !== undefined)); - - /** - * Inline diffs instead of +/- - */ - - exports.inlineDiffs = false; - - /** - * Default color map. - */ - - exports.colors = { - pass: 90, - fail: 31, - 'bright pass': 92, - 'bright fail': 91, - 'bright yellow': 93, - pending: 36, - suite: 0, - 'error title': 0, - 'error message': 31, - 'error stack': 90, - checkmark: 32, - fast: 90, - medium: 33, - slow: 31, - green: 32, - light: 90, - 'diff gutter': 90, - 'diff added': 32, - 'diff removed': 31 - }; - - /** - * Default symbol map. - */ - - exports.symbols = { - ok: '✓', - err: '✖', - dot: '․' - }; - - // With node.js on Windows: use symbols available in terminal default fonts - if (process.platform === 'win32') { - exports.symbols.ok = '\u221A'; - exports.symbols.err = '\u00D7'; - exports.symbols.dot = '.'; - } - - /** - * Color `str` with the given `type`, - * allowing colors to be disabled, - * as well as user-defined color - * schemes. - * - * @param {string} type - * @param {string} str - * @return {string} - * @api private - */ - var color = exports.color = function(type, str) { - if (!exports.useColors) { - return String(str); - } - return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m'; - }; - - /** - * Expose term window size, with some defaults for when stderr is not a tty. - */ - - exports.window = { - width: 75 - }; - - if (isatty) { - exports.window.width = process.stdout.getWindowSize - ? process.stdout.getWindowSize(1)[0] - : tty.getWindowSize()[1]; - } - - /** - * Expose some basic cursor interactions that are common among reporters. - */ - - exports.cursor = { - hide: function() { - isatty && process.stdout.write('\u001b[?25l'); - }, - - show: function() { - isatty && process.stdout.write('\u001b[?25h'); - }, - - deleteLine: function() { - isatty && process.stdout.write('\u001b[2K'); - }, - - beginningOfLine: function() { - isatty && process.stdout.write('\u001b[0G'); - }, - - CR: function() { - if (isatty) { - exports.cursor.deleteLine(); - exports.cursor.beginningOfLine(); - } else { - process.stdout.write('\r'); - } - } - }; - - /** - * Outut the given `failures` as a list. - * - * @param {Array} failures - * @api public - */ - - exports.list = function(failures) { - console.log(); - failures.forEach(function(test, i) { - // format - var fmt = color('error title', ' %s) %s:\n') - + color('error message', ' %s') - + color('error stack', '\n%s\n'); - - // msg - var msg; - var err = test.err; - var message; - if (err.message) { - message = err.message; - } else if (typeof err.inspect === 'function') { - message = err.inspect() + ''; - } else { - message = ''; - } - var stack = err.stack || message; - var index = stack.indexOf(message); - var actual = err.actual; - var expected = err.expected; - var escape = true; - - if (index === -1) { - msg = message; - } else { - index += message.length; - msg = stack.slice(0, index); - // remove msg from stack - stack = stack.slice(index + 1); - } - - // uncaught - if (err.uncaught) { - msg = 'Uncaught ' + msg; - } - // explicitly show diff - if (err.showDiff !== false && sameType(actual, expected) && expected !== undefined) { - escape = false; - if (!(utils.isString(actual) && utils.isString(expected))) { - err.actual = actual = utils.stringify(actual); - err.expected = expected = utils.stringify(expected); - } - - fmt = color('error title', ' %s) %s:\n%s') + color('error stack', '\n%s\n'); - var match = message.match(/^([^:]+): expected/); - msg = '\n ' + color('error message', match ? match[1] : msg); - - if (exports.inlineDiffs) { - msg += inlineDiff(err, escape); - } else { - msg += unifiedDiff(err, escape); - } - } - - // indent stack trace - stack = stack.replace(/^/gm, ' '); - - console.log(fmt, (i + 1), test.fullTitle(), msg, stack); - }); - }; - - /** - * Initialize a new `Base` reporter. - * - * All other reporters generally - * inherit from this reporter, providing - * stats such as test duration, number - * of tests passed / failed etc. - * - * @param {Runner} runner - * @api public - */ - - function Base(runner) { - var stats = this.stats = { - suites: 0, - tests: 0, - passes: 0, - pending: 0, - failures: 0 - }; - var failures = this.failures = []; - - if (!runner) { - return; - } - this.runner = runner; - - runner.stats = stats; - - runner.on('start', function() { - stats.start = new Date(); - }); - - runner.on('suite', function(suite) { - stats.suites = stats.suites || 0; - suite.root || stats.suites++; - }); - - runner.on('test end', function() { - stats.tests = stats.tests || 0; - stats.tests++; - }); - - runner.on('pass', function(test) { - stats.passes = stats.passes || 0; - - if (test.duration > test.slow()) { - test.speed = 'slow'; - } else if (test.duration > test.slow() / 2) { - test.speed = 'medium'; - } else { - test.speed = 'fast'; - } - - stats.passes++; - }); - - runner.on('fail', function(test, err) { - stats.failures = stats.failures || 0; - stats.failures++; - test.err = err; - failures.push(test); - }); - - runner.on('end', function() { - stats.end = new Date(); - stats.duration = new Date() - stats.start; - }); - - runner.on('pending', function() { - stats.pending++; - }); - } - - /** - * Output common epilogue used by many of - * the bundled reporters. - * - * @api public - */ - Base.prototype.epilogue = function() { - var stats = this.stats; - var fmt; - - console.log(); - - // passes - fmt = color('bright pass', ' ') - + color('green', ' %d passing') - + color('light', ' (%s)'); - - console.log(fmt, - stats.passes || 0, - ms(stats.duration)); - - // pending - if (stats.pending) { - fmt = color('pending', ' ') - + color('pending', ' %d pending'); - - console.log(fmt, stats.pending); - } - - // failures - if (stats.failures) { - fmt = color('fail', ' %d failing'); - - console.log(fmt, stats.failures); - - Base.list(this.failures); - console.log(); - } - - console.log(); - }; - - /** - * Pad the given `str` to `len`. - * - * @api private - * @param {string} str - * @param {string} len - * @return {string} - */ - function pad(str, len) { - str = String(str); - return Array(len - str.length + 1).join(' ') + str; - } - - /** - * Returns an inline diff between 2 strings with coloured ANSI output - * - * @api private - * @param {Error} err with actual/expected - * @param {boolean} escape - * @return {string} Diff - */ - function inlineDiff(err, escape) { - var msg = errorDiff(err, 'WordsWithSpace', escape); - - // linenos - var lines = msg.split('\n'); - if (lines.length > 4) { - var width = String(lines.length).length; - msg = lines.map(function(str, i) { - return pad(++i, width) + ' |' + ' ' + str; - }).join('\n'); - } - - // legend - msg = '\n' - + color('diff removed', 'actual') - + ' ' - + color('diff added', 'expected') - + '\n\n' - + msg - + '\n'; - - // indent - msg = msg.replace(/^/gm, ' '); - return msg; - } - - /** - * Returns a unified diff between two strings. - * - * @api private - * @param {Error} err with actual/expected - * @param {boolean} escape - * @return {string} The diff. - */ - function unifiedDiff(err, escape) { - var indent = ' '; - function cleanUp(line) { - if (escape) { - line = escapeInvisibles(line); - } - if (line[0] === '+') { - return indent + colorLines('diff added', line); - } - if (line[0] === '-') { - return indent + colorLines('diff removed', line); - } - if (line.match(/\@\@/)) { - return null; - } - if (line.match(/\\ No newline/)) { - return null; - } - return indent + line; - } - function notBlank(line) { - return typeof line !== 'undefined' && line !== null; - } - var msg = diff.createPatch('string', err.actual, err.expected); - var lines = msg.split('\n').splice(4); - return '\n ' - + colorLines('diff added', '+ expected') + ' ' - + colorLines('diff removed', '- actual') - + '\n\n' - + lines.map(cleanUp).filter(notBlank).join('\n'); - } - - /** - * Return a character diff for `err`. - * - * @api private - * @param {Error} err - * @param {string} type - * @param {boolean} escape - * @return {string} - */ - function errorDiff(err, type, escape) { - var actual = escape ? escapeInvisibles(err.actual) : err.actual; - var expected = escape ? escapeInvisibles(err.expected) : err.expected; - return diff['diff' + type](actual, expected).map(function(str) { - if (str.added) { - return colorLines('diff added', str.value); - } - if (str.removed) { - return colorLines('diff removed', str.value); - } - return str.value; - }).join(''); - } - - /** - * Returns a string with all invisible characters in plain text - * - * @api private - * @param {string} line - * @return {string} - */ - function escapeInvisibles(line) { - return line.replace(/\t/g, '') - .replace(/\r/g, '') - .replace(/\n/g, '\n'); - } - - /** - * Color lines for `str`, using the color `name`. - * - * @api private - * @param {string} name - * @param {string} str - * @return {string} - */ - function colorLines(name, str) { - return str.split('\n').map(function(str) { - return color(name, str); - }).join('\n'); - } - - /** - * Object#toString reference. - */ - var objToString = Object.prototype.toString; - - /** - * Check that a / b have the same type. - * - * @api private - * @param {Object} a - * @param {Object} b - * @return {boolean} - */ - function sameType(a, b) { - return objToString.call(a) === objToString.call(b); - } - - }).call(this, require('_process'), typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) - }, { - "../ms": 15, - "../utils": 39, - "_process": 51, - "diff": 67, - "supports-color": 41, - "tty": 5 - }], - 18: [function(require, module, exports) { - /** - * Module dependencies. - */ - - var Base = require('./base'); - var utils = require('../utils'); - - /** - * Expose `Doc`. - */ - - exports = module.exports = Doc; - - /** - * Initialize a new `Doc` reporter. - * - * @param {Runner} runner - * @api public - */ - function Doc(runner) { - Base.call(this, runner); - - var indents = 2; - - function indent() { - return Array(indents).join(' '); - } - - runner.on('suite', function(suite) { - if (suite.root) { - return; - } - ++indents; - console.log('%s
', indent()); - ++indents; - console.log('%s

%s

', indent(), utils.escape(suite.title)); - console.log('%s
', indent()); - }); - - runner.on('suite end', function(suite) { - if (suite.root) { - return; - } - console.log('%s
', indent()); - --indents; - console.log('%s
', indent()); - --indents; - }); - - runner.on('pass', function(test) { - console.log('%s
%s
', indent(), utils.escape(test.title)); - var code = utils.escape(utils.clean(test.fn.toString())); - console.log('%s
%s
', indent(), code); - }); - - runner.on('fail', function(test, err) { - console.log('%s
%s
', indent(), utils.escape(test.title)); - var code = utils.escape(utils.clean(test.fn.toString())); - console.log('%s
%s
', indent(), code); - console.log('%s
%s
', indent(), utils.escape(err)); - }); - } - - }, { - "../utils": 39, - "./base": 17 - }], - 19: [function(require, module, exports) { - (function(process) { - /** - * Module dependencies. - */ - - var Base = require('./base'); - var inherits = require('../utils').inherits; - var color = Base.color; - - /** - * Expose `Dot`. - */ - - exports = module.exports = Dot; - - /** - * Initialize a new `Dot` matrix test reporter. - * - * @api public - * @param {Runner} runner - */ - function Dot(runner) { - Base.call(this, runner); - - var self = this; - var width = Base.window.width * .75 | 0; - var n = -1; - - runner.on('start', function() { - process.stdout.write('\n'); - }); - - runner.on('pending', function() { - if (++n % width === 0) { - process.stdout.write('\n '); - } - process.stdout.write(color('pending', Base.symbols.dot)); - }); - - runner.on('pass', function(test) { - if (++n % width === 0) { - process.stdout.write('\n '); - } - if (test.speed === 'slow') { - process.stdout.write(color('bright yellow', Base.symbols.dot)); - } else { - process.stdout.write(color(test.speed, Base.symbols.dot)); - } - }); - - runner.on('fail', function() { - if (++n % width === 0) { - process.stdout.write('\n '); - } - process.stdout.write(color('fail', Base.symbols.dot)); - }); - - runner.on('end', function() { - console.log(); - self.epilogue(); - }); - } - - /** - * Inherit from `Base.prototype`. - */ - inherits(Dot, Base); - - }).call(this, require('_process')) - }, { - "../utils": 39, - "./base": 17, - "_process": 51 - }], - 20: [function(require, module, exports) { - (function(process, __dirname) { - /** - * Module dependencies. - */ - - var JSONCov = require('./json-cov'); - var readFileSync = require('fs').readFileSync; - var join = require('path').join; - - /** - * Expose `HTMLCov`. - */ - - exports = module.exports = HTMLCov; - - /** - * Initialize a new `JsCoverage` reporter. - * - * @api public - * @param {Runner} runner - */ - function HTMLCov(runner) { - var jade = require('jade'); - var file = join(__dirname, '/templates/coverage.jade'); - var str = readFileSync(file, 'utf8'); - var fn = jade.compile(str, { - filename: file - }); - var self = this; - - JSONCov.call(this, runner, false); - - runner.on('end', function() { - process.stdout.write(fn({ - cov: self.cov, - coverageClass: coverageClass - })); - }); - } - - /** - * Return coverage class for a given coverage percentage. - * - * @api private - * @param {number} coveragePctg - * @return {string} - */ - function coverageClass(coveragePctg) { - if (coveragePctg >= 75) { - return 'high'; - } - if (coveragePctg >= 50) { - return 'medium'; - } - if (coveragePctg >= 25) { - return 'low'; - } - return 'terrible'; - } - - }).call(this, require('_process'), "/lib/reporters") - }, { - "./json-cov": 23, - "_process": 51, - "fs": 41, - "jade": 41, - "path": 41 - }], - 21: [function(require, module, exports) { - (function(global) { - /* eslint-env browser */ - - /** - * Module dependencies. - */ - - var Base = require('./base'); - var utils = require('../utils'); - var Progress = require('../browser/progress'); - var escapeRe = require('escape-string-regexp'); - var escape = utils.escape; - - /** - * Save timer references to avoid Sinon interfering (see GH-237). - */ - - /* eslint-disable no-unused-vars, no-native-reassign */ - var Date = global.Date; - var setTimeout = global.setTimeout; - var setInterval = global.setInterval; - var clearTimeout = global.clearTimeout; - var clearInterval = global.clearInterval; - /* eslint-enable no-unused-vars, no-native-reassign */ - - /** - * Expose `HTML`. - */ - - exports = module.exports = HTML; - - /** - * Stats template. - */ - - var statsTemplate = ''; - - /** - * Initialize a new `HTML` reporter. - * - * @api public - * @param {Runner} runner - */ - function HTML(runner) { - Base.call(this, runner); - - var self = this; - var stats = this.stats; - var stat = fragment(statsTemplate); - var items = stat.getElementsByTagName('li'); - var passes = items[1].getElementsByTagName('em')[0]; - var passesLink = items[1].getElementsByTagName('a')[0]; - var failures = items[2].getElementsByTagName('em')[0]; - var failuresLink = items[2].getElementsByTagName('a')[0]; - var duration = items[3].getElementsByTagName('em')[0]; - var canvas = stat.getElementsByTagName('canvas')[0]; - var report = fragment('
    '); - var stack = [report]; - var progress; - var ctx; - var root = document.getElementById('mocha'); - - if (canvas.getContext) { - var ratio = window.devicePixelRatio || 1; - canvas.style.width = canvas.width; - canvas.style.height = canvas.height; - canvas.width *= ratio; - canvas.height *= ratio; - ctx = canvas.getContext('2d'); - ctx.scale(ratio, ratio); - progress = new Progress(); - } - - if (!root) { - return error('#mocha div missing, add it to your document'); - } - - // pass toggle - on(passesLink, 'click', function() { - unhide(); - var name = (/pass/).test(report.className) ? '' : ' pass'; - report.className = report.className.replace(/fail|pass/g, '') + name; - if (report.className.trim()) { - hideSuitesWithout('test pass'); - } - }); - - // failure toggle - on(failuresLink, 'click', function() { - unhide(); - var name = (/fail/).test(report.className) ? '' : ' fail'; - report.className = report.className.replace(/fail|pass/g, '') + name; - if (report.className.trim()) { - hideSuitesWithout('test fail'); - } - }); - - root.appendChild(stat); - root.appendChild(report); - - if (progress) { - progress.size(40); - } - - runner.on('suite', function(suite) { - if (suite.root) { - return; - } - - // suite - var url = self.suiteURL(suite); - var el = fragment('
  • %s

  • ', url, escape(suite.title)); - - // container - stack[0].appendChild(el); - stack.unshift(document.createElement('ul')); - el.appendChild(stack[0]); - }); - - runner.on('suite end', function(suite) { - if (suite.root) { - return; - } - stack.shift(); - }); - - runner.on('fail', function(test) { - if (test.type === 'hook') { - runner.emit('test end', test); - } - }); - - runner.on('test end', function(test) { - // TODO: add to stats - var percent = stats.tests / this.total * 100 | 0; - if (progress) { - progress.update(percent).draw(ctx); - } - - // update stats - var ms = new Date() - stats.start; - text(passes, stats.passes); - text(failures, stats.failures); - text(duration, (ms / 1000).toFixed(2)); - - // test - var el; - if (test.state === 'passed') { - var url = self.testURL(test); - el = fragment('
  • %e%ems

  • ', test.speed, test.title, test.duration, url); - } else if (test.pending) { - el = fragment('
  • %e

  • ', test.title); - } else { - el = fragment('
  • %e

  • ', test.title, self.testURL(test)); - var stackString; // Note: Includes leading newline - var message = test.err.toString(); - - // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we - // check for the result of the stringifying. - if (message === '[object Error]') { - message = test.err.message; - } - - if (test.err.stack) { - var indexOfMessage = test.err.stack.indexOf(test.err.message); - if (indexOfMessage === -1) { - stackString = test.err.stack; - } else { - stackString = test.err.stack.substr(test.err.message.length + indexOfMessage); - } - } else if (test.err.sourceURL && test.err.line !== undefined) { - // Safari doesn't give you a stack. Let's at least provide a source line. - stackString = '\n(' + test.err.sourceURL + ':' + test.err.line + ')'; - } - - stackString = stackString || ''; - - if (test.err.htmlMessage && stackString) { - el.appendChild(fragment('
    %s\n
    %e
    ', test.err.htmlMessage, stackString)); - } else if (test.err.htmlMessage) { - el.appendChild(fragment('
    %s
    ', test.err.htmlMessage)); - } else { - el.appendChild(fragment('
    %e%e
    ', message, stackString)); - } - } - - // toggle code - // TODO: defer - if (!test.pending) { - var h2 = el.getElementsByTagName('h2')[0]; - - on(h2, 'click', function() { - pre.style.display = pre.style.display === 'none' ? 'block' : 'none'; - }); - - var pre = fragment('
    %e
    ', utils.clean(test.fn.toString())); - el.appendChild(pre); - pre.style.display = 'none'; - } - - // Don't call .appendChild if #mocha-report was already .shift()'ed off the stack. - if (stack[0]) { - stack[0].appendChild(el); - } - }); - } - - /** - * Makes a URL, preserving querystring ("search") parameters. - * - * @param {string} s - * @return {string} A new URL. - */ - function makeUrl(s) { - var search = window.location.search; - - // Remove previous grep query parameter if present - if (search) { - search = search.replace(/[?&]grep=[^&\s]*/g, '').replace(/^&/, '?'); - } - - return window.location.pathname + (search ? search + '&' : '?') + 'grep=' + encodeURIComponent(escapeRe(s)); - } - - /** - * Provide suite URL. - * - * @param {Object} [suite] - */ - HTML.prototype.suiteURL = function(suite) { - return makeUrl(suite.fullTitle()); - }; - - /** - * Provide test URL. - * - * @param {Object} [test] - */ - HTML.prototype.testURL = function(test) { - return makeUrl(test.fullTitle()); - }; - - /** - * Display error `msg`. - * - * @param {string} msg - */ - function error(msg) { - document.body.appendChild(fragment('
    %s
    ', msg)); - } - - /** - * Return a DOM fragment from `html`. - * - * @param {string} html - */ - function fragment(html) { - var args = arguments; - var div = document.createElement('div'); - var i = 1; - - div.innerHTML = html.replace(/%([se])/g, function(_, type) { - switch (type) { - case 's': - return String(args[i++]); - case 'e': - return escape(args[i++]); - // no default - } - }); - - return div.firstChild; - } - - /** - * Check for suites that do not have elements - * with `classname`, and hide them. - * - * @param {text} classname - */ - function hideSuitesWithout(classname) { - var suites = document.getElementsByClassName('suite'); - for (var i = 0; i < suites.length; i++) { - var els = suites[i].getElementsByClassName(classname); - if (!els.length) { - suites[i].className += ' hidden'; - } - } - } - - /** - * Unhide .hidden suites. - */ - function unhide() { - var els = document.getElementsByClassName('suite hidden'); - for (var i = 0; i < els.length; ++i) { - els[i].className = els[i].className.replace('suite hidden', 'suite'); - } - } - - /** - * Set an element's text contents. - * - * @param {HTMLElement} el - * @param {string} contents - */ - function text(el, contents) { - if (el.textContent) { - el.textContent = contents; - } else { - el.innerText = contents; - } - } - - /** - * Listen on `event` with callback `fn`. - */ - function on(el, event, fn) { - if (el.addEventListener) { - el.addEventListener(event, fn, false); - } else { - el.attachEvent('on' + event, fn); - } - } - - }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) - }, { - "../browser/progress": 4, - "../utils": 39, - "./base": 17, - "escape-string-regexp": 68 - }], - 22: [function(require, module, exports) { - // Alias exports to a their normalized format Mocha#reporter to prevent a need - // for dynamic (try/catch) requires, which Browserify doesn't handle. - exports.Base = exports.base = require('./base'); - exports.Dot = exports.dot = require('./dot'); - exports.Doc = exports.doc = require('./doc'); - exports.TAP = exports.tap = require('./tap'); - exports.JSON = exports.json = require('./json'); - exports.HTML = exports.html = require('./html'); - exports.List = exports.list = require('./list'); - exports.Min = exports.min = require('./min'); - exports.Spec = exports.spec = require('./spec'); - exports.Nyan = exports.nyan = require('./nyan'); - exports.XUnit = exports.xunit = require('./xunit'); - exports.Markdown = exports.markdown = require('./markdown'); - exports.Progress = exports.progress = require('./progress'); - exports.Landing = exports.landing = require('./landing'); - exports.JSONCov = exports['json-cov'] = require('./json-cov'); - exports.HTMLCov = exports['html-cov'] = require('./html-cov'); - exports.JSONStream = exports['json-stream'] = require('./json-stream'); - - }, { - "./base": 17, - "./doc": 18, - "./dot": 19, - "./html": 21, - "./html-cov": 20, - "./json": 25, - "./json-cov": 23, - "./json-stream": 24, - "./landing": 26, - "./list": 27, - "./markdown": 28, - "./min": 29, - "./nyan": 30, - "./progress": 31, - "./spec": 32, - "./tap": 33, - "./xunit": 34 - }], - 23: [function(require, module, exports) { - (function(process, global) { - /** - * Module dependencies. - */ - - var Base = require('./base'); - - /** - * Expose `JSONCov`. - */ - - exports = module.exports = JSONCov; - - /** - * Initialize a new `JsCoverage` reporter. - * - * @api public - * @param {Runner} runner - * @param {boolean} output - */ - function JSONCov(runner, output) { - Base.call(this, runner); - - output = arguments.length === 1 || output; - var self = this; - var tests = []; - var failures = []; - var passes = []; - - runner.on('test end', function(test) { - tests.push(test); - }); - - runner.on('pass', function(test) { - passes.push(test); - }); - - runner.on('fail', function(test) { - failures.push(test); - }); - - runner.on('end', function() { - var cov = global._$jscoverage || {}; - var result = self.cov = map(cov); - result.stats = self.stats; - result.tests = tests.map(clean); - result.failures = failures.map(clean); - result.passes = passes.map(clean); - if (!output) { - return; - } - process.stdout.write(JSON.stringify(result, null, 2)); - }); - } - - /** - * Map jscoverage data to a JSON structure - * suitable for reporting. - * - * @api private - * @param {Object} cov - * @return {Object} - */ - - function map(cov) { - var ret = { - instrumentation: 'node-jscoverage', - sloc: 0, - hits: 0, - misses: 0, - coverage: 0, - files: [] - }; - - for (var filename in cov) { - if (Object.prototype.hasOwnProperty.call(cov, filename)) { - var data = coverage(filename, cov[filename]); - ret.files.push(data); - ret.hits += data.hits; - ret.misses += data.misses; - ret.sloc += data.sloc; - } - } - - ret.files.sort(function(a, b) { - return a.filename.localeCompare(b.filename); - }); - - if (ret.sloc > 0) { - ret.coverage = (ret.hits / ret.sloc) * 100; - } - - return ret; - } - - /** - * Map jscoverage data for a single source file - * to a JSON structure suitable for reporting. - * - * @api private - * @param {string} filename name of the source file - * @param {Object} data jscoverage coverage data - * @return {Object} - */ - function coverage(filename, data) { - var ret = { - filename: filename, - coverage: 0, - hits: 0, - misses: 0, - sloc: 0, - source: {} - }; - - data.source.forEach(function(line, num) { - num++; - - if (data[num] === 0) { - ret.misses++; - ret.sloc++; - } else if (data[num] !== undefined) { - ret.hits++; - ret.sloc++; - } - - ret.source[num] = { - source: line, - coverage: data[num] === undefined ? '' : data[num] - }; - }); - - ret.coverage = ret.hits / ret.sloc * 100; - - return ret; - } - - /** - * Return a plain-object representation of `test` - * free of cyclic properties etc. - * - * @api private - * @param {Object} test - * @return {Object} - */ - function clean(test) { - return { - duration: test.duration, - fullTitle: test.fullTitle(), - title: test.title - }; - } - - }).call(this, require('_process'), typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) - }, { - "./base": 17, - "_process": 51 - }], - 24: [function(require, module, exports) { - (function(process) { - /** - * Module dependencies. - */ - - var Base = require('./base'); - - /** - * Expose `List`. - */ - - exports = module.exports = List; - - /** - * Initialize a new `List` test reporter. - * - * @api public - * @param {Runner} runner - */ - function List(runner) { - Base.call(this, runner); - - var self = this; - var total = runner.total; - - runner.on('start', function() { - console.log(JSON.stringify(['start', { - total: total - }])); - }); - - runner.on('pass', function(test) { - console.log(JSON.stringify(['pass', clean(test)])); - }); - - runner.on('fail', function(test, err) { - test = clean(test); - test.err = err.message; - test.stack = err.stack || null; - console.log(JSON.stringify(['fail', test])); - }); - - runner.on('end', function() { - process.stdout.write(JSON.stringify(['end', self.stats])); - }); - } - - /** - * Return a plain-object representation of `test` - * free of cyclic properties etc. - * - * @api private - * @param {Object} test - * @return {Object} - */ - function clean(test) { - return { - title: test.title, - fullTitle: test.fullTitle(), - duration: test.duration - }; - } - - }).call(this, require('_process')) - }, { - "./base": 17, - "_process": 51 - }], - 25: [function(require, module, exports) { - (function(process) { - /** - * Module dependencies. - */ - - var Base = require('./base'); - - /** - * Expose `JSON`. - */ - - exports = module.exports = JSONReporter; - - /** - * Initialize a new `JSON` reporter. - * - * @api public - * @param {Runner} runner - */ - function JSONReporter(runner) { - Base.call(this, runner); - - var self = this; - var tests = []; - var pending = []; - var failures = []; - var passes = []; - - runner.on('test end', function(test) { - tests.push(test); - }); - - runner.on('pass', function(test) { - passes.push(test); - }); - - runner.on('fail', function(test) { - failures.push(test); - }); - - runner.on('pending', function(test) { - pending.push(test); - }); - - runner.on('end', function() { - var obj = { - stats: self.stats, - tests: tests.map(clean), - pending: pending.map(clean), - failures: failures.map(clean), - passes: passes.map(clean) - }; - - runner.testResults = obj; - - process.stdout.write(JSON.stringify(obj, null, 2)); - }); - } - - /** - * Return a plain-object representation of `test` - * free of cyclic properties etc. - * - * @api private - * @param {Object} test - * @return {Object} - */ - function clean(test) { - return { - title: test.title, - fullTitle: test.fullTitle(), - duration: test.duration, - err: errorJSON(test.err || {}) - }; - } - - /** - * Transform `error` into a JSON object. - * - * @api private - * @param {Error} err - * @return {Object} - */ - function errorJSON(err) { - var res = {}; - Object.getOwnPropertyNames(err).forEach(function(key) { - res[key] = err[key]; - }, err); - return res; - } - - }).call(this, require('_process')) - }, { - "./base": 17, - "_process": 51 - }], - 26: [function(require, module, exports) { - (function(process) { - /** - * Module dependencies. - */ - - var Base = require('./base'); - var inherits = require('../utils').inherits; - var cursor = Base.cursor; - var color = Base.color; - - /** - * Expose `Landing`. - */ - - exports = module.exports = Landing; - - /** - * Airplane color. - */ - - Base.colors.plane = 0; - - /** - * Airplane crash color. - */ - - Base.colors['plane crash'] = 31; - - /** - * Runway color. - */ - - Base.colors.runway = 90; - - /** - * Initialize a new `Landing` reporter. - * - * @api public - * @param {Runner} runner - */ - function Landing(runner) { - Base.call(this, runner); - - var self = this; - var width = Base.window.width * .75 | 0; - var total = runner.total; - var stream = process.stdout; - var plane = color('plane', '✈'); - var crashed = -1; - var n = 0; - - function runway() { - var buf = Array(width).join('-'); - return ' ' + color('runway', buf); - } - - runner.on('start', function() { - stream.write('\n\n\n '); - cursor.hide(); - }); - - runner.on('test end', function(test) { - // check if the plane crashed - var col = crashed === -1 ? width * ++n / total | 0 : crashed; - - // show the crash - if (test.state === 'failed') { - plane = color('plane crash', '✈'); - crashed = col; - } - - // render landing strip - stream.write('\u001b[' + (width + 1) + 'D\u001b[2A'); - stream.write(runway()); - stream.write('\n '); - stream.write(color('runway', Array(col).join('⋅'))); - stream.write(plane); - stream.write(color('runway', Array(width - col).join('⋅') + '\n')); - stream.write(runway()); - stream.write('\u001b[0m'); - }); - - runner.on('end', function() { - cursor.show(); - console.log(); - self.epilogue(); - }); - } - - /** - * Inherit from `Base.prototype`. - */ - inherits(Landing, Base); - - }).call(this, require('_process')) - }, { - "../utils": 39, - "./base": 17, - "_process": 51 - }], - 27: [function(require, module, exports) { - (function(process) { - /** - * Module dependencies. - */ - - var Base = require('./base'); - var inherits = require('../utils').inherits; - var color = Base.color; - var cursor = Base.cursor; - - /** - * Expose `List`. - */ - - exports = module.exports = List; - - /** - * Initialize a new `List` test reporter. - * - * @api public - * @param {Runner} runner - */ - function List(runner) { - Base.call(this, runner); - - var self = this; - var n = 0; - - runner.on('start', function() { - console.log(); - }); - - runner.on('test', function(test) { - process.stdout.write(color('pass', ' ' + test.fullTitle() + ': ')); - }); - - runner.on('pending', function(test) { - var fmt = color('checkmark', ' -') - + color('pending', ' %s'); - console.log(fmt, test.fullTitle()); - }); - - runner.on('pass', function(test) { - var fmt = color('checkmark', ' ' + Base.symbols.dot) - + color('pass', ' %s: ') - + color(test.speed, '%dms'); - cursor.CR(); - console.log(fmt, test.fullTitle(), test.duration); - }); - - runner.on('fail', function(test) { - cursor.CR(); - console.log(color('fail', ' %d) %s'), ++n, test.fullTitle()); - }); - - runner.on('end', self.epilogue.bind(self)); - } - - /** - * Inherit from `Base.prototype`. - */ - inherits(List, Base); - - }).call(this, require('_process')) - }, { - "../utils": 39, - "./base": 17, - "_process": 51 - }], - 28: [function(require, module, exports) { - (function(process) { - /** - * Module dependencies. - */ - - var Base = require('./base'); - var utils = require('../utils'); - - /** - * Constants - */ - - var SUITE_PREFIX = '$'; - - /** - * Expose `Markdown`. - */ - - exports = module.exports = Markdown; - - /** - * Initialize a new `Markdown` reporter. - * - * @api public - * @param {Runner} runner - */ - function Markdown(runner) { - Base.call(this, runner); - - var level = 0; - var buf = ''; - - function title(str) { - return Array(level).join('#') + ' ' + str; - } - - function mapTOC(suite, obj) { - var ret = obj; - var key = SUITE_PREFIX + suite.title; - - obj = obj[key] = obj[key] || { - suite: suite - }; - suite.suites.forEach(function(suite) { - mapTOC(suite, obj); - }); - - return ret; - } - - function stringifyTOC(obj, level) { - ++level; - var buf = ''; - var link; - for (var key in obj) { - if (key === 'suite') { - continue; - } - if (key !== SUITE_PREFIX) { - link = ' - [' + key.substring(1) + ']'; - link += '(#' + utils.slug(obj[key].suite.fullTitle()) + ')\n'; - buf += Array(level).join(' ') + link; - } - buf += stringifyTOC(obj[key], level); - } - return buf; - } - - function generateTOC(suite) { - var obj = mapTOC(suite, {}); - return stringifyTOC(obj, 0); - } - - generateTOC(runner.suite); - - runner.on('suite', function(suite) { - ++level; - var slug = utils.slug(suite.fullTitle()); - buf += '' + '\n'; - buf += title(suite.title) + '\n'; - }); - - runner.on('suite end', function() { - --level; - }); - - runner.on('pass', function(test) { - var code = utils.clean(test.fn.toString()); - buf += test.title + '.\n'; - buf += '\n```js\n'; - buf += code + '\n'; - buf += '```\n\n'; - }); - - runner.on('end', function() { - process.stdout.write('# TOC\n'); - process.stdout.write(generateTOC(runner.suite)); - process.stdout.write(buf); - }); - } - - }).call(this, require('_process')) - }, { - "../utils": 39, - "./base": 17, - "_process": 51 - }], - 29: [function(require, module, exports) { - (function(process) { - /** - * Module dependencies. - */ - - var Base = require('./base'); - var inherits = require('../utils').inherits; - - /** - * Expose `Min`. - */ - - exports = module.exports = Min; - - /** - * Initialize a new `Min` minimal test reporter (best used with --watch). - * - * @api public - * @param {Runner} runner - */ - function Min(runner) { - Base.call(this, runner); - - runner.on('start', function() { - // clear screen - process.stdout.write('\u001b[2J'); - // set cursor position - process.stdout.write('\u001b[1;3H'); - }); - - runner.on('end', this.epilogue.bind(this)); - } - - /** - * Inherit from `Base.prototype`. - */ - inherits(Min, Base); - - }).call(this, require('_process')) - }, { - "../utils": 39, - "./base": 17, - "_process": 51 - }], - 30: [function(require, module, exports) { - (function(process) { - /** - * Module dependencies. - */ - - var Base = require('./base'); - var inherits = require('../utils').inherits; - - /** - * Expose `Dot`. - */ - - exports = module.exports = NyanCat; - - /** - * Initialize a new `Dot` matrix test reporter. - * - * @param {Runner} runner - * @api public - */ - - function NyanCat(runner) { - Base.call(this, runner); - - var self = this; - var width = Base.window.width * .75 | 0; - var nyanCatWidth = this.nyanCatWidth = 11; - - this.colorIndex = 0; - this.numberOfLines = 4; - this.rainbowColors = self.generateColors(); - this.scoreboardWidth = 5; - this.tick = 0; - this.trajectories = [[], [], [], []]; - this.trajectoryWidthMax = (width - nyanCatWidth); - - runner.on('start', function() { - Base.cursor.hide(); - self.draw(); - }); - - runner.on('pending', function() { - self.draw(); - }); - - runner.on('pass', function() { - self.draw(); - }); - - runner.on('fail', function() { - self.draw(); - }); - - runner.on('end', function() { - Base.cursor.show(); - for (var i = 0; i < self.numberOfLines; i++) { - write('\n'); - } - self.epilogue(); - }); - } - - /** - * Inherit from `Base.prototype`. - */ - inherits(NyanCat, Base); - - /** - * Draw the nyan cat - * - * @api private - */ - - NyanCat.prototype.draw = function() { - this.appendRainbow(); - this.drawScoreboard(); - this.drawRainbow(); - this.drawNyanCat(); - this.tick = !this.tick; - }; - - /** - * Draw the "scoreboard" showing the number - * of passes, failures and pending tests. - * - * @api private - */ - - NyanCat.prototype.drawScoreboard = function() { - var stats = this.stats; - - function draw(type, n) { - write(' '); - write(Base.color(type, n)); - write('\n'); - } - - draw('green', stats.passes); - draw('fail', stats.failures); - draw('pending', stats.pending); - write('\n'); - - this.cursorUp(this.numberOfLines); - }; - - /** - * Append the rainbow. - * - * @api private - */ - - NyanCat.prototype.appendRainbow = function() { - var segment = this.tick ? '_' : '-'; - var rainbowified = this.rainbowify(segment); - - for (var index = 0; index < this.numberOfLines; index++) { - var trajectory = this.trajectories[index]; - if (trajectory.length >= this.trajectoryWidthMax) { - trajectory.shift(); - } - trajectory.push(rainbowified); - } - }; - - /** - * Draw the rainbow. - * - * @api private - */ - - NyanCat.prototype.drawRainbow = function() { - var self = this; - - this.trajectories.forEach(function(line) { - write('\u001b[' + self.scoreboardWidth + 'C'); - write(line.join('')); - write('\n'); - }); - - this.cursorUp(this.numberOfLines); - }; - - /** - * Draw the nyan cat - * - * @api private - */ - NyanCat.prototype.drawNyanCat = function() { - var self = this; - var startWidth = this.scoreboardWidth + this.trajectories[0].length; - var dist = '\u001b[' + startWidth + 'C'; - var padding = ''; - - write(dist); - write('_,------,'); - write('\n'); - - write(dist); - padding = self.tick ? ' ' : ' '; - write('_|' + padding + '/\\_/\\ '); - write('\n'); - - write(dist); - padding = self.tick ? '_' : '__'; - var tail = self.tick ? '~' : '^'; - write(tail + '|' + padding + this.face() + ' '); - write('\n'); - - write(dist); - padding = self.tick ? ' ' : ' '; - write(padding + '"" "" '); - write('\n'); - - this.cursorUp(this.numberOfLines); - }; - - /** - * Draw nyan cat face. - * - * @api private - * @return {string} - */ - - NyanCat.prototype.face = function() { - var stats = this.stats; - if (stats.failures) { - return '( x .x)'; - } else if (stats.pending) { - return '( o .o)'; - } else if (stats.passes) { - return '( ^ .^)'; - } - return '( - .-)'; - }; - - /** - * Move cursor up `n`. - * - * @api private - * @param {number} n - */ - - NyanCat.prototype.cursorUp = function(n) { - write('\u001b[' + n + 'A'); - }; - - /** - * Move cursor down `n`. - * - * @api private - * @param {number} n - */ - - NyanCat.prototype.cursorDown = function(n) { - write('\u001b[' + n + 'B'); - }; - - /** - * Generate rainbow colors. - * - * @api private - * @return {Array} - */ - NyanCat.prototype.generateColors = function() { - var colors = []; - - for (var i = 0; i < (6 * 7); i++) { - var pi3 = Math.floor(Math.PI / 3); - var n = (i * (1.0 / 6)); - var r = Math.floor(3 * Math.sin(n) + 3); - var g = Math.floor(3 * Math.sin(n + 2 * pi3) + 3); - var b = Math.floor(3 * Math.sin(n + 4 * pi3) + 3); - colors.push(36 * r + 6 * g + b + 16); - } - - return colors; - }; - - /** - * Apply rainbow to the given `str`. - * - * @api private - * @param {string} str - * @return {string} - */ - NyanCat.prototype.rainbowify = function(str) { - if (!Base.useColors) { - return str; - } - var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length]; - this.colorIndex += 1; - return '\u001b[38;5;' + color + 'm' + str + '\u001b[0m'; - }; - - /** - * Stdout helper. - * - * @param {string} string A message to write to stdout. - */ - function write(string) { - process.stdout.write(string); - } - - }).call(this, require('_process')) - }, { - "../utils": 39, - "./base": 17, - "_process": 51 - }], - 31: [function(require, module, exports) { - (function(process) { - /** - * Module dependencies. - */ - - var Base = require('./base'); - var inherits = require('../utils').inherits; - var color = Base.color; - var cursor = Base.cursor; - - /** - * Expose `Progress`. - */ - - exports = module.exports = Progress; - - /** - * General progress bar color. - */ - - Base.colors.progress = 90; - - /** - * Initialize a new `Progress` bar test reporter. - * - * @api public - * @param {Runner} runner - * @param {Object} options - */ - function Progress(runner, options) { - Base.call(this, runner); - - var self = this; - var width = Base.window.width * .50 | 0; - var total = runner.total; - var complete = 0; - var lastN = -1; - - // default chars - options = options || {}; - options.open = options.open || '['; - options.complete = options.complete || '▬'; - options.incomplete = options.incomplete || Base.symbols.dot; - options.close = options.close || ']'; - options.verbose = false; - - // tests started - runner.on('start', function() { - console.log(); - cursor.hide(); - }); - - // tests complete - runner.on('test end', function() { - complete++; - - var percent = complete / total; - var n = width * percent | 0; - var i = width - n; - - if (n === lastN && !options.verbose) { - // Don't re-render the line if it hasn't changed - return; - } - lastN = n; - - cursor.CR(); - process.stdout.write('\u001b[J'); - process.stdout.write(color('progress', ' ' + options.open)); - process.stdout.write(Array(n).join(options.complete)); - process.stdout.write(Array(i).join(options.incomplete)); - process.stdout.write(color('progress', options.close)); - if (options.verbose) { - process.stdout.write(color('progress', ' ' + complete + ' of ' + total)); - } - }); - - // tests are complete, output some stats - // and the failures if any - runner.on('end', function() { - cursor.show(); - console.log(); - self.epilogue(); - }); - } - - /** - * Inherit from `Base.prototype`. - */ - inherits(Progress, Base); - - }).call(this, require('_process')) - }, { - "../utils": 39, - "./base": 17, - "_process": 51 - }], - 32: [function(require, module, exports) { - /** - * Module dependencies. - */ - - var Base = require('./base'); - var inherits = require('../utils').inherits; - var color = Base.color; - var cursor = Base.cursor; - - /** - * Expose `Spec`. - */ - - exports = module.exports = Spec; - - /** - * Initialize a new `Spec` test reporter. - * - * @api public - * @param {Runner} runner - */ - function Spec(runner) { - Base.call(this, runner); - - var self = this; - var indents = 0; - var n = 0; - - function indent() { - return Array(indents).join(' '); - } - - runner.on('start', function() { - console.log(); - }); - - runner.on('suite', function(suite) { - ++indents; - console.log(color('suite', '%s%s'), indent(), suite.title); - }); - - runner.on('suite end', function() { - --indents; - if (indents === 1) { - console.log(); - } - }); - - runner.on('pending', function(test) { - var fmt = indent() + color('pending', ' - %s'); - console.log(fmt, test.title); - }); - - runner.on('pass', function(test) { - var fmt; - if (test.speed === 'fast') { - fmt = indent() - + color('checkmark', ' ' + Base.symbols.ok) - + color('pass', ' %s'); - cursor.CR(); - console.log(fmt, test.title); - } else { - fmt = indent() - + color('checkmark', ' ' + Base.symbols.ok) - + color('pass', ' %s') - + color(test.speed, ' (%dms)'); - cursor.CR(); - console.log(fmt, test.title, test.duration); - } - }); - - runner.on('fail', function(test) { - cursor.CR(); - console.log(indent() + color('fail', ' %d) %s'), ++n, test.title); - }); - - runner.on('end', self.epilogue.bind(self)); - } - - /** - * Inherit from `Base.prototype`. - */ - inherits(Spec, Base); - - }, { - "../utils": 39, - "./base": 17 - }], - 33: [function(require, module, exports) { - /** - * Module dependencies. - */ - - var Base = require('./base'); - - /** - * Expose `TAP`. - */ - - exports = module.exports = TAP; - - /** - * Initialize a new `TAP` reporter. - * - * @api public - * @param {Runner} runner - */ - function TAP(runner) { - Base.call(this, runner); - - var n = 1; - var passes = 0; - var failures = 0; - - runner.on('start', function() { - var total = runner.grepTotal(runner.suite); - console.log('%d..%d', 1, total); - }); - - runner.on('test end', function() { - ++n; - }); - - runner.on('pending', function(test) { - console.log('ok %d %s # SKIP -', n, title(test)); - }); - - runner.on('pass', function(test) { - passes++; - console.log('ok %d %s', n, title(test)); - }); - - runner.on('fail', function(test, err) { - failures++; - console.log('not ok %d %s', n, title(test)); - if (err.stack) { - console.log(err.stack.replace(/^/gm, ' ')); - } - }); - - runner.on('end', function() { - console.log('# tests ' + (passes + failures)); - console.log('# pass ' + passes); - console.log('# fail ' + failures); - }); - } - - /** - * Return a TAP-safe title of `test` - * - * @api private - * @param {Object} test - * @return {String} - */ - function title(test) { - return test.fullTitle().replace(/#/g, ''); - } - - }, { - "./base": 17 - }], - 34: [function(require, module, exports) { - (function(global) { - /** - * Module dependencies. - */ - - var Base = require('./base'); - var utils = require('../utils'); - var inherits = utils.inherits; - var fs = require('fs'); - var escape = utils.escape; - - /** - * Save timer references to avoid Sinon interfering (see GH-237). - */ - - /* eslint-disable no-unused-vars, no-native-reassign */ - var Date = global.Date; - var setTimeout = global.setTimeout; - var setInterval = global.setInterval; - var clearTimeout = global.clearTimeout; - var clearInterval = global.clearInterval; - /* eslint-enable no-unused-vars, no-native-reassign */ - - /** - * Expose `XUnit`. - */ - - exports = module.exports = XUnit; - - /** - * Initialize a new `XUnit` reporter. - * - * @api public - * @param {Runner} runner - */ - function XUnit(runner, options) { - Base.call(this, runner); - - var stats = this.stats; - var tests = []; - var self = this; - - if (options.reporterOptions && options.reporterOptions.output) { - if (!fs.createWriteStream) { - throw new Error('file output not supported in browser'); - } - self.fileStream = fs.createWriteStream(options.reporterOptions.output); - } - - runner.on('pending', function(test) { - tests.push(test); - }); - - runner.on('pass', function(test) { - tests.push(test); - }); - - runner.on('fail', function(test) { - tests.push(test); - }); - - runner.on('end', function() { - self.write(tag('testsuite', { - name: 'Mocha Tests', - tests: stats.tests, - failures: stats.failures, - errors: stats.failures, - skipped: stats.tests - stats.failures - stats.passes, - timestamp: (new Date()).toUTCString(), - time: (stats.duration / 1000) || 0 - }, false)); - - tests.forEach(function(t) { - self.test(t); - }); - - self.write(''); - }); - } - - /** - * Inherit from `Base.prototype`. - */ - inherits(XUnit, Base); - - /** - * Override done to close the stream (if it's a file). - * - * @param failures - * @param {Function} fn - */ - XUnit.prototype.done = function(failures, fn) { - if (this.fileStream) { - this.fileStream.end(function() { - fn(failures); - }); - } else { - fn(failures); - } - }; - - /** - * Write out the given line. - * - * @param {string} line - */ - XUnit.prototype.write = function(line) { - if (this.fileStream) { - this.fileStream.write(line + '\n'); - } else { - console.log(line); - } - }; - - /** - * Output tag for the given `test.` - * - * @param {Test} test - */ - XUnit.prototype.test = function(test) { - var attrs = { - classname: test.parent.fullTitle(), - name: test.title, - time: (test.duration / 1000) || 0 - }; - - if (test.state === 'failed') { - var err = test.err; - this.write(tag('testcase', attrs, false, tag('failure', {}, false, cdata(escape(err.message) + '\n' + err.stack)))); - } else if (test.pending) { - this.write(tag('testcase', attrs, false, tag('skipped', {}, true))); - } else { - this.write(tag('testcase', attrs, true)); - } - }; - - /** - * HTML tag helper. - * - * @param name - * @param attrs - * @param close - * @param content - * @return {string} - */ - function tag(name, attrs, close, content) { - var end = close ? '/>' : '>'; - var pairs = []; - var tag; - - for (var key in attrs) { - if (Object.prototype.hasOwnProperty.call(attrs, key)) { - pairs.push(key + '="' + escape(attrs[key]) + '"'); - } - } - - tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end; - if (content) { - tag += content + ''; - } - - }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) - }, { - "../utils": 39, - "./base": 17, - "fs": 41 - }], - 35: [function(require, module, exports) { - (function(global) { - /** - * Module dependencies. - */ - - var EventEmitter = require('events').EventEmitter; - var Pending = require('./pending'); - var debug = require('debug')('mocha:runnable'); - var milliseconds = require('./ms'); - var utils = require('./utils'); - var inherits = utils.inherits; - - /** - * Save timer references to avoid Sinon interfering (see GH-237). - */ - - /* eslint-disable no-unused-vars, no-native-reassign */ - var Date = global.Date; - var setTimeout = global.setTimeout; - var setInterval = global.setInterval; - var clearTimeout = global.clearTimeout; - var clearInterval = global.clearInterval; - /* eslint-enable no-unused-vars, no-native-reassign */ - - /** - * Object#toString(). - */ - - var toString = Object.prototype.toString; - - /** - * Expose `Runnable`. - */ - - module.exports = Runnable; - - /** - * Initialize a new `Runnable` with the given `title` and callback `fn`. - * - * @param {String} title - * @param {Function} fn - * @api private - * @param {string} title - * @param {Function} fn - */ - function Runnable(title, fn) { - this.title = title; - this.fn = fn; - this.async = fn && fn.length; - this.sync = !this.async; - this._timeout = 2000; - this._slow = 75; - this._enableTimeouts = true; - this.timedOut = false; - this._trace = new Error('done() called multiple times'); - } - - /** - * Inherit from `EventEmitter.prototype`. - */ - inherits(Runnable, EventEmitter); - - /** - * Set & get timeout `ms`. - * - * @api private - * @param {number|string} ms - * @return {Runnable|number} ms or Runnable instance. - */ - Runnable.prototype.timeout = function(ms) { - if (!arguments.length) { - return this._timeout; - } - if (ms === 0) { - this._enableTimeouts = false; - } - if (typeof ms === 'string') { - ms = milliseconds(ms); - } - debug('timeout %d', ms); - this._timeout = ms; - if (this.timer) { - this.resetTimeout(); - } - return this; - }; - - /** - * Set & get slow `ms`. - * - * @api private - * @param {number|string} ms - * @return {Runnable|number} ms or Runnable instance. - */ - Runnable.prototype.slow = function(ms) { - if (!arguments.length) { - return this._slow; - } - if (typeof ms === 'string') { - ms = milliseconds(ms); - } - debug('timeout %d', ms); - this._slow = ms; - return this; - }; - - /** - * Set and get whether timeout is `enabled`. - * - * @api private - * @param {boolean} enabled - * @return {Runnable|boolean} enabled or Runnable instance. - */ - Runnable.prototype.enableTimeouts = function(enabled) { - if (!arguments.length) { - return this._enableTimeouts; - } - debug('enableTimeouts %s', enabled); - this._enableTimeouts = enabled; - return this; - }; - - /** - * Halt and mark as pending. - * - * @api private - */ - Runnable.prototype.skip = function() { - throw new Pending(); - }; - - /** - * Return the full title generated by recursively concatenating the parent's - * full title. - * - * @api public - * @return {string} - */ - Runnable.prototype.fullTitle = function() { - return this.parent.fullTitle() + ' ' + this.title; - }; - - /** - * Clear the timeout. - * - * @api private - */ - Runnable.prototype.clearTimeout = function() { - clearTimeout(this.timer); - }; - - /** - * Inspect the runnable void of private properties. - * - * @api private - * @return {string} - */ - Runnable.prototype.inspect = function() { - return JSON.stringify(this, function(key, val) { - if (key[0] === '_') { - return; - } - if (key === 'parent') { - return '#'; - } - if (key === 'ctx') { - return '#'; - } - return val; - }, 2); - }; - - /** - * Reset the timeout. - * - * @api private - */ - Runnable.prototype.resetTimeout = function() { - var self = this; - var ms = this.timeout() || 1e9; - - if (!this._enableTimeouts) { - return; - } - this.clearTimeout(); - this.timer = setTimeout(function() { - if (!self._enableTimeouts) { - return; - } - self.callback(new Error('timeout of ' + ms + 'ms exceeded. Ensure the done() callback is being called in this test.')); - self.timedOut = true; - }, ms); - }; - - /** - * Whitelist a list of globals for this test run. - * - * @api private - * @param {string[]} globals - */ - Runnable.prototype.globals = function(globals) { - this._allowedGlobals = globals; - }; - - /** - * Run the test and invoke `fn(err)`. - * - * @param {Function} fn - * @api private - */ - Runnable.prototype.run = function(fn) { - var self = this; - var start = new Date(); - var ctx = this.ctx; - var finished; - var emitted; - - // Sometimes the ctx exists, but it is not runnable - if (ctx && ctx.runnable) { - ctx.runnable(this); - } - - // called multiple times - function multiple(err) { - if (emitted) { - return; - } - emitted = true; - self.emit('error', err || new Error('done() called multiple times; stacktrace may be inaccurate')); - } - - // finished - function done(err) { - var ms = self.timeout(); - if (self.timedOut) { - return; - } - if (finished) { - return multiple(err || self._trace); - } - - self.clearTimeout(); - self.duration = new Date() - start; - finished = true; - if (!err && self.duration > ms && self._enableTimeouts) { - err = new Error('timeout of ' + ms + 'ms exceeded. Ensure the done() callback is being called in this test.'); - } - fn(err); - } - - // for .resetTimeout() - this.callback = done; - - // explicit async with `done` argument - if (this.async) { - this.resetTimeout(); - - if (this.allowUncaught) { - return callFnAsync(this.fn); - } - try { - callFnAsync(this.fn); - } catch (err) { - done(utils.getError(err)); - } - return; - } - - if (this.allowUncaught) { - callFn(this.fn); - done(); - return; - } - - // sync or promise-returning - try { - if (this.pending) { - done(); - } else { - callFn(this.fn); - } - } catch (err) { - done(utils.getError(err)); - } - - function callFn(fn) { - var result = fn.call(ctx); - if (result && typeof result.then === 'function') { - self.resetTimeout(); - result - .then(function() { - done(); - }, - function(reason) { - done(reason || new Error('Promise rejected with no or falsy reason')); - }); - } else { - if (self.asyncOnly) { - return done(new Error('--async-only option in use without declaring `done()` or returning a promise')); - } - - done(); - } - } - - function callFnAsync(fn) { - fn.call(ctx, function(err) { - if (err instanceof Error || toString.call(err) === '[object Error]') { - return done(err); - } - if (err) { - if (Object.prototype.toString.call(err) === '[object Object]') { - return done(new Error('done() invoked with non-Error: ' - + JSON.stringify(err))); - } - return done(new Error('done() invoked with non-Error: ' + err)); - } - done(); - }); - } - }; - - }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) - }, { - "./ms": 15, - "./pending": 16, - "./utils": 39, - "debug": 2, - "events": 3 - }], - 36: [function(require, module, exports) { - (function(process, global) { - /** - * Module dependencies. - */ - - var EventEmitter = require('events').EventEmitter; - var Pending = require('./pending'); - var utils = require('./utils'); - var inherits = utils.inherits; - var debug = require('debug')('mocha:runner'); - var Runnable = require('./runnable'); - var filter = utils.filter; - var indexOf = utils.indexOf; - var keys = utils.keys; - var stackFilter = utils.stackTraceFilter(); - var stringify = utils.stringify; - var type = utils.type; - var undefinedError = utils.undefinedError; - - /** - * Non-enumerable globals. - */ - - var globals = [ - 'setTimeout', - 'clearTimeout', - 'setInterval', - 'clearInterval', - 'XMLHttpRequest', - 'Date', - 'setImmediate', - 'clearImmediate' - ]; - - /** - * Expose `Runner`. - */ - - module.exports = Runner; - - /** - * Initialize a `Runner` for the given `suite`. - * - * Events: - * - * - `start` execution started - * - `end` execution complete - * - `suite` (suite) test suite execution started - * - `suite end` (suite) all tests (and sub-suites) have finished - * - `test` (test) test execution started - * - `test end` (test) test completed - * - `hook` (hook) hook execution started - * - `hook end` (hook) hook complete - * - `pass` (test) test passed - * - `fail` (test, err) test failed - * - `pending` (test) test pending - * - * @api public - * @param {Suite} suite Root suite - * @param {boolean} [delay] Whether or not to delay execution of root suite - * until ready. - */ - function Runner(suite, delay) { - var self = this; - this._globals = []; - this._abort = false; - this._delay = delay; - this.suite = suite; - this.started = false; - this.total = suite.total(); - this.failures = 0; - this.on('test end', function(test) { - self.checkGlobals(test); - }); - this.on('hook end', function(hook) { - self.checkGlobals(hook); - }); - this._defaultGrep = /.*/; - this.grep(this._defaultGrep); - this.globals(this.globalProps().concat(extraGlobals())); - } - - /** - * Wrapper for setImmediate, process.nextTick, or browser polyfill. - * - * @param {Function} fn - * @api private - */ - Runner.immediately = global.setImmediate || process.nextTick; - - /** - * Inherit from `EventEmitter.prototype`. - */ - inherits(Runner, EventEmitter); - - /** - * Run tests with full titles matching `re`. Updates runner.total - * with number of tests matched. - * - * @param {RegExp} re - * @param {Boolean} invert - * @return {Runner} for chaining - * @api public - * @param {RegExp} re - * @param {boolean} invert - * @return {Runner} Runner instance. - */ - Runner.prototype.grep = function(re, invert) { - debug('grep %s', re); - this._grep = re; - this._invert = invert; - this.total = this.grepTotal(this.suite); - return this; - }; - - /** - * Returns the number of tests matching the grep search for the - * given suite. - * - * @param {Suite} suite - * @return {Number} - * @api public - * @param {Suite} suite - * @return {number} - */ - Runner.prototype.grepTotal = function(suite) { - var self = this; - var total = 0; - - suite.eachTest(function(test) { - var match = self._grep.test(test.fullTitle()); - if (self._invert) { - match = !match; - } - if (match) { - total++; - } - }); - - return total; - }; - - /** - * Return a list of global properties. - * - * @return {Array} - * @api private - */ - Runner.prototype.globalProps = function() { - var props = keys(global); - - // non-enumerables - for (var i = 0; i < globals.length; ++i) { - if (~indexOf(props, globals[i])) { - continue; - } - props.push(globals[i]); - } - - return props; - }; - - /** - * Allow the given `arr` of globals. - * - * @param {Array} arr - * @return {Runner} for chaining - * @api public - * @param {Array} arr - * @return {Runner} Runner instance. - */ - Runner.prototype.globals = function(arr) { - if (!arguments.length) { - return this._globals; - } - debug('globals %j', arr); - this._globals = this._globals.concat(arr); - return this; - }; - - /** - * Check for global variable leaks. - * - * @api private - */ - Runner.prototype.checkGlobals = function(test) { - if (this.ignoreLeaks) { - return; - } - var ok = this._globals; - - var globals = this.globalProps(); - var leaks; - - if (test) { - ok = ok.concat(test._allowedGlobals || []); - } - - if (this.prevGlobalsLength === globals.length) { - return; - } - this.prevGlobalsLength = globals.length; - - leaks = filterLeaks(ok, globals); - this._globals = this._globals.concat(leaks); - - if (leaks.length > 1) { - this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + '')); - } else if (leaks.length) { - this.fail(test, new Error('global leak detected: ' + leaks[0])); - } - }; - - /** - * Fail the given `test`. - * - * @api private - * @param {Test} test - * @param {Error} err - */ - Runner.prototype.fail = function(test, err) { - ++this.failures; - test.state = 'failed'; - - if (!(err instanceof Error || err && typeof err.message === 'string')) { - err = new Error('the ' + type(err) + ' ' + stringify(err) + ' was thrown, throw an Error :)'); - } - - err.stack = (this.fullStackTrace || !err.stack) - ? err.stack - : stackFilter(err.stack); - - this.emit('fail', test, err); - }; - - /** - * Fail the given `hook` with `err`. - * - * Hook failures work in the following pattern: - * - If bail, then exit - * - Failed `before` hook skips all tests in a suite and subsuites, - * but jumps to corresponding `after` hook - * - Failed `before each` hook skips remaining tests in a - * suite and jumps to corresponding `after each` hook, - * which is run only once - * - Failed `after` hook does not alter - * execution order - * - Failed `after each` hook skips remaining tests in a - * suite and subsuites, but executes other `after each` - * hooks - * - * @api private - * @param {Hook} hook - * @param {Error} err - */ - Runner.prototype.failHook = function(hook, err) { - if (hook.ctx && hook.ctx.currentTest) { - hook.originalTitle = hook.originalTitle || hook.title; - hook.title = hook.originalTitle + ' for "' + hook.ctx.currentTest.title + '"'; - } - - this.fail(hook, err); - if (this.suite.bail()) { - this.emit('end'); - } - }; - - /** - * Run hook `name` callbacks and then invoke `fn()`. - * - * @api private - * @param {string} name - * @param {Function} fn - */ - - Runner.prototype.hook = function(name, fn) { - var suite = this.suite; - var hooks = suite['_' + name]; - var self = this; - - function next(i) { - var hook = hooks[i]; - if (!hook) { - return fn(); - } - self.currentRunnable = hook; - - hook.ctx.currentTest = self.test; - - self.emit('hook', hook); - - if (!hook.listeners('error').length) { - hook.on('error', function(err) { - self.failHook(hook, err); - }); - } - - hook.run(function(err) { - var testError = hook.error(); - if (testError) { - self.fail(self.test, testError); - } - if (err) { - if (err instanceof Pending) { - suite.pending = true; - } else { - self.failHook(hook, err); - - // stop executing hooks, notify callee of hook err - return fn(err); - } - } - self.emit('hook end', hook); - delete hook.ctx.currentTest; - next(++i); - }); - } - - Runner.immediately(function() { - next(0); - }); - }; - - /** - * Run hook `name` for the given array of `suites` - * in order, and callback `fn(err, errSuite)`. - * - * @api private - * @param {string} name - * @param {Array} suites - * @param {Function} fn - */ - Runner.prototype.hooks = function(name, suites, fn) { - var self = this; - var orig = this.suite; - - function next(suite) { - self.suite = suite; - - if (!suite) { - self.suite = orig; - return fn(); - } - - self.hook(name, function(err) { - if (err) { - var errSuite = self.suite; - self.suite = orig; - return fn(err, errSuite); - } - - next(suites.pop()); - }); - } - - next(suites.pop()); - }; - - /** - * Run hooks from the top level down. - * - * @param {String} name - * @param {Function} fn - * @api private - */ - Runner.prototype.hookUp = function(name, fn) { - var suites = [this.suite].concat(this.parents()).reverse(); - this.hooks(name, suites, fn); - }; - - /** - * Run hooks from the bottom up. - * - * @param {String} name - * @param {Function} fn - * @api private - */ - Runner.prototype.hookDown = function(name, fn) { - var suites = [this.suite].concat(this.parents()); - this.hooks(name, suites, fn); - }; - - /** - * Return an array of parent Suites from - * closest to furthest. - * - * @return {Array} - * @api private - */ - Runner.prototype.parents = function() { - var suite = this.suite; - var suites = []; - while (suite.parent) { - suite = suite.parent; - suites.push(suite); - } - return suites; - }; - - /** - * Run the current test and callback `fn(err)`. - * - * @param {Function} fn - * @api private - */ - Runner.prototype.runTest = function(fn) { - var self = this; - var test = this.test; - - if (this.asyncOnly) { - test.asyncOnly = true; - } - - if (this.allowUncaught) { - test.allowUncaught = true; - return test.run(fn); - } - try { - test.on('error', function(err) { - self.fail(test, err); - }); - test.run(fn); - } catch (err) { - fn(err); - } - }; - - /** - * Run tests in the given `suite` and invoke the callback `fn()` when complete. - * - * @api private - * @param {Suite} suite - * @param {Function} fn - */ - Runner.prototype.runTests = function(suite, fn) { - var self = this; - var tests = suite.tests.slice(); - var test; - - function hookErr(_, errSuite, after) { - // before/after Each hook for errSuite failed: - var orig = self.suite; - - // for failed 'after each' hook start from errSuite parent, - // otherwise start from errSuite itself - self.suite = after ? errSuite.parent : errSuite; - - if (self.suite) { - // call hookUp afterEach - self.hookUp('afterEach', function(err2, errSuite2) { - self.suite = orig; - // some hooks may fail even now - if (err2) { - return hookErr(err2, errSuite2, true); - } - // report error suite - fn(errSuite); - }); - } else { - // there is no need calling other 'after each' hooks - self.suite = orig; - fn(errSuite); - } - } - - function next(err, errSuite) { - // if we bail after first err - if (self.failures && suite._bail) { - return fn(); - } - - if (self._abort) { - return fn(); - } - - if (err) { - return hookErr(err, errSuite, true); - } - - // next test - test = tests.shift(); - - // all done - if (!test) { - return fn(); - } - - // grep - var match = self._grep.test(test.fullTitle()); - if (self._invert) { - match = !match; - } - if (!match) { - // Run immediately only if we have defined a grep. When we - // define a grep — It can cause maximum callstack error if - // the grep is doing a large recursive loop by neglecting - // all tests. The run immediately function also comes with - // a performance cost. So we don't want to run immediately - // if we run the whole test suite, because running the whole - // test suite don't do any immediate recursive loops. Thus, - // allowing a JS runtime to breathe. - if (self._grep !== self._defaultGrep) { - Runner.immediately(next); - } else { - next(); - } - return; - } - - // pending - if (test.pending) { - self.emit('pending', test); - self.emit('test end', test); - return next(); - } - - // execute test and hook(s) - self.emit('test', self.test = test); - self.hookDown('beforeEach', function(err, errSuite) { - if (suite.pending) { - self.emit('pending', test); - self.emit('test end', test); - return next(); - } - if (err) { - return hookErr(err, errSuite, false); - } - self.currentRunnable = self.test; - self.runTest(function(err) { - test = self.test; - - if (err) { - if (err instanceof Pending) { - self.emit('pending', test); - } else { - self.fail(test, err); - } - self.emit('test end', test); - - if (err instanceof Pending) { - return next(); - } - - return self.hookUp('afterEach', next); - } - - test.state = 'passed'; - self.emit('pass', test); - self.emit('test end', test); - self.hookUp('afterEach', next); - }); - }); - } - - this.next = next; - this.hookErr = hookErr; - next(); - }; - - /** - * Run the given `suite` and invoke the callback `fn()` when complete. - * - * @api private - * @param {Suite} suite - * @param {Function} fn - */ - Runner.prototype.runSuite = function(suite, fn) { - var i = 0; - var self = this; - var total = this.grepTotal(suite); - var afterAllHookCalled = false; - - debug('run suite %s', suite.fullTitle()); - - if (!total || (self.failures && suite._bail)) { - return fn(); - } - - this.emit('suite', this.suite = suite); - - function next(errSuite) { - if (errSuite) { - // current suite failed on a hook from errSuite - if (errSuite === suite) { - // if errSuite is current suite - // continue to the next sibling suite - return done(); - } - // errSuite is among the parents of current suite - // stop execution of errSuite and all sub-suites - return done(errSuite); - } - - if (self._abort) { - return done(); - } - - var curr = suite.suites[i++]; - if (!curr) { - return done(); - } - - // Avoid grep neglecting large number of tests causing a - // huge recursive loop and thus a maximum call stack error. - // See comment in `this.runTests()` for more information. - if (self._grep !== self._defaultGrep) { - Runner.immediately(function() { - self.runSuite(curr, next); - }); - } else { - self.runSuite(curr, next); - } - } - - function done(errSuite) { - self.suite = suite; - self.nextSuite = next; - - if (afterAllHookCalled) { - fn(errSuite); - } else { - // mark that the afterAll block has been called once - // and so can be skipped if there is an error in it. - afterAllHookCalled = true; - self.hook('afterAll', function() { - self.emit('suite end', suite); - fn(errSuite); - }); - } - } - - this.nextSuite = next; - - this.hook('beforeAll', function(err) { - if (err) { - return done(); - } - self.runTests(suite, next); - }); - }; - - /** - * Handle uncaught exceptions. - * - * @param {Error} err - * @api private - */ - Runner.prototype.uncaught = function(err) { - if (err) { - debug('uncaught exception %s', err !== function() { - return this; - }.call(err) ? err : (err.message || err)); - } else { - debug('uncaught undefined exception'); - err = undefinedError(); - } - err.uncaught = true; - - var runnable = this.currentRunnable; - - if (!runnable) { - runnable = new Runnable('Uncaught error outside test suite'); - runnable.parent = this.suite; - - if (this.started) { - this.fail(runnable, err); - } else { - // Can't recover from this failure - this.emit('start'); - this.fail(runnable, err); - this.emit('end'); - } - - return; - } - - runnable.clearTimeout(); - - // Ignore errors if complete - if (runnable.state) { - return; - } - this.fail(runnable, err); - - // recover from test - if (runnable.type === 'test') { - this.emit('test end', runnable); - this.hookUp('afterEach', this.next); - return; - } - - // recover from hooks - if (runnable.type === 'hook') { - var errSuite = this.suite; - // if hook failure is in afterEach block - if (runnable.fullTitle().indexOf('after each') > -1) { - return this.hookErr(err, errSuite, true); - } - // if hook failure is in beforeEach block - if (runnable.fullTitle().indexOf('before each') > -1) { - return this.hookErr(err, errSuite, false); - } - // if hook failure is in after or before blocks - return this.nextSuite(errSuite); - } - - // bail - this.emit('end'); - }; - - /** - * Run the root suite and invoke `fn(failures)` - * on completion. - * - * @param {Function} fn - * @return {Runner} for chaining - * @api public - * @param {Function} fn - * @return {Runner} Runner instance. - */ - Runner.prototype.run = function(fn) { - var self = this; - var rootSuite = this.suite; - - fn = fn || function() {}; - - function uncaught(err) { - self.uncaught(err); - } - - function start() { - self.started = true; - self.emit('start'); - self.runSuite(rootSuite, function() { - debug('finished running'); - self.emit('end'); - }); - } - - debug('start'); - - // callback - this.on('end', function() { - debug('end'); - process.removeListener('uncaughtException', uncaught); - fn(self.failures); - }); - - // uncaught exception - process.on('uncaughtException', uncaught); - - if (this._delay) { - // for reporters, I guess. - // might be nice to debounce some dots while we wait. - this.emit('waiting', rootSuite); - rootSuite.once('run', start); - } else { - start(); - } - - return this; - }; - - /** - * Cleanly abort execution. - * - * @api public - * @return {Runner} Runner instance. - */ - Runner.prototype.abort = function() { - debug('aborting'); - this._abort = true; - - return this; - }; - - /** - * Filter leaks with the given globals flagged as `ok`. - * - * @api private - * @param {Array} ok - * @param {Array} globals - * @return {Array} - */ - function filterLeaks(ok, globals) { - return filter(globals, function(key) { - // Firefox and Chrome exposes iframes as index inside the window object - if (/^d+/.test(key)) { - return false; - } - - // in firefox - // if runner runs in an iframe, this iframe's window.getInterface method not init at first - // it is assigned in some seconds - if (global.navigator && (/^getInterface/).test(key)) { - return false; - } - - // an iframe could be approached by window[iframeIndex] - // in ie6,7,8 and opera, iframeIndex is enumerable, this could cause leak - if (global.navigator && (/^\d+/).test(key)) { - return false; - } - - // Opera and IE expose global variables for HTML element IDs (issue #243) - if (/^mocha-/.test(key)) { - return false; - } - - var matched = filter(ok, function(ok) { - if (~ok.indexOf('*')) { - return key.indexOf(ok.split('*')[0]) === 0; - } - return key === ok; - }); - return !matched.length && (!global.navigator || key !== 'onerror'); - }); - } - - /** - * Array of globals dependent on the environment. - * - * @return {Array} - * @api private - */ - function extraGlobals() { - if (typeof process === 'object' && typeof process.version === 'string') { - var parts = process.version.split('.'); - var nodeVersion = utils.reduce(parts, function(a, v) { - return a << 8 | v; - }); - - // 'errno' was renamed to process._errno in v0.9.11. - - if (nodeVersion < 0x00090B) { - return ['errno']; - } - } - - return []; - } - - }).call(this, require('_process'), typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) - }, { - "./pending": 16, - "./runnable": 35, - "./utils": 39, - "_process": 51, - "debug": 2, - "events": 3 - }], - 37: [function(require, module, exports) { - /** - * Module dependencies. - */ - - var EventEmitter = require('events').EventEmitter; - var Hook = require('./hook'); - var utils = require('./utils'); - var inherits = utils.inherits; - var debug = require('debug')('mocha:suite'); - var milliseconds = require('./ms'); - - /** - * Expose `Suite`. - */ - - exports = module.exports = Suite; - - /** - * Create a new `Suite` with the given `title` and parent `Suite`. When a suite - * with the same title is already present, that suite is returned to provide - * nicer reporter and more flexible meta-testing. - * - * @api public - * @param {Suite} parent - * @param {string} title - * @return {Suite} - */ - exports.create = function(parent, title) { - var suite = new Suite(title, parent.ctx); - suite.parent = parent; - if (parent.pending) { - suite.pending = true; - } - title = suite.fullTitle(); - parent.addSuite(suite); - return suite; - }; - - /** - * Initialize a new `Suite` with the given `title` and `ctx`. - * - * @api private - * @param {string} title - * @param {Context} parentContext - */ - function Suite(title, parentContext) { - this.title = title; - function Context() { - } - Context.prototype = parentContext; - this.ctx = new Context(); - this.suites = []; - this.tests = []; - this.pending = false; - this._beforeEach = []; - this._beforeAll = []; - this._afterEach = []; - this._afterAll = []; - this.root = !title; - this._timeout = 2000; - this._enableTimeouts = true; - this._slow = 75; - this._bail = false; - this.delayed = false; - } - - /** - * Inherit from `EventEmitter.prototype`. - */ - inherits(Suite, EventEmitter); - - /** - * Return a clone of this `Suite`. - * - * @api private - * @return {Suite} - */ - Suite.prototype.clone = function() { - var suite = new Suite(this.title); - debug('clone'); - suite.ctx = this.ctx; - suite.timeout(this.timeout()); - suite.enableTimeouts(this.enableTimeouts()); - suite.slow(this.slow()); - suite.bail(this.bail()); - return suite; - }; - - /** - * Set timeout `ms` or short-hand such as "2s". - * - * @api private - * @param {number|string} ms - * @return {Suite|number} for chaining - */ - Suite.prototype.timeout = function(ms) { - if (!arguments.length) { - return this._timeout; - } - if (ms.toString() === '0') { - this._enableTimeouts = false; - } - if (typeof ms === 'string') { - ms = milliseconds(ms); - } - debug('timeout %d', ms); - this._timeout = parseInt(ms, 10); - return this; - }; - - /** - * Set timeout to `enabled`. - * - * @api private - * @param {boolean} enabled - * @return {Suite|boolean} self or enabled - */ - Suite.prototype.enableTimeouts = function(enabled) { - if (!arguments.length) { - return this._enableTimeouts; - } - debug('enableTimeouts %s', enabled); - this._enableTimeouts = enabled; - return this; - }; - - /** - * Set slow `ms` or short-hand such as "2s". - * - * @api private - * @param {number|string} ms - * @return {Suite|number} for chaining - */ - Suite.prototype.slow = function(ms) { - if (!arguments.length) { - return this._slow; - } - if (typeof ms === 'string') { - ms = milliseconds(ms); - } - debug('slow %d', ms); - this._slow = ms; - return this; - }; - - /** - * Sets whether to bail after first error. - * - * @api private - * @param {boolean} bail - * @return {Suite|number} for chaining - */ - Suite.prototype.bail = function(bail) { - if (!arguments.length) { - return this._bail; - } - debug('bail %s', bail); - this._bail = bail; - return this; - }; - - /** - * Run `fn(test[, done])` before running tests. - * - * @api private - * @param {string} title - * @param {Function} fn - * @return {Suite} for chaining - */ - Suite.prototype.beforeAll = function(title, fn) { - if (this.pending) { - return this; - } - if (typeof title === 'function') { - fn = title; - title = fn.name; - } - title = '"before all" hook' + (title ? ': ' + title : ''); - - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.enableTimeouts(this.enableTimeouts()); - hook.slow(this.slow()); - hook.ctx = this.ctx; - this._beforeAll.push(hook); - this.emit('beforeAll', hook); - return this; - }; - - /** - * Run `fn(test[, done])` after running tests. - * - * @api private - * @param {string} title - * @param {Function} fn - * @return {Suite} for chaining - */ - Suite.prototype.afterAll = function(title, fn) { - if (this.pending) { - return this; - } - if (typeof title === 'function') { - fn = title; - title = fn.name; - } - title = '"after all" hook' + (title ? ': ' + title : ''); - - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.enableTimeouts(this.enableTimeouts()); - hook.slow(this.slow()); - hook.ctx = this.ctx; - this._afterAll.push(hook); - this.emit('afterAll', hook); - return this; - }; - - /** - * Run `fn(test[, done])` before each test case. - * - * @api private - * @param {string} title - * @param {Function} fn - * @return {Suite} for chaining - */ - Suite.prototype.beforeEach = function(title, fn) { - if (this.pending) { - return this; - } - if (typeof title === 'function') { - fn = title; - title = fn.name; - } - title = '"before each" hook' + (title ? ': ' + title : ''); - - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.enableTimeouts(this.enableTimeouts()); - hook.slow(this.slow()); - hook.ctx = this.ctx; - this._beforeEach.push(hook); - this.emit('beforeEach', hook); - return this; - }; - - /** - * Run `fn(test[, done])` after each test case. - * - * @api private - * @param {string} title - * @param {Function} fn - * @return {Suite} for chaining - */ - Suite.prototype.afterEach = function(title, fn) { - if (this.pending) { - return this; - } - if (typeof title === 'function') { - fn = title; - title = fn.name; - } - title = '"after each" hook' + (title ? ': ' + title : ''); - - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.enableTimeouts(this.enableTimeouts()); - hook.slow(this.slow()); - hook.ctx = this.ctx; - this._afterEach.push(hook); - this.emit('afterEach', hook); - return this; - }; - - /** - * Add a test `suite`. - * - * @api private - * @param {Suite} suite - * @return {Suite} for chaining - */ - Suite.prototype.addSuite = function(suite) { - suite.parent = this; - suite.timeout(this.timeout()); - suite.enableTimeouts(this.enableTimeouts()); - suite.slow(this.slow()); - suite.bail(this.bail()); - this.suites.push(suite); - this.emit('suite', suite); - return this; - }; - - /** - * Add a `test` to this suite. - * - * @api private - * @param {Test} test - * @return {Suite} for chaining - */ - Suite.prototype.addTest = function(test) { - test.parent = this; - test.timeout(this.timeout()); - test.enableTimeouts(this.enableTimeouts()); - test.slow(this.slow()); - test.ctx = this.ctx; - this.tests.push(test); - this.emit('test', test); - return this; - }; - - /** - * Return the full title generated by recursively concatenating the parent's - * full title. - * - * @api public - * @return {string} - */ - Suite.prototype.fullTitle = function() { - if (this.parent) { - var full = this.parent.fullTitle(); - if (full) { - return full + ' ' + this.title; - } - } - return this.title; - }; - - /** - * Return the total number of tests. - * - * @api public - * @return {number} - */ - Suite.prototype.total = function() { - return utils.reduce(this.suites, function(sum, suite) { - return sum + suite.total(); - }, 0) + this.tests.length; - }; - - /** - * Iterates through each suite recursively to find all tests. Applies a - * function in the format `fn(test)`. - * - * @api private - * @param {Function} fn - * @return {Suite} - */ - Suite.prototype.eachTest = function(fn) { - utils.forEach(this.tests, fn); - utils.forEach(this.suites, function(suite) { - suite.eachTest(fn); - }); - return this; - }; - - /** - * This will run the root suite if we happen to be running in delayed mode. - */ - Suite.prototype.run = function run() { - if (this.root) { - this.emit('run'); - } - }; - - }, { - "./hook": 7, - "./ms": 15, - "./utils": 39, - "debug": 2, - "events": 3 - }], - 38: [function(require, module, exports) { - /** - * Module dependencies. - */ - - var Runnable = require('./runnable'); - var inherits = require('./utils').inherits; - - /** - * Expose `Test`. - */ - - module.exports = Test; - - /** - * Initialize a new `Test` with the given `title` and callback `fn`. - * - * @api private - * @param {String} title - * @param {Function} fn - */ - function Test(title, fn) { - Runnable.call(this, title, fn); - this.pending = !fn; - this.type = 'test'; - } - - /** - * Inherit from `Runnable.prototype`. - */ - inherits(Test, Runnable); - - }, { - "./runnable": 35, - "./utils": 39 - }], - 39: [function(require, module, exports) { - (function(process, Buffer) { - /* eslint-env browser */ - - /** - * Module dependencies. - */ - - var basename = require('path').basename; - var debug = require('debug')('mocha:watch'); - var exists = require('fs').existsSync || require('path').existsSync; - var glob = require('glob'); - var join = require('path').join; - var readdirSync = require('fs').readdirSync; - var statSync = require('fs').statSync; - var watchFile = require('fs').watchFile; - - /** - * Ignored directories. - */ - - var ignore = ['node_modules', '.git']; - - exports.inherits = require('util').inherits; - - /** - * Escape special characters in the given string of html. - * - * @api private - * @param {string} html - * @return {string} - */ - exports.escape = function(html) { - return String(html) - .replace(/&/g, '&') - .replace(/"/g, '"') - .replace(//g, '>'); - }; - - /** - * Array#forEach (<=IE8) - * - * @api private - * @param {Array} arr - * @param {Function} fn - * @param {Object} scope - */ - exports.forEach = function(arr, fn, scope) { - for (var i = 0, l = arr.length; i < l; i++) { - fn.call(scope, arr[i], i); - } - }; - - /** - * Test if the given obj is type of string. - * - * @api private - * @param {Object} obj - * @return {boolean} - */ - exports.isString = function(obj) { - return typeof obj === 'string'; - }; - - /** - * Array#map (<=IE8) - * - * @api private - * @param {Array} arr - * @param {Function} fn - * @param {Object} scope - * @return {Array} - */ - exports.map = function(arr, fn, scope) { - var result = []; - for (var i = 0, l = arr.length; i < l; i++) { - result.push(fn.call(scope, arr[i], i, arr)); - } - return result; - }; - - /** - * Array#indexOf (<=IE8) - * - * @api private - * @param {Array} arr - * @param {Object} obj to find index of - * @param {number} start - * @return {number} - */ - exports.indexOf = function(arr, obj, start) { - for (var i = start || 0, l = arr.length; i < l; i++) { - if (arr[i] === obj) { - return i; - } - } - return -1; - }; - - /** - * Array#reduce (<=IE8) - * - * @api private - * @param {Array} arr - * @param {Function} fn - * @param {Object} val Initial value. - * @return {*} - */ - exports.reduce = function(arr, fn, val) { - var rval = val; - - for (var i = 0, l = arr.length; i < l; i++) { - rval = fn(rval, arr[i], i, arr); - } - - return rval; - }; - - /** - * Array#filter (<=IE8) - * - * @api private - * @param {Array} arr - * @param {Function} fn - * @return {Array} - */ - exports.filter = function(arr, fn) { - var ret = []; - - for (var i = 0, l = arr.length; i < l; i++) { - var val = arr[i]; - if (fn(val, i, arr)) { - ret.push(val); - } - } - - return ret; - }; - - /** - * Object.keys (<=IE8) - * - * @api private - * @param {Object} obj - * @return {Array} keys - */ - exports.keys = typeof Object.keys === 'function' ? Object.keys : function(obj) { - var keys = []; - var has = Object.prototype.hasOwnProperty; // for `window` on <=IE8 - - for (var key in obj) { - if (has.call(obj, key)) { - keys.push(key); - } - } - - return keys; - }; - - /** - * Watch the given `files` for changes - * and invoke `fn(file)` on modification. - * - * @api private - * @param {Array} files - * @param {Function} fn - */ - exports.watch = function(files, fn) { - var options = { - interval: 100 - }; - files.forEach(function(file) { - debug('file %s', file); - watchFile(file, options, function(curr, prev) { - if (prev.mtime < curr.mtime) { - fn(file); - } - }); - }); - }; - - /** - * Array.isArray (<=IE8) - * - * @api private - * @param {Object} obj - * @return {Boolean} - */ - var isArray = typeof Array.isArray === 'function' ? Array.isArray : function(obj) { - return Object.prototype.toString.call(obj) === '[object Array]'; - }; - - /** - * Buffer.prototype.toJSON polyfill. - * - * @type {Function} - */ - if (typeof Buffer !== 'undefined' && Buffer.prototype) { - Buffer.prototype.toJSON = Buffer.prototype.toJSON || function() { - return Array.prototype.slice.call(this, 0); - }; - } - - /** - * Ignored files. - * - * @api private - * @param {string} path - * @return {boolean} - */ - function ignored(path) { - return !~ignore.indexOf(path); - } - - /** - * Lookup files in the given `dir`. - * - * @api private - * @param {string} dir - * @param {string[]} [ext=['.js']] - * @param {Array} [ret=[]] - * @return {Array} - */ - exports.files = function(dir, ext, ret) { - ret = ret || []; - ext = ext || ['js']; - - var re = new RegExp('\\.(' + ext.join('|') + ')$'); - - readdirSync(dir) - .filter(ignored) - .forEach(function(path) { - path = join(dir, path); - if (statSync(path).isDirectory()) { - exports.files(path, ext, ret); - } else if (path.match(re)) { - ret.push(path); - } - }); - - return ret; - }; - - /** - * Compute a slug from the given `str`. - * - * @api private - * @param {string} str - * @return {string} - */ - exports.slug = function(str) { - return str - .toLowerCase() - .replace(/ +/g, '-') - .replace(/[^-\w]/g, ''); - }; - - /** - * Strip the function definition from `str`, and re-indent for pre whitespace. - * - * @param {string} str - * @return {string} - */ - exports.clean = function(str) { - str = str - .replace(/\r\n?|[\n\u2028\u2029]/g, '\n').replace(/^\uFEFF/, '') - .replace(/^function *\(.*\)\s*{|\(.*\) *=> *{?/, '') - .replace(/\s+\}$/, ''); - - var spaces = str.match(/^\n?( *)/)[1].length; - var tabs = str.match(/^\n?(\t*)/)[1].length; - var re = new RegExp('^\n?' + (tabs ? '\t' : ' ') + '{' + (tabs ? tabs : spaces) + '}', 'gm'); - - str = str.replace(re, ''); - - return exports.trim(str); - }; - - /** - * Trim the given `str`. - * - * @api private - * @param {string} str - * @return {string} - */ - exports.trim = function(str) { - return str.replace(/^\s+|\s+$/g, ''); - }; - - /** - * Parse the given `qs`. - * - * @api private - * @param {string} qs - * @return {Object} - */ - exports.parseQuery = function(qs) { - return exports.reduce(qs.replace('?', '').split('&'), function(obj, pair) { - var i = pair.indexOf('='); - var key = pair.slice(0, i); - var val = pair.slice(++i); - - obj[key] = decodeURIComponent(val); - return obj; - }, {}); - }; - - /** - * Highlight the given string of `js`. - * - * @api private - * @param {string} js - * @return {string} - */ - function highlight(js) { - return js - .replace(//g, '>') - .replace(/\/\/(.*)/gm, '//$1') - .replace(/('.*?')/gm, '$1') - .replace(/(\d+\.\d+)/gm, '$1') - .replace(/(\d+)/gm, '$1') - .replace(/\bnew[ \t]+(\w+)/gm, 'new $1') - .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '$1'); - } - - /** - * Highlight the contents of tag `name`. - * - * @api private - * @param {string} name - */ - exports.highlightTags = function(name) { - var code = document.getElementById('mocha').getElementsByTagName(name); - for (var i = 0, len = code.length; i < len; ++i) { - code[i].innerHTML = highlight(code[i].innerHTML); - } - }; - - /** - * If a value could have properties, and has none, this function is called, - * which returns a string representation of the empty value. - * - * Functions w/ no properties return `'[Function]'` - * Arrays w/ length === 0 return `'[]'` - * Objects w/ no properties return `'{}'` - * All else: return result of `value.toString()` - * - * @api private - * @param {*} value The value to inspect. - * @param {string} [type] The type of the value, if known. - * @returns {string} - */ - function emptyRepresentation(value, type) { - type = type || exports.type(value); - - switch (type) { - case 'function': - return '[Function]'; - case 'object': - return '{}'; - case 'array': - return '[]'; - default: - return value.toString(); - } - } - - /** - * Takes some variable and asks `Object.prototype.toString()` what it thinks it - * is. - * - * @api private - * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString - * @param {*} value The value to test. - * @returns {string} - * @example - * type({}) // 'object' - * type([]) // 'array' - * type(1) // 'number' - * type(false) // 'boolean' - * type(Infinity) // 'number' - * type(null) // 'null' - * type(new Date()) // 'date' - * type(/foo/) // 'regexp' - * type('type') // 'string' - * type(global) // 'global' - */ - exports.type = function type(value) { - if (value === undefined) { - return 'undefined'; - } else if (value === null) { - return 'null'; - } else if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) { - return 'buffer'; - } - return Object.prototype.toString.call(value) - .replace(/^\[.+\s(.+?)\]$/, '$1') - .toLowerCase(); - }; - - /** - * Stringify `value`. Different behavior depending on type of value: - * - * - If `value` is undefined or null, return `'[undefined]'` or `'[null]'`, respectively. - * - If `value` is not an object, function or array, return result of `value.toString()` wrapped in double-quotes. - * - If `value` is an *empty* object, function, or array, return result of function - * {@link emptyRepresentation}. - * - If `value` has properties, call {@link exports.canonicalize} on it, then return result of - * JSON.stringify(). - * - * @api private - * @see exports.type - * @param {*} value - * @return {string} - */ - exports.stringify = function(value) { - var type = exports.type(value); - - if (!~exports.indexOf(['object', 'array', 'function'], type)) { - if (type !== 'buffer') { - return jsonStringify(value); - } - var json = value.toJSON(); - // Based on the toJSON result - return jsonStringify(json.data && json.type ? json.data : json, 2) - .replace(/,(\n|$)/g, '$1'); - } - - for (var prop in value) { - if (Object.prototype.hasOwnProperty.call(value, prop)) { - return jsonStringify(exports.canonicalize(value), 2).replace(/,(\n|$)/g, '$1'); - } - } - - return emptyRepresentation(value, type); - }; - - /** - * like JSON.stringify but more sense. - * - * @api private - * @param {Object} object - * @param {number=} spaces - * @param {number=} depth - * @returns {*} - */ - function jsonStringify(object, spaces, depth) { - if (typeof spaces === 'undefined') { - // primitive types - return _stringify(object); - } - - depth = depth || 1; - var space = spaces * depth; - var str = isArray(object) ? '[' : '{'; - var end = isArray(object) ? ']' : '}'; - var length = object.length || exports.keys(object).length; - // `.repeat()` polyfill - function repeat(s, n) { - return new Array(n).join(s); - } - - function _stringify(val) { - switch (exports.type(val)) { - case 'null': - case 'undefined': - val = '[' + val + ']'; - break; - case 'array': - case 'object': - val = jsonStringify(val, spaces, depth + 1); - break; - case 'boolean': - case 'regexp': - case 'number': - val = val === 0 && (1 / val) === -Infinity // `-0` - ? '-0' - : val.toString(); - break; - case 'date': - var sDate = isNaN(val.getTime()) // Invalid date - ? val.toString() - : val.toISOString(); - val = '[Date: ' + sDate + ']'; - break; - case 'buffer': - var json = val.toJSON(); - // Based on the toJSON result - json = json.data && json.type ? json.data : json; - val = '[Buffer: ' + jsonStringify(json, 2, depth + 1) + ']'; - break; - default: - val = (val === '[Function]' || val === '[Circular]') - ? val - : JSON.stringify(val); // string - } - return val; - } - - for (var i in object) { - if (!object.hasOwnProperty(i)) { - continue; // not my business - } - --length; - str += '\n ' + repeat(' ', space) - + (isArray(object) ? '' : '"' + i + '": ') // key - + _stringify(object[i]) // value - + (length ? ',' : ''); // comma - } - - return str - // [], {} - + (str.length !== 1 ? '\n' + repeat(' ', --space) + end : end); - } - - /** - * Test if a value is a buffer. - * - * @api private - * @param {*} value The value to test. - * @return {boolean} True if `value` is a buffer, otherwise false - */ - exports.isBuffer = function(value) { - return typeof Buffer !== 'undefined' && Buffer.isBuffer(value); - }; - - /** - * Return a new Thing that has the keys in sorted order. Recursive. - * - * If the Thing... - * - has already been seen, return string `'[Circular]'` - * - is `undefined`, return string `'[undefined]'` - * - is `null`, return value `null` - * - is some other primitive, return the value - * - is not a primitive or an `Array`, `Object`, or `Function`, return the value of the Thing's `toString()` method - * - is a non-empty `Array`, `Object`, or `Function`, return the result of calling this function again. - * - is an empty `Array`, `Object`, or `Function`, return the result of calling `emptyRepresentation()` - * - * @api private - * @see {@link exports.stringify} - * @param {*} value Thing to inspect. May or may not have properties. - * @param {Array} [stack=[]] Stack of seen values - * @return {(Object|Array|Function|string|undefined)} - */ - exports.canonicalize = function(value, stack) { - var canonicalizedObj; - /* eslint-disable no-unused-vars */ - var prop; - /* eslint-enable no-unused-vars */ - var type = exports.type(value); - function withStack(value, fn) { - stack.push(value); - fn(); - stack.pop(); - } - - stack = stack || []; - - if (exports.indexOf(stack, value) !== -1) { - return '[Circular]'; - } - - switch (type) { - case 'undefined': - case 'buffer': - case 'null': - canonicalizedObj = value; - break; - case 'array': - withStack(value, function() { - canonicalizedObj = exports.map(value, function(item) { - return exports.canonicalize(item, stack); - }); - }); - break; - case 'function': - /* eslint-disable guard-for-in */ - for (prop in value) { - canonicalizedObj = {}; - break; - } - /* eslint-enable guard-for-in */ - if (!canonicalizedObj) { - canonicalizedObj = emptyRepresentation(value, type); - break; - } - /* falls through */ - case 'object': - canonicalizedObj = canonicalizedObj || {}; - withStack(value, function() { - exports.forEach(exports.keys(value).sort(), function(key) { - canonicalizedObj[key] = exports.canonicalize(value[key], stack); - }); - }); - break; - case 'date': - case 'number': - case 'regexp': - case 'boolean': - canonicalizedObj = value; - break; - default: - canonicalizedObj = value.toString(); - } - - return canonicalizedObj; - }; - - /** - * Lookup file names at the given `path`. - * - * @api public - * @param {string} path Base path to start searching from. - * @param {string[]} extensions File extensions to look for. - * @param {boolean} recursive Whether or not to recurse into subdirectories. - * @return {string[]} An array of paths. - */ - exports.lookupFiles = function lookupFiles(path, extensions, recursive) { - var files = []; - var re = new RegExp('\\.(' + extensions.join('|') + ')$'); - - if (!exists(path)) { - if (exists(path + '.js')) { - path += '.js'; - } else { - files = glob.sync(path); - if (!files.length) { - throw new Error("cannot resolve path (or pattern) '" + path + "'"); - } - return files; - } - } - - try { - var stat = statSync(path); - if (stat.isFile()) { - return path; - } - } catch (err) { - // ignore error - return; - } - - readdirSync(path).forEach(function(file) { - file = join(path, file); - try { - var stat = statSync(file); - if (stat.isDirectory()) { - if (recursive) { - files = files.concat(lookupFiles(file, extensions, recursive)); - } - return; - } - } catch (err) { - // ignore error - return; - } - if (!stat.isFile() || !re.test(file) || basename(file)[0] === '.') { - return; - } - files.push(file); - }); - - return files; - }; - - /** - * Generate an undefined error with a message warning the user. - * - * @return {Error} - */ - - exports.undefinedError = function() { - return new Error('Caught undefined error, did you throw without specifying what?'); - }; - - /** - * Generate an undefined error if `err` is not defined. - * - * @param {Error} err - * @return {Error} - */ - - exports.getError = function(err) { - return err || exports.undefinedError(); - }; - - /** - * @summary - * This Filter based on `mocha-clean` module.(see: `github.com/rstacruz/mocha-clean`) - * @description - * When invoking this function you get a filter function that get the Error.stack as an input, - * and return a prettify output. - * (i.e: strip Mocha and internal node functions from stack trace). - * @returns {Function} - */ - exports.stackTraceFilter = function() { - // TODO: Replace with `process.browser` - var slash = '/'; - var is = typeof document === 'undefined' ? { - node: true - } : { - browser: true - }; - var cwd = is.node - ? process.cwd() + slash - : (typeof location === 'undefined' ? window.location : location).href.replace(/\/[^\/]*$/, '/'); - - function isMochaInternal(line) { - return (~line.indexOf('node_modules' + slash + 'mocha' + slash)) - || (~line.indexOf('components' + slash + 'mochajs' + slash)) - || (~line.indexOf('components' + slash + 'mocha' + slash)) - || (~line.indexOf(slash + 'mocha.js')); - } - - function isNodeInternal(line) { - return (~line.indexOf('(timers.js:')) - || (~line.indexOf('(events.js:')) - || (~line.indexOf('(node.js:')) - || (~line.indexOf('(module.js:')) - || (~line.indexOf('GeneratorFunctionPrototype.next (native)')) - || false; - } - - return function(stack) { - stack = stack.split('\n'); - - stack = exports.reduce(stack, function(list, line) { - if (isMochaInternal(line)) { - return list; - } - - if (is.node && isNodeInternal(line)) { - return list; - } - - // Clean up cwd(absolute) - list.push(line.replace(cwd, '')); - return list; - }, []); - - return stack.join('\n'); - }; - }; - - }).call(this, require('_process'), require("buffer").Buffer) - }, { - "_process": 51, - "buffer": 43, - "debug": 2, - "fs": 41, - "glob": 41, - "path": 41, - "util": 66 - }], - 40: [function(require, module, exports) { - (function(process) { - var WritableStream = require('stream').Writable - var inherits = require('util').inherits - - module.exports = BrowserStdout - - - inherits(BrowserStdout, WritableStream) - - function BrowserStdout(opts) { - if (!(this instanceof BrowserStdout)) { - return new BrowserStdout(opts) - } - - opts = opts || {} - WritableStream.call(this, opts) - this.label = (opts.label !== undefined) ? opts.label : 'stdout' - } - - BrowserStdout.prototype._write = function(chunks, encoding, cb) { - var output = chunks.toString ? chunks.toString() : chunks - if (this.label === false) { - console.log(output) - } else { - console.log(this.label + ':', output) - } - process.nextTick(cb) - } - - }).call(this, require('_process')) - }, { - "_process": 51, - "stream": 63, - "util": 66 - }], - 41: [function(require, module, exports) {}, {}], - 42: [function(require, module, exports) { - arguments[4][41][0].apply(exports, arguments) - }, { - "dup": 41 - }], - 43: [function(require, module, exports) { - /*! - * The buffer module from node.js, for the browser. - * - * @author Feross Aboukhadijeh - * @license MIT - */ - - var base64 = require('base64-js') - var ieee754 = require('ieee754') - var isArray = require('is-array') - - exports.Buffer = Buffer - exports.SlowBuffer = SlowBuffer - exports.INSPECT_MAX_BYTES = 50 - Buffer.poolSize = 8192 // not used by this implementation - - var rootParent = {} - - /** - * If `Buffer.TYPED_ARRAY_SUPPORT`: - * === true Use Uint8Array implementation (fastest) - * === false Use Object implementation (most compatible, even IE6) - * - * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, - * Opera 11.6+, iOS 4.2+. - * - * Due to various browser bugs, sometimes the Object implementation will be used even - * when the browser supports typed arrays. - * - * Note: - * - * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances, - * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438. - * - * - Safari 5-7 lacks support for changing the `Object.prototype.constructor` property - * on objects. - * - * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function. - * - * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of - * incorrect length in some situations. - - * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they - * get the Object implementation, which is slower but behaves correctly. - */ - Buffer.TYPED_ARRAY_SUPPORT = (function() { - function Bar() { - } - try { - var arr = new Uint8Array(1) - arr.foo = function() { - return 42 - } - arr.constructor = Bar - return arr.foo() === 42 && // typed array instances can be augmented - arr.constructor === Bar && // constructor can be set - typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray` - arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray` - } catch (e) { - return false - } - })() - - function kMaxLength() { - return Buffer.TYPED_ARRAY_SUPPORT - ? 0x7fffffff - : 0x3fffffff - } - - /** - * Class: Buffer - * ============= - * - * The Buffer constructor returns instances of `Uint8Array` that are augmented - * with function properties for all the node `Buffer` API functions. We use - * `Uint8Array` so that square bracket notation works as expected -- it returns - * a single octet. - * - * By augmenting the instances, we can avoid modifying the `Uint8Array` - * prototype. - */ - function Buffer(arg) { - if (!(this instanceof Buffer)) { - // Avoid going through an ArgumentsAdaptorTrampoline in the common case. - if (arguments.length > 1) { - return new Buffer(arg, arguments[1]) - } - return new Buffer(arg) - } - - this.length = 0 - this.parent = undefined - - // Common case. - if (typeof arg === 'number') { - return fromNumber(this, arg) - } - - // Slightly less common case. - if (typeof arg === 'string') { - return fromString(this, arg, arguments.length > 1 ? arguments[1] : 'utf8') - } - - // Unusual. - return fromObject(this, arg) - } - - function fromNumber(that, length) { - that = allocate(that, length < 0 ? 0 : checked(length) | 0) - if (!Buffer.TYPED_ARRAY_SUPPORT) { - for (var i = 0; i < length; i++) { - that[i] = 0 - } - } - return that - } - - function fromString(that, string, encoding) { - if (typeof encoding !== 'string' || encoding === '') { - encoding = 'utf8' - } - - // Assumption: byteLength() return value is always < kMaxLength. - var length = byteLength(string, encoding) | 0 - that = allocate(that, length) - - that.write(string, encoding) - return that - } - - function fromObject(that, object) { - if (Buffer.isBuffer(object)) { - return fromBuffer(that, object) - } - - if (isArray(object)) { - return fromArray(that, object) - } - - if (object == null) { - throw new TypeError('must start with number, buffer, array or string') - } - - if (typeof ArrayBuffer !== 'undefined') { - if (object.buffer instanceof ArrayBuffer) { - return fromTypedArray(that, object) - } - if (object instanceof ArrayBuffer) { - return fromArrayBuffer(that, object) - } - } - - if (object.length) { - return fromArrayLike(that, object) - } - - return fromJsonObject(that, object) - } - - function fromBuffer(that, buffer) { - var length = checked(buffer.length) | 0 - that = allocate(that, length) - buffer.copy(that, 0, 0, length) - return that - } - - function fromArray(that, array) { - var length = checked(array.length) | 0 - that = allocate(that, length) - for (var i = 0; i < length; i += 1) { - that[i] = array[i] & 255 - } - return that - } - - // Duplicate of fromArray() to keep fromArray() monomorphic. - function fromTypedArray(that, array) { - var length = checked(array.length) | 0 - that = allocate(that, length) - // Truncating the elements is probably not what people expect from typed - // arrays with BYTES_PER_ELEMENT > 1 but it's compatible with the behavior - // of the old Buffer constructor. - for (var i = 0; i < length; i += 1) { - that[i] = array[i] & 255 - } - return that - } - - function fromArrayBuffer(that, array) { - if (Buffer.TYPED_ARRAY_SUPPORT) { - // Return an augmented `Uint8Array` instance, for best performance - array.byteLength - that = Buffer._augment(new Uint8Array(array)) - } else { - // Fallback: Return an object instance of the Buffer class - that = fromTypedArray(that, new Uint8Array(array)) - } - return that - } - - function fromArrayLike(that, array) { - var length = checked(array.length) | 0 - that = allocate(that, length) - for (var i = 0; i < length; i += 1) { - that[i] = array[i] & 255 - } - return that - } - - // Deserialize { type: 'Buffer', data: [1,2,3,...] } into a Buffer object. - // Returns a zero-length buffer for inputs that don't conform to the spec. - function fromJsonObject(that, object) { - var array - var length = 0 - - if (object.type === 'Buffer' && isArray(object.data)) { - array = object.data - length = checked(array.length) | 0 - } - that = allocate(that, length) - - for (var i = 0; i < length; i += 1) { - that[i] = array[i] & 255 - } - return that - } - - function allocate(that, length) { - if (Buffer.TYPED_ARRAY_SUPPORT) { - // Return an augmented `Uint8Array` instance, for best performance - that = Buffer._augment(new Uint8Array(length)) - } else { - // Fallback: Return an object instance of the Buffer class - that.length = length - that._isBuffer = true - } - - var fromPool = length !== 0 && length <= Buffer.poolSize >>> 1 - if (fromPool) { - that.parent = rootParent - } - - return that - } - - function checked(length) { - // Note: cannot use `length < kMaxLength` here because that fails when - // length is NaN (which is otherwise coerced to zero.) - if (length >= kMaxLength()) { - throw new RangeError('Attempt to allocate Buffer larger than maximum ' + - 'size: 0x' + kMaxLength().toString(16) + ' bytes') - } - return length | 0 - } - - function SlowBuffer(subject, encoding) { - if (!(this instanceof SlowBuffer)) { - return new SlowBuffer(subject, encoding) - } - - var buf = new Buffer(subject, encoding) - delete buf.parent - return buf - } - - Buffer.isBuffer = function isBuffer(b) { - return !!(b != null && b._isBuffer) - } - - Buffer.compare = function compare(a, b) { - if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { - throw new TypeError('Arguments must be Buffers') - } - - if (a === b) { - return 0 - } - - var x = a.length - var y = b.length - - var i = 0 - var len = Math.min(x, y) - while (i < len) { - if (a[i] !== b[i]) { - break - } - - ++i - } - - if (i !== len) { - x = a[i] - y = b[i] - } - - if (x < y) { - return -1 - } - if (y < x) { - return 1 - } - return 0 - } - - Buffer.isEncoding = function isEncoding(encoding) { - switch (String(encoding).toLowerCase()) { - case 'hex': - case 'utf8': - case 'utf-8': - case 'ascii': - case 'binary': - case 'base64': - case 'raw': - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return true - default: - return false - } - } - - Buffer.concat = function concat(list, length) { - if (!isArray(list)) { - throw new TypeError('list argument must be an Array of Buffers.') - } - - if (list.length === 0) { - return new Buffer(0) - } - - var i - if (length === undefined) { - length = 0 - for (i = 0; i < list.length; i++) { - length += list[i].length - } - } - - var buf = new Buffer(length) - var pos = 0 - for (i = 0; i < list.length; i++) { - var item = list[i] - item.copy(buf, pos) - pos += item.length - } - return buf - } - - function byteLength(string, encoding) { - if (typeof string !== 'string') { - string = '' + string - } - - var len = string.length - if (len === 0) { - return 0 - } - - // Use a for loop to avoid recursion - var loweredCase = false - for (;;) { - switch (encoding) { - case 'ascii': - case 'binary': - // Deprecated - case 'raw': - case 'raws': - return len - case 'utf8': - case 'utf-8': - return utf8ToBytes(string).length - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return len * 2 - case 'hex': - return len >>> 1 - case 'base64': - return base64ToBytes(string).length - default: - if (loweredCase) { - return utf8ToBytes(string).length - } // assume utf8 - encoding = ('' + encoding).toLowerCase() - loweredCase = true - } - } - } - Buffer.byteLength = byteLength - - // pre-set for values that may exist in the future - Buffer.prototype.length = undefined - Buffer.prototype.parent = undefined - - function slowToString(encoding, start, end) { - var loweredCase = false - - start = start | 0 - end = end === undefined || end === Infinity ? this.length : end | 0 - - if (!encoding) { - encoding = 'utf8' - } - if (start < 0) { - start = 0 - } - if (end > this.length) { - end = this.length - } - if (end <= start) { - return '' - } - - while (true) { - switch (encoding) { - case 'hex': - return hexSlice(this, start, end) - - case 'utf8': - case 'utf-8': - return utf8Slice(this, start, end) - - case 'ascii': - return asciiSlice(this, start, end) - - case 'binary': - return binarySlice(this, start, end) - - case 'base64': - return base64Slice(this, start, end) - - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return utf16leSlice(this, start, end) - - default: - if (loweredCase) { - throw new TypeError('Unknown encoding: ' + encoding) - } - encoding = (encoding + '').toLowerCase() - loweredCase = true - } - } - } - - Buffer.prototype.toString = function toString() { - var length = this.length | 0 - if (length === 0) { - return '' - } - if (arguments.length === 0) { - return utf8Slice(this, 0, length) - } - return slowToString.apply(this, arguments) - } - - Buffer.prototype.equals = function equals(b) { - if (!Buffer.isBuffer(b)) { - throw new TypeError('Argument must be a Buffer') - } - if (this === b) { - return true - } - return Buffer.compare(this, b) === 0 - } - - Buffer.prototype.inspect = function inspect() { - var str = '' - var max = exports.INSPECT_MAX_BYTES - if (this.length > 0) { - str = this.toString('hex', 0, max).match(/.{2}/g).join(' ') - if (this.length > max) { - str += ' ... ' - } - } - return '' - } - - Buffer.prototype.compare = function compare(b) { - if (!Buffer.isBuffer(b)) { - throw new TypeError('Argument must be a Buffer') - } - if (this === b) { - return 0 - } - return Buffer.compare(this, b) - } - - Buffer.prototype.indexOf = function indexOf(val, byteOffset) { - if (byteOffset > 0x7fffffff) { - byteOffset = 0x7fffffff - } else if (byteOffset < -0x80000000) { - byteOffset = -0x80000000 - } - byteOffset >>= 0 - - if (this.length === 0) { - return -1 - } - if (byteOffset >= this.length) { - return -1 - } - - // Negative offsets start from the end of the buffer - if (byteOffset < 0) { - byteOffset = Math.max(this.length + byteOffset, 0) - } - - if (typeof val === 'string') { - if (val.length === 0) { - return -1 - } // special case: looking for empty string always fails - return String.prototype.indexOf.call(this, val, byteOffset) - } - if (Buffer.isBuffer(val)) { - return arrayIndexOf(this, val, byteOffset) - } - if (typeof val === 'number') { - if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') { - return Uint8Array.prototype.indexOf.call(this, val, byteOffset) - } - return arrayIndexOf(this, [val], byteOffset) - } - - function arrayIndexOf(arr, val, byteOffset) { - var foundIndex = -1 - for (var i = 0; byteOffset + i < arr.length; i++) { - if (arr[byteOffset + i] === val[foundIndex === -1 ? 0 : i - foundIndex]) { - if (foundIndex === -1) { - foundIndex = i - } - if (i - foundIndex + 1 === val.length) { - return byteOffset + foundIndex - } - } else { - foundIndex = -1 - } - } - return -1 - } - - throw new TypeError('val must be string, number or Buffer') - } - - // `get` is deprecated - Buffer.prototype.get = function get(offset) { - console.log('.get() is deprecated. Access using array indexes instead.') - return this.readUInt8(offset) - } - - // `set` is deprecated - Buffer.prototype.set = function set(v, offset) { - console.log('.set() is deprecated. Access using array indexes instead.') - return this.writeUInt8(v, offset) - } - - function hexWrite(buf, string, offset, length) { - offset = Number(offset) || 0 - var remaining = buf.length - offset - if (!length) { - length = remaining - } else { - length = Number(length) - if (length > remaining) { - length = remaining - } - } - - // must be an even number of digits - var strLen = string.length - if (strLen % 2 !== 0) { - throw new Error('Invalid hex string') - } - - if (length > strLen / 2) { - length = strLen / 2 - } - for (var i = 0; i < length; i++) { - var parsed = parseInt(string.substr(i * 2, 2), 16) - if (isNaN(parsed)) { - throw new Error('Invalid hex string') - } - buf[offset + i] = parsed - } - return i - } - - function utf8Write(buf, string, offset, length) { - return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) - } - - function asciiWrite(buf, string, offset, length) { - return blitBuffer(asciiToBytes(string), buf, offset, length) - } - - function binaryWrite(buf, string, offset, length) { - return asciiWrite(buf, string, offset, length) - } - - function base64Write(buf, string, offset, length) { - return blitBuffer(base64ToBytes(string), buf, offset, length) - } - - function ucs2Write(buf, string, offset, length) { - return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) - } - - Buffer.prototype.write = function write(string, offset, length, encoding) { - // Buffer#write(string) - if (offset === undefined) { - encoding = 'utf8' - length = this.length - offset = 0 - // Buffer#write(string, encoding) - } else if (length === undefined && typeof offset === 'string') { - encoding = offset - length = this.length - offset = 0 - // Buffer#write(string, offset[, length][, encoding]) - } else if (isFinite(offset)) { - offset = offset | 0 - if (isFinite(length)) { - length = length | 0 - if (encoding === undefined) { - encoding = 'utf8' - } - } else { - encoding = length - length = undefined - } - // legacy write(string, encoding, offset, length) - remove in v0.13 - } else { - var swap = encoding - encoding = offset - offset = length | 0 - length = swap - } - - var remaining = this.length - offset - if (length === undefined || length > remaining) { - length = remaining - } - - if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { - throw new RangeError('attempt to write outside buffer bounds') - } - - if (!encoding) { - encoding = 'utf8' - } - - var loweredCase = false - for (;;) { - switch (encoding) { - case 'hex': - return hexWrite(this, string, offset, length) - - case 'utf8': - case 'utf-8': - return utf8Write(this, string, offset, length) - - case 'ascii': - return asciiWrite(this, string, offset, length) - - case 'binary': - return binaryWrite(this, string, offset, length) - - case 'base64': - // Warning: maxLength not taken into account in base64Write - return base64Write(this, string, offset, length) - - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return ucs2Write(this, string, offset, length) - - default: - if (loweredCase) { - throw new TypeError('Unknown encoding: ' + encoding) - } - encoding = ('' + encoding).toLowerCase() - loweredCase = true - } - } - } - - Buffer.prototype.toJSON = function toJSON() { - return { - type: 'Buffer', - data: Array.prototype.slice.call(this._arr || this, 0) - } - } - - function base64Slice(buf, start, end) { - if (start === 0 && end === buf.length) { - return base64.fromByteArray(buf) - } else { - return base64.fromByteArray(buf.slice(start, end)) - } - } - - function utf8Slice(buf, start, end) { - end = Math.min(buf.length, end) - var res = [] - - var i = start - while (i < end) { - var firstByte = buf[i] - var codePoint = null - var bytesPerSequence = (firstByte > 0xEF) ? 4 - : (firstByte > 0xDF) ? 3 - : (firstByte > 0xBF) ? 2 - : 1 - - if (i + bytesPerSequence <= end) { - var secondByte, - thirdByte, - fourthByte, - tempCodePoint - - switch (bytesPerSequence) { - case 1: - if (firstByte < 0x80) { - codePoint = firstByte - } - break - case 2: - secondByte = buf[i + 1] - if ((secondByte & 0xC0) === 0x80) { - tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F) - if (tempCodePoint > 0x7F) { - codePoint = tempCodePoint - } - } - break - case 3: - secondByte = buf[i + 1] - thirdByte = buf[i + 2] - if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { - tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F) - if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { - codePoint = tempCodePoint - } - } - break - case 4: - secondByte = buf[i + 1] - thirdByte = buf[i + 2] - fourthByte = buf[i + 3] - if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { - tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F) - if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { - codePoint = tempCodePoint - } - } - } - } - - if (codePoint === null) { - // we did not generate a valid codePoint so insert a - // replacement char (U+FFFD) and advance only 1 byte - codePoint = 0xFFFD - bytesPerSequence = 1 - } else if (codePoint > 0xFFFF) { - // encode to utf16 (surrogate pair dance) - codePoint -= 0x10000 - res.push(codePoint >>> 10 & 0x3FF | 0xD800) - codePoint = 0xDC00 | codePoint & 0x3FF - } - - res.push(codePoint) - i += bytesPerSequence - } - - return decodeCodePointsArray(res) - } - - // Based on http://stackoverflow.com/a/22747272/680742, the browser with - // the lowest limit is Chrome, with 0x10000 args. - // We go 1 magnitude less, for safety - var MAX_ARGUMENTS_LENGTH = 0x1000 - - function decodeCodePointsArray(codePoints) { - var len = codePoints.length - if (len <= MAX_ARGUMENTS_LENGTH) { - return String.fromCharCode.apply(String, codePoints) // avoid extra slice() - } - - // Decode in chunks to avoid "call stack size exceeded". - var res = '' - var i = 0 - while (i < len) { - res += String.fromCharCode.apply( - String, - codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) - ) - } - return res - } - - function asciiSlice(buf, start, end) { - var ret = '' - end = Math.min(buf.length, end) - - for (var i = start; i < end; i++) { - ret += String.fromCharCode(buf[i] & 0x7F) - } - return ret - } - - function binarySlice(buf, start, end) { - var ret = '' - end = Math.min(buf.length, end) - - for (var i = start; i < end; i++) { - ret += String.fromCharCode(buf[i]) - } - return ret - } - - function hexSlice(buf, start, end) { - var len = buf.length - - if (!start || start < 0) { - start = 0 - } - if (!end || end < 0 || end > len) { - end = len - } - - var out = '' - for (var i = start; i < end; i++) { - out += toHex(buf[i]) - } - return out - } - - function utf16leSlice(buf, start, end) { - var bytes = buf.slice(start, end) - var res = '' - for (var i = 0; i < bytes.length; i += 2) { - res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256) - } - return res - } - - Buffer.prototype.slice = function slice(start, end) { - var len = this.length - start = ~~start - end = end === undefined ? len : ~~end - - if (start < 0) { - start += len - if (start < 0) { - start = 0 - } - } else if (start > len) { - start = len - } - - if (end < 0) { - end += len - if (end < 0) { - end = 0 - } - } else if (end > len) { - end = len - } - - if (end < start) { - end = start - } - - var newBuf - if (Buffer.TYPED_ARRAY_SUPPORT) { - newBuf = Buffer._augment(this.subarray(start, end)) - } else { - var sliceLen = end - start - newBuf = new Buffer(sliceLen, undefined) - for (var i = 0; i < sliceLen; i++) { - newBuf[i] = this[i + start] - } - } - - if (newBuf.length) { - newBuf.parent = this.parent || this - } - - return newBuf - } - - /* - * Need to make sure that buffer isn't trying to write out of bounds. - */ - function checkOffset(offset, ext, length) { - if ((offset % 1) !== 0 || offset < 0) { - throw new RangeError('offset is not uint') - } - if (offset + ext > length) { - throw new RangeError('Trying to access beyond buffer length') - } - } - - Buffer.prototype.readUIntLE = function readUIntLE(offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) { - checkOffset(offset, byteLength, this.length) - } - - var val = this[offset] - var mul = 1 - var i = 0 - while (++i < byteLength && (mul *= 0x100)) { - val += this[offset + i] * mul - } - - return val - } - - Buffer.prototype.readUIntBE = function readUIntBE(offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) { - checkOffset(offset, byteLength, this.length) - } - - var val = this[offset + --byteLength] - var mul = 1 - while (byteLength > 0 && (mul *= 0x100)) { - val += this[offset + --byteLength] * mul - } - - return val - } - - Buffer.prototype.readUInt8 = function readUInt8(offset, noAssert) { - if (!noAssert) { - checkOffset(offset, 1, this.length) - } - return this[offset] - } - - Buffer.prototype.readUInt16LE = function readUInt16LE(offset, noAssert) { - if (!noAssert) { - checkOffset(offset, 2, this.length) - } - return this[offset] | (this[offset + 1] << 8) - } - - Buffer.prototype.readUInt16BE = function readUInt16BE(offset, noAssert) { - if (!noAssert) { - checkOffset(offset, 2, this.length) - } - return (this[offset] << 8) | this[offset + 1] - } - - Buffer.prototype.readUInt32LE = function readUInt32LE(offset, noAssert) { - if (!noAssert) { - checkOffset(offset, 4, this.length) - } - - return ((this[offset]) | - (this[offset + 1] << 8) | - (this[offset + 2] << 16)) + - (this[offset + 3] * 0x1000000) - } - - Buffer.prototype.readUInt32BE = function readUInt32BE(offset, noAssert) { - if (!noAssert) { - checkOffset(offset, 4, this.length) - } - - return (this[offset] * 0x1000000) + - ((this[offset + 1] << 16) | - (this[offset + 2] << 8) | - this[offset + 3]) - } - - Buffer.prototype.readIntLE = function readIntLE(offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) { - checkOffset(offset, byteLength, this.length) - } - - var val = this[offset] - var mul = 1 - var i = 0 - while (++i < byteLength && (mul *= 0x100)) { - val += this[offset + i] * mul - } - mul *= 0x80 - - if (val >= mul) { - val -= Math.pow(2, 8 * byteLength) - } - - return val - } - - Buffer.prototype.readIntBE = function readIntBE(offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) { - checkOffset(offset, byteLength, this.length) - } - - var i = byteLength - var mul = 1 - var val = this[offset + --i] - while (i > 0 && (mul *= 0x100)) { - val += this[offset + --i] * mul - } - mul *= 0x80 - - if (val >= mul) { - val -= Math.pow(2, 8 * byteLength) - } - - return val - } - - Buffer.prototype.readInt8 = function readInt8(offset, noAssert) { - if (!noAssert) { - checkOffset(offset, 1, this.length) - } - if (!(this[offset] & 0x80)) { - return (this[offset]) - } - return ((0xff - this[offset] + 1) * -1) - } - - Buffer.prototype.readInt16LE = function readInt16LE(offset, noAssert) { - if (!noAssert) { - checkOffset(offset, 2, this.length) - } - var val = this[offset] | (this[offset + 1] << 8) - return (val & 0x8000) ? val | 0xFFFF0000 : val - } - - Buffer.prototype.readInt16BE = function readInt16BE(offset, noAssert) { - if (!noAssert) { - checkOffset(offset, 2, this.length) - } - var val = this[offset + 1] | (this[offset] << 8) - return (val & 0x8000) ? val | 0xFFFF0000 : val - } - - Buffer.prototype.readInt32LE = function readInt32LE(offset, noAssert) { - if (!noAssert) { - checkOffset(offset, 4, this.length) - } - - return (this[offset]) | - (this[offset + 1] << 8) | - (this[offset + 2] << 16) | - (this[offset + 3] << 24) - } - - Buffer.prototype.readInt32BE = function readInt32BE(offset, noAssert) { - if (!noAssert) { - checkOffset(offset, 4, this.length) - } - - return (this[offset] << 24) | - (this[offset + 1] << 16) | - (this[offset + 2] << 8) | - (this[offset + 3]) - } - - Buffer.prototype.readFloatLE = function readFloatLE(offset, noAssert) { - if (!noAssert) { - checkOffset(offset, 4, this.length) - } - return ieee754.read(this, offset, true, 23, 4) - } - - Buffer.prototype.readFloatBE = function readFloatBE(offset, noAssert) { - if (!noAssert) { - checkOffset(offset, 4, this.length) - } - return ieee754.read(this, offset, false, 23, 4) - } - - Buffer.prototype.readDoubleLE = function readDoubleLE(offset, noAssert) { - if (!noAssert) { - checkOffset(offset, 8, this.length) - } - return ieee754.read(this, offset, true, 52, 8) - } - - Buffer.prototype.readDoubleBE = function readDoubleBE(offset, noAssert) { - if (!noAssert) { - checkOffset(offset, 8, this.length) - } - return ieee754.read(this, offset, false, 52, 8) - } - - function checkInt(buf, value, offset, ext, max, min) { - if (!Buffer.isBuffer(buf)) { - throw new TypeError('buffer must be a Buffer instance') - } - if (value > max || value < min) { - throw new RangeError('value is out of bounds') - } - if (offset + ext > buf.length) { - throw new RangeError('index out of range') - } - } - - Buffer.prototype.writeUIntLE = function writeUIntLE(value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) { - checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0) - } - - var mul = 1 - var i = 0 - this[offset] = value & 0xFF - while (++i < byteLength && (mul *= 0x100)) { - this[offset + i] = (value / mul) & 0xFF - } - - return offset + byteLength - } - - Buffer.prototype.writeUIntBE = function writeUIntBE(value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) { - checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0) - } - - var i = byteLength - 1 - var mul = 1 - this[offset + i] = value & 0xFF - while (--i >= 0 && (mul *= 0x100)) { - this[offset + i] = (value / mul) & 0xFF - } - - return offset + byteLength - } - - Buffer.prototype.writeUInt8 = function writeUInt8(value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) { - checkInt(this, value, offset, 1, 0xff, 0) - } - if (!Buffer.TYPED_ARRAY_SUPPORT) { - value = Math.floor(value) - } - this[offset] = value - return offset + 1 - } - - function objectWriteUInt16(buf, value, offset, littleEndian) { - if (value < 0) { - value = 0xffff + value + 1 - } - for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; i++) { - buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>> - (littleEndian ? i : 1 - i) * 8 - } - } - - Buffer.prototype.writeUInt16LE = function writeUInt16LE(value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) { - checkInt(this, value, offset, 2, 0xffff, 0) - } - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = value - this[offset + 1] = (value >>> 8) - } else { - objectWriteUInt16(this, value, offset, true) - } - return offset + 2 - } - - Buffer.prototype.writeUInt16BE = function writeUInt16BE(value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) { - checkInt(this, value, offset, 2, 0xffff, 0) - } - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 8) - this[offset + 1] = value - } else { - objectWriteUInt16(this, value, offset, false) - } - return offset + 2 - } - - function objectWriteUInt32(buf, value, offset, littleEndian) { - if (value < 0) { - value = 0xffffffff + value + 1 - } - for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; i++) { - buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff - } - } - - Buffer.prototype.writeUInt32LE = function writeUInt32LE(value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) { - checkInt(this, value, offset, 4, 0xffffffff, 0) - } - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset + 3] = (value >>> 24) - this[offset + 2] = (value >>> 16) - this[offset + 1] = (value >>> 8) - this[offset] = value - } else { - objectWriteUInt32(this, value, offset, true) - } - return offset + 4 - } - - Buffer.prototype.writeUInt32BE = function writeUInt32BE(value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) { - checkInt(this, value, offset, 4, 0xffffffff, 0) - } - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 24) - this[offset + 1] = (value >>> 16) - this[offset + 2] = (value >>> 8) - this[offset + 3] = value - } else { - objectWriteUInt32(this, value, offset, false) - } - return offset + 4 - } - - Buffer.prototype.writeIntLE = function writeIntLE(value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) { - var limit = Math.pow(2, 8 * byteLength - 1) - - checkInt(this, value, offset, byteLength, limit - 1, -limit) - } - - var i = 0 - var mul = 1 - var sub = value < 0 ? 1 : 0 - this[offset] = value & 0xFF - while (++i < byteLength && (mul *= 0x100)) { - this[offset + i] = ((value / mul) >> 0) - sub & 0xFF - } - - return offset + byteLength - } - - Buffer.prototype.writeIntBE = function writeIntBE(value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) { - var limit = Math.pow(2, 8 * byteLength - 1) - - checkInt(this, value, offset, byteLength, limit - 1, -limit) - } - - var i = byteLength - 1 - var mul = 1 - var sub = value < 0 ? 1 : 0 - this[offset + i] = value & 0xFF - while (--i >= 0 && (mul *= 0x100)) { - this[offset + i] = ((value / mul) >> 0) - sub & 0xFF - } - - return offset + byteLength - } - - Buffer.prototype.writeInt8 = function writeInt8(value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) { - checkInt(this, value, offset, 1, 0x7f, -0x80) - } - if (!Buffer.TYPED_ARRAY_SUPPORT) { - value = Math.floor(value) - } - if (value < 0) { - value = 0xff + value + 1 - } - this[offset] = value - return offset + 1 - } - - Buffer.prototype.writeInt16LE = function writeInt16LE(value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) { - checkInt(this, value, offset, 2, 0x7fff, -0x8000) - } - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = value - this[offset + 1] = (value >>> 8) - } else { - objectWriteUInt16(this, value, offset, true) - } - return offset + 2 - } - - Buffer.prototype.writeInt16BE = function writeInt16BE(value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) { - checkInt(this, value, offset, 2, 0x7fff, -0x8000) - } - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 8) - this[offset + 1] = value - } else { - objectWriteUInt16(this, value, offset, false) - } - return offset + 2 - } - - Buffer.prototype.writeInt32LE = function writeInt32LE(value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) { - checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) - } - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = value - this[offset + 1] = (value >>> 8) - this[offset + 2] = (value >>> 16) - this[offset + 3] = (value >>> 24) - } else { - objectWriteUInt32(this, value, offset, true) - } - return offset + 4 - } - - Buffer.prototype.writeInt32BE = function writeInt32BE(value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) { - checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) - } - if (value < 0) { - value = 0xffffffff + value + 1 - } - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 24) - this[offset + 1] = (value >>> 16) - this[offset + 2] = (value >>> 8) - this[offset + 3] = value - } else { - objectWriteUInt32(this, value, offset, false) - } - return offset + 4 - } - - function checkIEEE754(buf, value, offset, ext, max, min) { - if (value > max || value < min) { - throw new RangeError('value is out of bounds') - } - if (offset + ext > buf.length) { - throw new RangeError('index out of range') - } - if (offset < 0) { - throw new RangeError('index out of range') - } - } - - function writeFloat(buf, value, offset, littleEndian, noAssert) { - if (!noAssert) { - checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38) - } - ieee754.write(buf, value, offset, littleEndian, 23, 4) - return offset + 4 - } - - Buffer.prototype.writeFloatLE = function writeFloatLE(value, offset, noAssert) { - return writeFloat(this, value, offset, true, noAssert) - } - - Buffer.prototype.writeFloatBE = function writeFloatBE(value, offset, noAssert) { - return writeFloat(this, value, offset, false, noAssert) - } - - function writeDouble(buf, value, offset, littleEndian, noAssert) { - if (!noAssert) { - checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308) - } - ieee754.write(buf, value, offset, littleEndian, 52, 8) - return offset + 8 - } - - Buffer.prototype.writeDoubleLE = function writeDoubleLE(value, offset, noAssert) { - return writeDouble(this, value, offset, true, noAssert) - } - - Buffer.prototype.writeDoubleBE = function writeDoubleBE(value, offset, noAssert) { - return writeDouble(this, value, offset, false, noAssert) - } - - // copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) - Buffer.prototype.copy = function copy(target, targetStart, start, end) { - if (!start) { - start = 0 - } - if (!end && end !== 0) { - end = this.length - } - if (targetStart >= target.length) { - targetStart = target.length - } - if (!targetStart) { - targetStart = 0 - } - if (end > 0 && end < start) { - end = start - } - - // Copy 0 bytes; we're done - if (end === start) { - return 0 - } - if (target.length === 0 || this.length === 0) { - return 0 - } - - // Fatal error conditions - if (targetStart < 0) { - throw new RangeError('targetStart out of bounds') - } - if (start < 0 || start >= this.length) { - throw new RangeError('sourceStart out of bounds') - } - if (end < 0) { - throw new RangeError('sourceEnd out of bounds') - } - - // Are we oob? - if (end > this.length) { - end = this.length - } - if (target.length - targetStart < end - start) { - end = target.length - targetStart + start - } - - var len = end - start - var i - - if (this === target && start < targetStart && targetStart < end) { - // descending copy from end - for (i = len - 1; i >= 0; i--) { - target[i + targetStart] = this[i + start] - } - } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) { - // ascending copy from start - for (i = 0; i < len; i++) { - target[i + targetStart] = this[i + start] - } - } else { - target._set(this.subarray(start, start + len), targetStart) - } - - return len - } - - // fill(value, start=0, end=buffer.length) - Buffer.prototype.fill = function fill(value, start, end) { - if (!value) { - value = 0 - } - if (!start) { - start = 0 - } - if (!end) { - end = this.length - } - - if (end < start) { - throw new RangeError('end < start') - } - - // Fill 0 bytes; we're done - if (end === start) { - return - } - if (this.length === 0) { - return - } - - if (start < 0 || start >= this.length) { - throw new RangeError('start out of bounds') - } - if (end < 0 || end > this.length) { - throw new RangeError('end out of bounds') - } - - var i - if (typeof value === 'number') { - for (i = start; i < end; i++) { - this[i] = value - } - } else { - var bytes = utf8ToBytes(value.toString()) - var len = bytes.length - for (i = start; i < end; i++) { - this[i] = bytes[i % len] - } - } - - return this - } - - /** - * Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance. - * Added in Node 0.12. Only available in browsers that support ArrayBuffer. - */ - Buffer.prototype.toArrayBuffer = function toArrayBuffer() { - if (typeof Uint8Array !== 'undefined') { - if (Buffer.TYPED_ARRAY_SUPPORT) { - return (new Buffer(this)).buffer - } else { - var buf = new Uint8Array(this.length) - for (var i = 0, len = buf.length; i < len; i += 1) { - buf[i] = this[i] - } - return buf.buffer - } - } else { - throw new TypeError('Buffer.toArrayBuffer not supported in this browser') - } - } - - // HELPER FUNCTIONS - // ================ - - var BP = Buffer.prototype - - /** - * Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods - */ - Buffer._augment = function _augment(arr) { - arr.constructor = Buffer - arr._isBuffer = true - - // save reference to original Uint8Array set method before overwriting - arr._set = arr.set - - // deprecated - arr.get = BP.get - arr.set = BP.set - - arr.write = BP.write - arr.toString = BP.toString - arr.toLocaleString = BP.toString - arr.toJSON = BP.toJSON - arr.equals = BP.equals - arr.compare = BP.compare - arr.indexOf = BP.indexOf - arr.copy = BP.copy - arr.slice = BP.slice - arr.readUIntLE = BP.readUIntLE - arr.readUIntBE = BP.readUIntBE - arr.readUInt8 = BP.readUInt8 - arr.readUInt16LE = BP.readUInt16LE - arr.readUInt16BE = BP.readUInt16BE - arr.readUInt32LE = BP.readUInt32LE - arr.readUInt32BE = BP.readUInt32BE - arr.readIntLE = BP.readIntLE - arr.readIntBE = BP.readIntBE - arr.readInt8 = BP.readInt8 - arr.readInt16LE = BP.readInt16LE - arr.readInt16BE = BP.readInt16BE - arr.readInt32LE = BP.readInt32LE - arr.readInt32BE = BP.readInt32BE - arr.readFloatLE = BP.readFloatLE - arr.readFloatBE = BP.readFloatBE - arr.readDoubleLE = BP.readDoubleLE - arr.readDoubleBE = BP.readDoubleBE - arr.writeUInt8 = BP.writeUInt8 - arr.writeUIntLE = BP.writeUIntLE - arr.writeUIntBE = BP.writeUIntBE - arr.writeUInt16LE = BP.writeUInt16LE - arr.writeUInt16BE = BP.writeUInt16BE - arr.writeUInt32LE = BP.writeUInt32LE - arr.writeUInt32BE = BP.writeUInt32BE - arr.writeIntLE = BP.writeIntLE - arr.writeIntBE = BP.writeIntBE - arr.writeInt8 = BP.writeInt8 - arr.writeInt16LE = BP.writeInt16LE - arr.writeInt16BE = BP.writeInt16BE - arr.writeInt32LE = BP.writeInt32LE - arr.writeInt32BE = BP.writeInt32BE - arr.writeFloatLE = BP.writeFloatLE - arr.writeFloatBE = BP.writeFloatBE - arr.writeDoubleLE = BP.writeDoubleLE - arr.writeDoubleBE = BP.writeDoubleBE - arr.fill = BP.fill - arr.inspect = BP.inspect - arr.toArrayBuffer = BP.toArrayBuffer - - return arr - } - - var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g - - function base64clean(str) { - // Node strips out invalid characters like \n and \t from the string, base64-js does not - str = stringtrim(str).replace(INVALID_BASE64_RE, '') - // Node converts strings with length < 2 to '' - if (str.length < 2) { - return '' - } - // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not - while (str.length % 4 !== 0) { - str = str + '=' - } - return str - } - - function stringtrim(str) { - if (str.trim) { - return str.trim() - } - return str.replace(/^\s+|\s+$/g, '') - } - - function toHex(n) { - if (n < 16) { - return '0' + n.toString(16) - } - return n.toString(16) - } - - function utf8ToBytes(string, units) { - units = units || Infinity - var codePoint - var length = string.length - var leadSurrogate = null - var bytes = [] - - for (var i = 0; i < length; i++) { - codePoint = string.charCodeAt(i) - - // is surrogate component - if (codePoint > 0xD7FF && codePoint < 0xE000) { - // last char was a lead - if (!leadSurrogate) { - // no lead yet - if (codePoint > 0xDBFF) { - // unexpected trail - if ((units -= 3) > -1) { - bytes.push(0xEF, 0xBF, 0xBD) - } - continue - } else if (i + 1 === length) { - // unpaired lead - if ((units -= 3) > -1) { - bytes.push(0xEF, 0xBF, 0xBD) - } - continue - } - - // valid lead - leadSurrogate = codePoint - - continue - } - - // 2 leads in a row - if (codePoint < 0xDC00) { - if ((units -= 3) > -1) { - bytes.push(0xEF, 0xBF, 0xBD) - } - leadSurrogate = codePoint - continue - } - - // valid surrogate pair - codePoint = leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00 | 0x10000 - } else if (leadSurrogate) { - // valid bmp char, but last char was a lead - if ((units -= 3) > -1) { - bytes.push(0xEF, 0xBF, 0xBD) - } - } - - leadSurrogate = null - - // encode utf8 - if (codePoint < 0x80) { - if ((units -= 1) < 0) { - break - } - bytes.push(codePoint) - } else if (codePoint < 0x800) { - if ((units -= 2) < 0) { - break - } - bytes.push( - codePoint >> 0x6 | 0xC0, - codePoint & 0x3F | 0x80 - ) - } else if (codePoint < 0x10000) { - if ((units -= 3) < 0) { - break - } - bytes.push( - codePoint >> 0xC | 0xE0, - codePoint >> 0x6 & 0x3F | 0x80, - codePoint & 0x3F | 0x80 - ) - } else if (codePoint < 0x110000) { - if ((units -= 4) < 0) { - break - } - bytes.push( - codePoint >> 0x12 | 0xF0, - codePoint >> 0xC & 0x3F | 0x80, - codePoint >> 0x6 & 0x3F | 0x80, - codePoint & 0x3F | 0x80 - ) - } else { - throw new Error('Invalid code point') - } - } - - return bytes - } - - function asciiToBytes(str) { - var byteArray = [] - for (var i = 0; i < str.length; i++) { - // Node's code seems to be doing this and not & 0x7F.. - byteArray.push(str.charCodeAt(i) & 0xFF) - } - return byteArray - } - - function utf16leToBytes(str, units) { - var c, - hi, - lo - var byteArray = [] - for (var i = 0; i < str.length; i++) { - if ((units -= 2) < 0) { - break - } - - c = str.charCodeAt(i) - hi = c >> 8 - lo = c % 256 - byteArray.push(lo) - byteArray.push(hi) - } - - return byteArray - } - - function base64ToBytes(str) { - return base64.toByteArray(base64clean(str)) - } - - function blitBuffer(src, dst, offset, length) { - for (var i = 0; i < length; i++) { - if ((i + offset >= dst.length) || (i >= src.length)) { - break - } - dst[i + offset] = src[i] - } - return i - } - - }, { - "base64-js": 44, - "ieee754": 45, - "is-array": 46 - }], - 44: [function(require, module, exports) { - var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - - ;(function(exports) { - 'use strict'; - - var Arr = (typeof Uint8Array !== 'undefined') - ? Uint8Array - : Array - - var PLUS = '+'.charCodeAt(0) - var SLASH = '/'.charCodeAt(0) - var NUMBER = '0'.charCodeAt(0) - var LOWER = 'a'.charCodeAt(0) - var UPPER = 'A'.charCodeAt(0) - var PLUS_URL_SAFE = '-'.charCodeAt(0) - var SLASH_URL_SAFE = '_'.charCodeAt(0) - - function decode(elt) { - var code = elt.charCodeAt(0) - if (code === PLUS || - code === PLUS_URL_SAFE) { - return 62 - } // '+' - if (code === SLASH || - code === SLASH_URL_SAFE) { - return 63 - } // '/' - if (code < NUMBER) { - return -1 - } //no match - if (code < NUMBER + 10) { - return code - NUMBER + 26 + 26 - } - if (code < UPPER + 26) { - return code - UPPER - } - if (code < LOWER + 26) { - return code - LOWER + 26 - } - } - - function b64ToByteArray(b64) { - var i, - j, - l, - tmp, - placeHolders, - arr - - if (b64.length % 4 > 0) { - throw new Error('Invalid string. Length must be a multiple of 4') - } - - // the number of equal signs (place holders) - // if there are two placeholders, than the two characters before it - // represent one byte - // if there is only one, then the three characters before it represent 2 bytes - // this is just a cheap hack to not do indexOf twice - var len = b64.length - placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0 - - // base64 is 4/3 + up to two characters of the original data - arr = new Arr(b64.length * 3 / 4 - placeHolders) - - // if there are placeholders, only get up to the last complete 4 chars - l = placeHolders > 0 ? b64.length - 4 : b64.length - - var L = 0 - - function push(v) { - arr[L++] = v - } - - for (i = 0, j = 0; i < l; i += 4, j += 3) { - tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3)) - push((tmp & 0xFF0000) >> 16) - push((tmp & 0xFF00) >> 8) - push(tmp & 0xFF) - } - - if (placeHolders === 2) { - tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4) - push(tmp & 0xFF) - } else if (placeHolders === 1) { - tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2) - push((tmp >> 8) & 0xFF) - push(tmp & 0xFF) - } - - return arr - } - - function uint8ToBase64(uint8) { - var i, - extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes - output = "", - temp, - length - - function encode(num) { - return lookup.charAt(num) - } - - function tripletToBase64(num) { - return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F) - } - - // go through the array every three bytes, we'll deal with trailing stuff later - for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) { - temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]) - output += tripletToBase64(temp) - } - - // pad the end with zeros, but make sure to not forget the extra bytes - switch (extraBytes) { - case 1: - temp = uint8[uint8.length - 1] - output += encode(temp >> 2) - output += encode((temp << 4) & 0x3F) - output += '==' - break - case 2: - temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]) - output += encode(temp >> 10) - output += encode((temp >> 4) & 0x3F) - output += encode((temp << 2) & 0x3F) - output += '=' - break - } - - return output - } - - exports.toByteArray = b64ToByteArray - exports.fromByteArray = uint8ToBase64 - }(typeof exports === 'undefined' ? (this.base64js = {}) : exports)) - - }, {}], - 45: [function(require, module, exports) { - exports.read = function(buffer, offset, isLE, mLen, nBytes) { - var e, - m - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var nBits = -7 - var i = isLE ? (nBytes - 1) : 0 - var d = isLE ? -1 : 1 - var s = buffer[offset + i] - i += d - - e = s & ((1 << (-nBits)) - 1) - s >>= (-nBits) - nBits += eLen - for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) { - } - - m = e & ((1 << (-nBits)) - 1) - e >>= (-nBits) - nBits += mLen - for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) { - } - - if (e === 0) { - e = 1 - eBias - } else if (e === eMax) { - return m ? NaN : ((s ? -1 : 1) * Infinity) - } else { - m = m + Math.pow(2, mLen) - e = e - eBias - } - return (s ? -1 : 1) * m * Math.pow(2, e - mLen) - } - - exports.write = function(buffer, value, offset, isLE, mLen, nBytes) { - var e, - m, - c - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) - var i = isLE ? 0 : (nBytes - 1) - var d = isLE ? 1 : -1 - var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 - - value = Math.abs(value) - - if (isNaN(value) || value === Infinity) { - m = isNaN(value) ? 1 : 0 - e = eMax - } else { - e = Math.floor(Math.log(value) / Math.LN2) - if (value * (c = Math.pow(2, -e)) < 1) { - e-- - c *= 2 - } - if (e + eBias >= 1) { - value += rt / c - } else { - value += rt * Math.pow(2, 1 - eBias) - } - if (value * c >= 2) { - e++ - c /= 2 - } - - if (e + eBias >= eMax) { - m = 0 - e = eMax - } else if (e + eBias >= 1) { - m = (value * c - 1) * Math.pow(2, mLen) - e = e + eBias - } else { - m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) - e = 0 - } - } - - for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) { - } - - e = (e << mLen) | m - eLen += mLen - for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) { - } - - buffer[offset + i - d] |= s * 128 - } - - }, {}], - 46: [function(require, module, exports) { - - /** - * isArray - */ - - var isArray = Array.isArray; - - /** - * toString - */ - - var str = Object.prototype.toString; - - /** - * Whether or not the given `val` - * is an array. - * - * example: - * - * isArray([]); - * // > true - * isArray(arguments); - * // > false - * isArray(''); - * // > false - * - * @param {mixed} val - * @return {bool} - */ - - module.exports = isArray || function(val) { - return !!val && '[object Array]' == str.call(val); - }; - - }, {}], - 47: [function(require, module, exports) { - // Copyright Joyent, Inc. and other Node contributors. - // - // Permission is hereby granted, free of charge, to any person obtaining a - // copy of this software and associated documentation files (the - // "Software"), to deal in the Software without restriction, including - // without limitation the rights to use, copy, modify, merge, publish, - // distribute, sublicense, and/or sell copies of the Software, and to permit - // persons to whom the Software is furnished to do so, subject to the - // following conditions: - // - // The above copyright notice and this permission notice shall be included - // in all copies or substantial portions of the Software. - // - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - // USE OR OTHER DEALINGS IN THE SOFTWARE. - - function EventEmitter() { - this._events = this._events || {}; - this._maxListeners = this._maxListeners || undefined; - } - module.exports = EventEmitter; - - // Backwards-compat with node 0.10.x - EventEmitter.EventEmitter = EventEmitter; - - EventEmitter.prototype._events = undefined; - EventEmitter.prototype._maxListeners = undefined; - - // By default EventEmitters will print a warning if more than 10 listeners are - // added to it. This is a useful default which helps finding memory leaks. - EventEmitter.defaultMaxListeners = 10; - - // Obviously not all Emitters should be limited to 10. This function allows - // that to be increased. Set to zero for unlimited. - EventEmitter.prototype.setMaxListeners = function(n) { - if (!isNumber(n) || n < 0 || isNaN(n)) { - throw TypeError('n must be a positive number'); - } - this._maxListeners = n; - return this; - }; - - EventEmitter.prototype.emit = function(type) { - var er, - handler, - len, - args, - i, - listeners; - - if (!this._events) { - this._events = {}; - } - - // If there is no 'error' event listener then throw. - if (type === 'error') { - if (!this._events.error || - (isObject(this._events.error) && !this._events.error.length)) { - er = arguments[1]; - if (er instanceof Error) { - throw er; // Unhandled 'error' event - } - throw TypeError('Uncaught, unspecified "error" event.'); - } - } - - handler = this._events[type]; - - if (isUndefined(handler)) { - return false; - } - - if (isFunction(handler)) { - switch (arguments.length) { - // fast cases - case 1: - handler.call(this); - break; - case 2: - handler.call(this, arguments[1]); - break; - case 3: - handler.call(this, arguments[1], arguments[2]); - break; - // slower - default: - len = arguments.length; - args = new Array(len - 1); - for (i = 1; i < len; i++) { - args[i - 1] = arguments[i]; - } - handler.apply(this, args); - } - } else if (isObject(handler)) { - len = arguments.length; - args = new Array(len - 1); - for (i = 1; i < len; i++) { - args[i - 1] = arguments[i]; - } - - listeners = handler.slice(); - len = listeners.length; - for (i = 0; i < len; i++) { - listeners[i].apply(this, args); - } - } - - return true; - }; - - EventEmitter.prototype.addListener = function(type, listener) { - var m; - - if (!isFunction(listener)) { - throw TypeError('listener must be a function'); - } - - if (!this._events) { - this._events = {}; - } - - // To avoid recursion in the case that type === "newListener"! Before - // adding it to the listeners, first emit "newListener". - if (this._events.newListener) { - this.emit('newListener', type, - isFunction(listener.listener) ? - listener.listener : listener); - } - - if (!this._events[type]) - // Optimize the case of one listener. Don't need the extra array object. - { - this._events[type] = listener; - } else if (isObject(this._events[type])) - // If we've already got an array, just append. - { - this._events[type].push(listener); - } else - // Adding the second element, need to change to array. - { - this._events[type] = [this._events[type], listener]; - } - - // Check for listener leak - if (isObject(this._events[type]) && !this._events[type].warned) { - var m; - if (!isUndefined(this._maxListeners)) { - m = this._maxListeners; - } else { - m = EventEmitter.defaultMaxListeners; - } - - if (m && m > 0 && this._events[type].length > m) { - this._events[type].warned = true; - console.error('(node) warning: possible EventEmitter memory ' + - 'leak detected. %d listeners added. ' + - 'Use emitter.setMaxListeners() to increase limit.', - this._events[type].length); - if (typeof console.trace === 'function') { - // not supported in IE 10 - console.trace(); - } - } - } - - return this; - }; - - EventEmitter.prototype.on = EventEmitter.prototype.addListener; - - EventEmitter.prototype.once = function(type, listener) { - if (!isFunction(listener)) { - throw TypeError('listener must be a function'); - } - - var fired = false; - - function g() { - this.removeListener(type, g); - - if (!fired) { - fired = true; - listener.apply(this, arguments); - } - } - - g.listener = listener; - this.on(type, g); - - return this; - }; - - // emits a 'removeListener' event iff the listener was removed - EventEmitter.prototype.removeListener = function(type, listener) { - var list, - position, - length, - i; - - if (!isFunction(listener)) { - throw TypeError('listener must be a function'); - } - - if (!this._events || !this._events[type]) { - return this; - } - - list = this._events[type]; - length = list.length; - position = -1; - - if (list === listener || - (isFunction(list.listener) && list.listener === listener)) { - delete this._events[type]; - if (this._events.removeListener) { - this.emit('removeListener', type, listener); - } - - } else if (isObject(list)) { - for (i = length; i-- > 0;) { - if (list[i] === listener || - (list[i].listener && list[i].listener === listener)) { - position = i; - break; - } - } - - if (position < 0) { - return this; - } - - if (list.length === 1) { - list.length = 0; - delete this._events[type]; - } else { - list.splice(position, 1); - } - - if (this._events.removeListener) { - this.emit('removeListener', type, listener); - } - } - - return this; - }; - - EventEmitter.prototype.removeAllListeners = function(type) { - var key, - listeners; - - if (!this._events) { - return this; - } - - // not listening for removeListener, no need to emit - if (!this._events.removeListener) { - if (arguments.length === 0) { - this._events = {}; - } else if (this._events[type]) { - delete this._events[type]; - } - return this; - } - - // emit removeListener for all listeners on all events - if (arguments.length === 0) { - for (key in this._events) { - if (key === 'removeListener') { - continue; - } - this.removeAllListeners(key); - } - this.removeAllListeners('removeListener'); - this._events = {}; - return this; - } - - listeners = this._events[type]; - - if (isFunction(listeners)) { - this.removeListener(type, listeners); - } else { - // LIFO order - while (listeners.length) { - this.removeListener(type, listeners[listeners.length - 1]); - } - } - delete this._events[type]; - - return this; - }; - - EventEmitter.prototype.listeners = function(type) { - var ret; - if (!this._events || !this._events[type]) { - ret = []; - } else if (isFunction(this._events[type])) { - ret = [this._events[type]]; - } else { - ret = this._events[type].slice(); - } - return ret; - }; - - EventEmitter.listenerCount = function(emitter, type) { - var ret; - if (!emitter._events || !emitter._events[type]) { - ret = 0; - } else if (isFunction(emitter._events[type])) { - ret = 1; - } else { - ret = emitter._events[type].length; - } - return ret; - }; - - function isFunction(arg) { - return typeof arg === 'function'; - } - - function isNumber(arg) { - return typeof arg === 'number'; - } - - function isObject(arg) { - return typeof arg === 'object' && arg !== null; - } - - function isUndefined(arg) { - return arg === void 0; - } - - }, {}], - 48: [function(require, module, exports) { - if (typeof Object.create === 'function') { - // implementation from standard node.js 'util' module - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }); - }; - } else { - // old school shim for old browsers - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - var TempCtor = function() {} - TempCtor.prototype = superCtor.prototype - ctor.prototype = new TempCtor() - ctor.prototype.constructor = ctor - } - } - - }, {}], - 49: [function(require, module, exports) { - module.exports = Array.isArray || function(arr) { - return Object.prototype.toString.call(arr) == '[object Array]'; - }; - - }, {}], - 50: [function(require, module, exports) { - exports.endianness = function() { - return 'LE' - }; - - exports.hostname = function() { - if (typeof location !== 'undefined') { - return location.hostname - } else { - return ''; - } - }; - - exports.loadavg = function() { - return [] - }; - - exports.uptime = function() { - return 0 - }; - - exports.freemem = function() { - return Number.MAX_VALUE; - }; - - exports.totalmem = function() { - return Number.MAX_VALUE; - }; - - exports.cpus = function() { - return [] - }; - - exports.type = function() { - return 'Browser' - }; - - exports.release = function() { - if (typeof navigator !== 'undefined') { - return navigator.appVersion; - } - return ''; - }; - - exports.networkInterfaces = exports.getNetworkInterfaces = function() { - return {} - }; - - exports.arch = function() { - return 'javascript' - }; - - exports.platform = function() { - return 'browser' - }; - - exports.tmpdir = exports.tmpDir = function() { - return '/tmp'; - }; - - exports.EOL = '\n'; - - }, {}], - 51: [function(require, module, exports) { - // shim for using process in browser - - var process = module.exports = {}; - var queue = []; - var draining = false; - var currentQueue; - var queueIndex = -1; - - function cleanUpNextTick() { - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); - } else { - queueIndex = -1; - } - if (queue.length) { - drainQueue(); - } - } - - function drainQueue() { - if (draining) { - return; - } - var timeout = setTimeout(cleanUpNextTick); - draining = true; - - var len = queue.length; - while (len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); - } - } - queueIndex = -1; - len = queue.length; - } - currentQueue = null; - draining = false; - clearTimeout(timeout); - } - - process.nextTick = function(fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) { - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - } - queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) { - setTimeout(drainQueue, 0); - } - }; - - // v8 likes predictible objects - function Item(fun, array) { - this.fun = fun; - this.array = array; - } - Item.prototype.run = function() { - this.fun.apply(null, this.array); - }; - process.title = 'browser'; - process.browser = true; - process.env = {}; - process.argv = []; - process.version = ''; // empty string to avoid regexp issues - process.versions = {}; - - function noop() { - } - - process.on = noop; - process.addListener = noop; - process.once = noop; - process.off = noop; - process.removeListener = noop; - process.removeAllListeners = noop; - process.emit = noop; - - process.binding = function(name) { - throw new Error('process.binding is not supported'); - }; - - process.cwd = function() { - return '/' - }; - process.chdir = function(dir) { - throw new Error('process.chdir is not supported'); - }; - process.umask = function() { - return 0; - }; - - }, {}], - 52: [function(require, module, exports) { - module.exports = require("./lib/_stream_duplex.js") - - }, { - "./lib/_stream_duplex.js": 53 - }], - 53: [function(require, module, exports) { - (function(process) { - // Copyright Joyent, Inc. and other Node contributors. - // - // Permission is hereby granted, free of charge, to any person obtaining a - // copy of this software and associated documentation files (the - // "Software"), to deal in the Software without restriction, including - // without limitation the rights to use, copy, modify, merge, publish, - // distribute, sublicense, and/or sell copies of the Software, and to permit - // persons to whom the Software is furnished to do so, subject to the - // following conditions: - // - // The above copyright notice and this permission notice shall be included - // in all copies or substantial portions of the Software. - // - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - // USE OR OTHER DEALINGS IN THE SOFTWARE. - - // a duplex stream is just a stream that is both readable and writable. - // Since JS doesn't have multiple prototypal inheritance, this class - // prototypally inherits from Readable, and then parasitically from - // Writable. - - module.exports = Duplex; - - /**/ - var objectKeys = Object.keys || function(obj) { - var keys = []; - for (var key in obj) { - keys.push(key); - } - return keys; - } - /**/ - - - /**/ - var util = require('core-util-is'); - util.inherits = require('inherits'); - /**/ - - var Readable = require('./_stream_readable'); - var Writable = require('./_stream_writable'); - - util.inherits(Duplex, Readable); - - forEach(objectKeys(Writable.prototype), function(method) { - if (!Duplex.prototype[method]) { - Duplex.prototype[method] = Writable.prototype[method]; - } - }); - - function Duplex(options) { - if (!(this instanceof Duplex)) { - return new Duplex(options); - } - - Readable.call(this, options); - Writable.call(this, options); - - if (options && options.readable === false) { - this.readable = false; - } - - if (options && options.writable === false) { - this.writable = false; - } - - this.allowHalfOpen = true; - if (options && options.allowHalfOpen === false) { - this.allowHalfOpen = false; - } - - this.once('end', onend); - } - - // the no-half-open enforcer - function onend() { - // if we allow half-open state, or if the writable side ended, - // then we're ok. - if (this.allowHalfOpen || this._writableState.ended) { - return; - } - - // no more data can be written. - // But allow more writes to happen in this tick. - process.nextTick(this.end.bind(this)); - } - - function forEach(xs, f) { - for (var i = 0, l = xs.length; i < l; i++) { - f(xs[i], i); - } - } - - }).call(this, require('_process')) - }, { - "./_stream_readable": 55, - "./_stream_writable": 57, - "_process": 51, - "core-util-is": 58, - "inherits": 48 - }], - 54: [function(require, module, exports) { - // Copyright Joyent, Inc. and other Node contributors. - // - // Permission is hereby granted, free of charge, to any person obtaining a - // copy of this software and associated documentation files (the - // "Software"), to deal in the Software without restriction, including - // without limitation the rights to use, copy, modify, merge, publish, - // distribute, sublicense, and/or sell copies of the Software, and to permit - // persons to whom the Software is furnished to do so, subject to the - // following conditions: - // - // The above copyright notice and this permission notice shall be included - // in all copies or substantial portions of the Software. - // - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - // USE OR OTHER DEALINGS IN THE SOFTWARE. - - // a passthrough stream. - // basically just the most minimal sort of Transform stream. - // Every written chunk gets output as-is. - - module.exports = PassThrough; - - var Transform = require('./_stream_transform'); - - /**/ - var util = require('core-util-is'); - util.inherits = require('inherits'); - /**/ - - util.inherits(PassThrough, Transform); - - function PassThrough(options) { - if (!(this instanceof PassThrough)) { - return new PassThrough(options); - } - - Transform.call(this, options); - } - - PassThrough.prototype._transform = function(chunk, encoding, cb) { - cb(null, chunk); - }; - - }, { - "./_stream_transform": 56, - "core-util-is": 58, - "inherits": 48 - }], - 55: [function(require, module, exports) { - (function(process) { - // Copyright Joyent, Inc. and other Node contributors. - // - // Permission is hereby granted, free of charge, to any person obtaining a - // copy of this software and associated documentation files (the - // "Software"), to deal in the Software without restriction, including - // without limitation the rights to use, copy, modify, merge, publish, - // distribute, sublicense, and/or sell copies of the Software, and to permit - // persons to whom the Software is furnished to do so, subject to the - // following conditions: - // - // The above copyright notice and this permission notice shall be included - // in all copies or substantial portions of the Software. - // - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - // USE OR OTHER DEALINGS IN THE SOFTWARE. - - module.exports = Readable; - - /**/ - var isArray = require('isarray'); - /**/ - - - /**/ - var Buffer = require('buffer').Buffer; - /**/ - - Readable.ReadableState = ReadableState; - - var EE = require('events').EventEmitter; - - /**/ - if (!EE.listenerCount) { - EE.listenerCount = function(emitter, type) { - return emitter.listeners(type).length; - }; - } - /**/ - - var Stream = require('stream'); - - /**/ - var util = require('core-util-is'); - util.inherits = require('inherits'); - /**/ - - var StringDecoder; - - - /**/ - var debug = require('util'); - if (debug && debug.debuglog) { - debug = debug.debuglog('stream'); - } else { - debug = function() {}; - } - /**/ - - - util.inherits(Readable, Stream); - - function ReadableState(options, stream) { - var Duplex = require('./_stream_duplex'); - - options = options || {}; - - // the point at which it stops calling _read() to fill the buffer - // Note: 0 is a valid value, means "don't call _read preemptively ever" - var hwm = options.highWaterMark; - var defaultHwm = options.objectMode ? 16 : 16 * 1024; - this.highWaterMark = (hwm || hwm === 0) ? hwm : defaultHwm; - - // cast to ints. - this.highWaterMark = ~~this.highWaterMark; - - this.buffer = []; - this.length = 0; - this.pipes = null; - this.pipesCount = 0; - this.flowing = null; - this.ended = false; - this.endEmitted = false; - this.reading = false; - - // a flag to be able to tell if the onwrite cb is called immediately, - // or on a later tick. We set this to true at first, because any - // actions that shouldn't happen until "later" should generally also - // not happen before the first write call. - this.sync = true; - - // whenever we return null, then we set a flag to say - // that we're awaiting a 'readable' event emission. - this.needReadable = false; - this.emittedReadable = false; - this.readableListening = false; - - - // object stream flag. Used to make read(n) ignore n and to - // make all the buffer merging and length checks go away - this.objectMode = !!options.objectMode; - - if (stream instanceof Duplex) { - this.objectMode = this.objectMode || !!options.readableObjectMode; - } - - // Crypto is kind of old and crusty. Historically, its default string - // encoding is 'binary' so we have to make this configurable. - // Everything else in the universe uses 'utf8', though. - this.defaultEncoding = options.defaultEncoding || 'utf8'; - - // when piping, we only care about 'readable' events that happen - // after read()ing all the bytes and not getting any pushback. - this.ranOut = false; - - // the number of writers that are awaiting a drain event in .pipe()s - this.awaitDrain = 0; - - // if true, a maybeReadMore has been scheduled - this.readingMore = false; - - this.decoder = null; - this.encoding = null; - if (options.encoding) { - if (!StringDecoder) { - StringDecoder = require('string_decoder/').StringDecoder; - } - this.decoder = new StringDecoder(options.encoding); - this.encoding = options.encoding; - } - } - - function Readable(options) { - var Duplex = require('./_stream_duplex'); - - if (!(this instanceof Readable)) { - return new Readable(options); - } - - this._readableState = new ReadableState(options, this); - - // legacy - this.readable = true; - - Stream.call(this); - } - - // Manually shove something into the read() buffer. - // This returns true if the highWaterMark has not been hit yet, - // similar to how Writable.write() returns true if you should - // write() some more. - Readable.prototype.push = function(chunk, encoding) { - var state = this._readableState; - - if (util.isString(chunk) && !state.objectMode) { - encoding = encoding || state.defaultEncoding; - if (encoding !== state.encoding) { - chunk = new Buffer(chunk, encoding); - encoding = ''; - } - } - - return readableAddChunk(this, state, chunk, encoding, false); - }; - - // Unshift should *always* be something directly out of read() - Readable.prototype.unshift = function(chunk) { - var state = this._readableState; - return readableAddChunk(this, state, chunk, '', true); - }; - - function readableAddChunk(stream, state, chunk, encoding, addToFront) { - var er = chunkInvalid(state, chunk); - if (er) { - stream.emit('error', er); - } else if (util.isNullOrUndefined(chunk)) { - state.reading = false; - if (!state.ended) { - onEofChunk(stream, state); - } - } else if (state.objectMode || chunk && chunk.length > 0) { - if (state.ended && !addToFront) { - var e = new Error('stream.push() after EOF'); - stream.emit('error', e); - } else if (state.endEmitted && addToFront) { - var e = new Error('stream.unshift() after end event'); - stream.emit('error', e); - } else { - if (state.decoder && !addToFront && !encoding) { - chunk = state.decoder.write(chunk); - } - - if (!addToFront) { - state.reading = false; - } - - // if we want the data now, just emit it. - if (state.flowing && state.length === 0 && !state.sync) { - stream.emit('data', chunk); - stream.read(0); - } else { - // update the buffer info. - state.length += state.objectMode ? 1 : chunk.length; - if (addToFront) { - state.buffer.unshift(chunk); - } else { - state.buffer.push(chunk); - } - - if (state.needReadable) { - emitReadable(stream); - } - } - - maybeReadMore(stream, state); - } - } else if (!addToFront) { - state.reading = false; - } - - return needMoreData(state); - } - - - - // if it's past the high water mark, we can push in some more. - // Also, if we have no data yet, we can stand some - // more bytes. This is to work around cases where hwm=0, - // such as the repl. Also, if the push() triggered a - // readable event, and the user called read(largeNumber) such that - // needReadable was set, then we ought to push more, so that another - // 'readable' event will be triggered. - function needMoreData(state) { - return !state.ended && - (state.needReadable || - state.length < state.highWaterMark || - state.length === 0); - } - - // backwards compatibility. - Readable.prototype.setEncoding = function(enc) { - if (!StringDecoder) { - StringDecoder = require('string_decoder/').StringDecoder; - } - this._readableState.decoder = new StringDecoder(enc); - this._readableState.encoding = enc; - return this; - }; - - // Don't raise the hwm > 128MB - var MAX_HWM = 0x800000; - function roundUpToNextPowerOf2(n) { - if (n >= MAX_HWM) { - n = MAX_HWM; - } else { - // Get the next highest power of 2 - n--; - for (var p = 1; p < 32; p <<= 1) { - n |= n >> p; - } - n++; - } - return n; - } - - function howMuchToRead(n, state) { - if (state.length === 0 && state.ended) { - return 0; - } - - if (state.objectMode) { - return n === 0 ? 0 : 1; - } - - if (isNaN(n) || util.isNull(n)) { - // only flow one buffer at a time - if (state.flowing && state.buffer.length) { - return state.buffer[0].length; - } else { - return state.length; - } - } - - if (n <= 0) { - return 0; - } - - // If we're asking for more than the target buffer level, - // then raise the water mark. Bump up to the next highest - // power of 2, to prevent increasing it excessively in tiny - // amounts. - if (n > state.highWaterMark) { - state.highWaterMark = roundUpToNextPowerOf2(n); - } - - // don't have that much. return null, unless we've ended. - if (n > state.length) { - if (!state.ended) { - state.needReadable = true; - return 0; - } else { - return state.length; - } - } - - return n; - } - - // you can override either this method, or the async _read(n) below. - Readable.prototype.read = function(n) { - debug('read', n); - var state = this._readableState; - var nOrig = n; - - if (!util.isNumber(n) || n > 0) { - state.emittedReadable = false; - } - - // if we're doing read(0) to trigger a readable event, but we - // already have a bunch of data in the buffer, then just trigger - // the 'readable' event and move on. - if (n === 0 && - state.needReadable && - (state.length >= state.highWaterMark || state.ended)) { - debug('read: emitReadable', state.length, state.ended); - if (state.length === 0 && state.ended) { - endReadable(this); - } else { - emitReadable(this); - } - return null; - } - - n = howMuchToRead(n, state); - - // if we've ended, and we're now clear, then finish it up. - if (n === 0 && state.ended) { - if (state.length === 0) { - endReadable(this); - } - return null; - } - - // All the actual chunk generation logic needs to be - // *below* the call to _read. The reason is that in certain - // synthetic stream cases, such as passthrough streams, _read - // may be a completely synchronous operation which may change - // the state of the read buffer, providing enough data when - // before there was *not* enough. - // - // So, the steps are: - // 1. Figure out what the state of things will be after we do - // a read from the buffer. - // - // 2. If that resulting state will trigger a _read, then call _read. - // Note that this may be asynchronous, or synchronous. Yes, it is - // deeply ugly to write APIs this way, but that still doesn't mean - // that the Readable class should behave improperly, as streams are - // designed to be sync/async agnostic. - // Take note if the _read call is sync or async (ie, if the read call - // has returned yet), so that we know whether or not it's safe to emit - // 'readable' etc. - // - // 3. Actually pull the requested chunks out of the buffer and return. - - // if we need a readable event, then we need to do some reading. - var doRead = state.needReadable; - debug('need readable', doRead); - - // if we currently have less than the highWaterMark, then also read some - if (state.length === 0 || state.length - n < state.highWaterMark) { - doRead = true; - debug('length less than watermark', doRead); - } - - // however, if we've ended, then there's no point, and if we're already - // reading, then it's unnecessary. - if (state.ended || state.reading) { - doRead = false; - debug('reading or ended', doRead); - } - - if (doRead) { - debug('do read'); - state.reading = true; - state.sync = true; - // if the length is currently zero, then we *need* a readable event. - if (state.length === 0) { - state.needReadable = true; - } - // call internal read method - this._read(state.highWaterMark); - state.sync = false; - } - - // If _read pushed data synchronously, then `reading` will be false, - // and we need to re-evaluate how much data we can return to the user. - if (doRead && !state.reading) { - n = howMuchToRead(nOrig, state); - } - - var ret; - if (n > 0) { - ret = fromList(n, state); - } else { - ret = null; - } - - if (util.isNull(ret)) { - state.needReadable = true; - n = 0; - } - - state.length -= n; - - // If we have nothing in the buffer, then we want to know - // as soon as we *do* get something into the buffer. - if (state.length === 0 && !state.ended) { - state.needReadable = true; - } - - // If we tried to read() past the EOF, then emit end on the next tick. - if (nOrig !== n && state.ended && state.length === 0) { - endReadable(this); - } - - if (!util.isNull(ret)) { - this.emit('data', ret); - } - - return ret; - }; - - function chunkInvalid(state, chunk) { - var er = null; - if (!util.isBuffer(chunk) && - !util.isString(chunk) && - !util.isNullOrUndefined(chunk) && - !state.objectMode) { - er = new TypeError('Invalid non-string/buffer chunk'); - } - return er; - } - - - function onEofChunk(stream, state) { - if (state.decoder && !state.ended) { - var chunk = state.decoder.end(); - if (chunk && chunk.length) { - state.buffer.push(chunk); - state.length += state.objectMode ? 1 : chunk.length; - } - } - state.ended = true; - - // emit 'readable' now to make sure it gets picked up. - emitReadable(stream); - } - - // Don't emit readable right away in sync mode, because this can trigger - // another read() call => stack overflow. This way, it might trigger - // a nextTick recursion warning, but that's not so bad. - function emitReadable(stream) { - var state = stream._readableState; - state.needReadable = false; - if (!state.emittedReadable) { - debug('emitReadable', state.flowing); - state.emittedReadable = true; - if (state.sync) { - process.nextTick(function() { - emitReadable_(stream); - }); - } else { - emitReadable_(stream); - } - } - } - - function emitReadable_(stream) { - debug('emit readable'); - stream.emit('readable'); - flow(stream); - } - - - // at this point, the user has presumably seen the 'readable' event, - // and called read() to consume some data. that may have triggered - // in turn another _read(n) call, in which case reading = true if - // it's in progress. - // However, if we're not ended, or reading, and the length < hwm, - // then go ahead and try to read some more preemptively. - function maybeReadMore(stream, state) { - if (!state.readingMore) { - state.readingMore = true; - process.nextTick(function() { - maybeReadMore_(stream, state); - }); - } - } - - function maybeReadMore_(stream, state) { - var len = state.length; - while (!state.reading && !state.flowing && !state.ended && - state.length < state.highWaterMark) { - debug('maybeReadMore read 0'); - stream.read(0); - if (len === state.length) - // didn't get any data, stop spinning. - { - break; - } else { - len = state.length; - } - } - state.readingMore = false; - } - - // abstract method. to be overridden in specific implementation classes. - // call cb(er, data) where data is <= n in length. - // for virtual (non-string, non-buffer) streams, "length" is somewhat - // arbitrary, and perhaps not very meaningful. - Readable.prototype._read = function(n) { - this.emit('error', new Error('not implemented')); - }; - - Readable.prototype.pipe = function(dest, pipeOpts) { - var src = this; - var state = this._readableState; - - switch (state.pipesCount) { - case 0: - state.pipes = dest; - break; - case 1: - state.pipes = [state.pipes, dest]; - break; - default: - state.pipes.push(dest); - break; - } - state.pipesCount += 1; - debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts); - - var doEnd = (!pipeOpts || pipeOpts.end !== false) && - dest !== process.stdout && - dest !== process.stderr; - - var endFn = doEnd ? onend : cleanup; - if (state.endEmitted) { - process.nextTick(endFn); - } else { - src.once('end', endFn); - } - - dest.on('unpipe', onunpipe); - function onunpipe(readable) { - debug('onunpipe'); - if (readable === src) { - cleanup(); - } - } - - function onend() { - debug('onend'); - dest.end(); - } - - // when the dest drains, it reduces the awaitDrain counter - // on the source. This would be more elegant with a .once() - // handler in flow(), but adding and removing repeatedly is - // too slow. - var ondrain = pipeOnDrain(src); - dest.on('drain', ondrain); - - function cleanup() { - debug('cleanup'); - // cleanup event handlers once the pipe is broken - dest.removeListener('close', onclose); - dest.removeListener('finish', onfinish); - dest.removeListener('drain', ondrain); - dest.removeListener('error', onerror); - dest.removeListener('unpipe', onunpipe); - src.removeListener('end', onend); - src.removeListener('end', cleanup); - src.removeListener('data', ondata); - - // if the reader is waiting for a drain event from this - // specific writer, then it would cause it to never start - // flowing again. - // So, if this is awaiting a drain, then we just call it now. - // If we don't know, then assume that we are waiting for one. - if (state.awaitDrain && - (!dest._writableState || dest._writableState.needDrain)) { - ondrain(); - } - } - - src.on('data', ondata); - function ondata(chunk) { - debug('ondata'); - var ret = dest.write(chunk); - if (false === ret) { - debug('false write response, pause', - src._readableState.awaitDrain); - src._readableState.awaitDrain++; - src.pause(); - } - } - - // if the dest has an error, then stop piping into it. - // however, don't suppress the throwing behavior for this. - function onerror(er) { - debug('onerror', er); - unpipe(); - dest.removeListener('error', onerror); - if (EE.listenerCount(dest, 'error') === 0) { - dest.emit('error', er); - } - } - // This is a brutally ugly hack to make sure that our error handler - // is attached before any userland ones. NEVER DO THIS. - if (!dest._events || !dest._events.error) { - dest.on('error', onerror); - } else if (isArray(dest._events.error)) { - dest._events.error.unshift(onerror); - } else { - dest._events.error = [onerror, dest._events.error]; - } - - - - // Both close and finish should trigger unpipe, but only once. - function onclose() { - dest.removeListener('finish', onfinish); - unpipe(); - } - dest.once('close', onclose); - function onfinish() { - debug('onfinish'); - dest.removeListener('close', onclose); - unpipe(); - } - dest.once('finish', onfinish); - - function unpipe() { - debug('unpipe'); - src.unpipe(dest); - } - - // tell the dest that it's being piped to - dest.emit('pipe', src); - - // start the flow if it hasn't been started already. - if (!state.flowing) { - debug('pipe resume'); - src.resume(); - } - - return dest; - }; - - function pipeOnDrain(src) { - return function() { - var state = src._readableState; - debug('pipeOnDrain', state.awaitDrain); - if (state.awaitDrain) { - state.awaitDrain--; - } - if (state.awaitDrain === 0 && EE.listenerCount(src, 'data')) { - state.flowing = true; - flow(src); - } - }; - } - - - Readable.prototype.unpipe = function(dest) { - var state = this._readableState; - - // if we're not piping anywhere, then do nothing. - if (state.pipesCount === 0) { - return this; - } - - // just one destination. most common case. - if (state.pipesCount === 1) { - // passed in one, but it's not the right one. - if (dest && dest !== state.pipes) { - return this; - } - - if (!dest) { - dest = state.pipes; - } - - // got a match. - state.pipes = null; - state.pipesCount = 0; - state.flowing = false; - if (dest) { - dest.emit('unpipe', this); - } - return this; - } - - // slow case. multiple pipe destinations. - - if (!dest) { - // remove all. - var dests = state.pipes; - var len = state.pipesCount; - state.pipes = null; - state.pipesCount = 0; - state.flowing = false; - - for (var i = 0; i < len; i++) { - dests[i].emit('unpipe', this); - } - return this; - } - - // try to find the right one. - var i = indexOf(state.pipes, dest); - if (i === -1) { - return this; - } - - state.pipes.splice(i, 1); - state.pipesCount -= 1; - if (state.pipesCount === 1) { - state.pipes = state.pipes[0]; - } - - dest.emit('unpipe', this); - - return this; - }; - - // set up data events if they are asked for - // Ensure readable listeners eventually get something - Readable.prototype.on = function(ev, fn) { - var res = Stream.prototype.on.call(this, ev, fn); - - // If listening to data, and it has not explicitly been paused, - // then call resume to start the flow of data on the next tick. - if (ev === 'data' && false !== this._readableState.flowing) { - this.resume(); - } - - if (ev === 'readable' && this.readable) { - var state = this._readableState; - if (!state.readableListening) { - state.readableListening = true; - state.emittedReadable = false; - state.needReadable = true; - if (!state.reading) { - var self = this; - process.nextTick(function() { - debug('readable nexttick read 0'); - self.read(0); - }); - } else if (state.length) { - emitReadable(this, state); - } - } - } - - return res; - }; - Readable.prototype.addListener = Readable.prototype.on; - - // pause() and resume() are remnants of the legacy readable stream API - // If the user uses them, then switch into old mode. - Readable.prototype.resume = function() { - var state = this._readableState; - if (!state.flowing) { - debug('resume'); - state.flowing = true; - if (!state.reading) { - debug('resume read 0'); - this.read(0); - } - resume(this, state); - } - return this; - }; - - function resume(stream, state) { - if (!state.resumeScheduled) { - state.resumeScheduled = true; - process.nextTick(function() { - resume_(stream, state); - }); - } - } - - function resume_(stream, state) { - state.resumeScheduled = false; - stream.emit('resume'); - flow(stream); - if (state.flowing && !state.reading) { - stream.read(0); - } - } - - Readable.prototype.pause = function() { - debug('call pause flowing=%j', this._readableState.flowing); - if (false !== this._readableState.flowing) { - debug('pause'); - this._readableState.flowing = false; - this.emit('pause'); - } - return this; - }; - - function flow(stream) { - var state = stream._readableState; - debug('flow', state.flowing); - if (state.flowing) { - do { - var chunk = stream.read(); - } while (null !== chunk && state.flowing); - } - } - - // wrap an old-style stream as the async data source. - // This is *not* part of the readable stream interface. - // It is an ugly unfortunate mess of history. - Readable.prototype.wrap = function(stream) { - var state = this._readableState; - var paused = false; - - var self = this; - stream.on('end', function() { - debug('wrapped end'); - if (state.decoder && !state.ended) { - var chunk = state.decoder.end(); - if (chunk && chunk.length) { - self.push(chunk); - } - } - - self.push(null); - }); - - stream.on('data', function(chunk) { - debug('wrapped data'); - if (state.decoder) { - chunk = state.decoder.write(chunk); - } - if (!chunk || !state.objectMode && !chunk.length) { - return; - } - - var ret = self.push(chunk); - if (!ret) { - paused = true; - stream.pause(); - } - }); - - // proxy all the other methods. - // important when wrapping filters and duplexes. - for (var i in stream) { - if (util.isFunction(stream[i]) && util.isUndefined(this[i])) { - this[i] = function(method) { - return function() { - return stream[method].apply(stream, arguments); - } - }(i); - } - } - - // proxy certain important events. - var events = ['error', 'close', 'destroy', 'pause', 'resume']; - forEach(events, function(ev) { - stream.on(ev, self.emit.bind(self, ev)); - }); - - // when we try to consume some more bytes, simply unpause the - // underlying stream. - self._read = function(n) { - debug('wrapped _read', n); - if (paused) { - paused = false; - stream.resume(); - } - }; - - return self; - }; - - - - // exposed for testing purposes only. - Readable._fromList = fromList; - - // Pluck off n bytes from an array of buffers. - // Length is the combined lengths of all the buffers in the list. - function fromList(n, state) { - var list = state.buffer; - var length = state.length; - var stringMode = !!state.decoder; - var objectMode = !!state.objectMode; - var ret; - - // nothing in the list, definitely empty. - if (list.length === 0) { - return null; - } - - if (length === 0) { - ret = null; - } else if (objectMode) { - ret = list.shift(); - } else if (!n || n >= length) { - // read it all, truncate the array. - if (stringMode) { - ret = list.join(''); - } else { - ret = Buffer.concat(list, length); - } - list.length = 0; - } else { - // read just some of it. - if (n < list[0].length) { - // just take a part of the first list item. - // slice is the same for buffers and strings. - var buf = list[0]; - ret = buf.slice(0, n); - list[0] = buf.slice(n); - } else if (n === list[0].length) { - // first list is a perfect match - ret = list.shift(); - } else { - // complex case. - // we have enough to cover it, but it spans past the first buffer. - if (stringMode) { - ret = ''; - } else { - ret = new Buffer(n); - } - - var c = 0; - for (var i = 0, l = list.length; i < l && c < n; i++) { - var buf = list[0]; - var cpy = Math.min(n - c, buf.length); - - if (stringMode) { - ret += buf.slice(0, cpy); - } else { - buf.copy(ret, c, 0, cpy); - } - - if (cpy < buf.length) { - list[0] = buf.slice(cpy); - } else { - list.shift(); - } - - c += cpy; - } - } - } - - return ret; - } - - function endReadable(stream) { - var state = stream._readableState; - - // If we get here before consuming all the bytes, then that is a - // bug in node. Should never happen. - if (state.length > 0) { - throw new Error('endReadable called on non-empty stream'); - } - - if (!state.endEmitted) { - state.ended = true; - process.nextTick(function() { - // Check that we didn't get one last unshift. - if (!state.endEmitted && state.length === 0) { - state.endEmitted = true; - stream.readable = false; - stream.emit('end'); - } - }); - } - } - - function forEach(xs, f) { - for (var i = 0, l = xs.length; i < l; i++) { - f(xs[i], i); - } - } - - function indexOf(xs, x) { - for (var i = 0, l = xs.length; i < l; i++) { - if (xs[i] === x) { - return i; - } - } - return -1; - } - - }).call(this, require('_process')) - }, { - "./_stream_duplex": 53, - "_process": 51, - "buffer": 43, - "core-util-is": 58, - "events": 47, - "inherits": 48, - "isarray": 49, - "stream": 63, - "string_decoder/": 64, - "util": 42 - }], - 56: [function(require, module, exports) { - // Copyright Joyent, Inc. and other Node contributors. - // - // Permission is hereby granted, free of charge, to any person obtaining a - // copy of this software and associated documentation files (the - // "Software"), to deal in the Software without restriction, including - // without limitation the rights to use, copy, modify, merge, publish, - // distribute, sublicense, and/or sell copies of the Software, and to permit - // persons to whom the Software is furnished to do so, subject to the - // following conditions: - // - // The above copyright notice and this permission notice shall be included - // in all copies or substantial portions of the Software. - // - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - // USE OR OTHER DEALINGS IN THE SOFTWARE. - - - // a transform stream is a readable/writable stream where you do - // something with the data. Sometimes it's called a "filter", - // but that's not a great name for it, since that implies a thing where - // some bits pass through, and others are simply ignored. (That would - // be a valid example of a transform, of course.) - // - // While the output is causally related to the input, it's not a - // necessarily symmetric or synchronous transformation. For example, - // a zlib stream might take multiple plain-text writes(), and then - // emit a single compressed chunk some time in the future. - // - // Here's how this works: - // - // The Transform stream has all the aspects of the readable and writable - // stream classes. When you write(chunk), that calls _write(chunk,cb) - // internally, and returns false if there's a lot of pending writes - // buffered up. When you call read(), that calls _read(n) until - // there's enough pending readable data buffered up. - // - // In a transform stream, the written data is placed in a buffer. When - // _read(n) is called, it transforms the queued up data, calling the - // buffered _write cb's as it consumes chunks. If consuming a single - // written chunk would result in multiple output chunks, then the first - // outputted bit calls the readcb, and subsequent chunks just go into - // the read buffer, and will cause it to emit 'readable' if necessary. - // - // This way, back-pressure is actually determined by the reading side, - // since _read has to be called to start processing a new chunk. However, - // a pathological inflate type of transform can cause excessive buffering - // here. For example, imagine a stream where every byte of input is - // interpreted as an integer from 0-255, and then results in that many - // bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in - // 1kb of data being output. In this case, you could write a very small - // amount of input, and end up with a very large amount of output. In - // such a pathological inflating mechanism, there'd be no way to tell - // the system to stop doing the transform. A single 4MB write could - // cause the system to run out of memory. - // - // However, even in such a pathological case, only a single written chunk - // would be consumed, and then the rest would wait (un-transformed) until - // the results of the previous transformed chunk were consumed. - - module.exports = Transform; - - var Duplex = require('./_stream_duplex'); - - /**/ - var util = require('core-util-is'); - util.inherits = require('inherits'); - /**/ - - util.inherits(Transform, Duplex); - - - function TransformState(options, stream) { - this.afterTransform = function(er, data) { - return afterTransform(stream, er, data); - }; - - this.needTransform = false; - this.transforming = false; - this.writecb = null; - this.writechunk = null; - } - - function afterTransform(stream, er, data) { - var ts = stream._transformState; - ts.transforming = false; - - var cb = ts.writecb; - - if (!cb) { - return stream.emit('error', new Error('no writecb in Transform class')); - } - - ts.writechunk = null; - ts.writecb = null; - - if (!util.isNullOrUndefined(data)) { - stream.push(data); - } - - if (cb) { - cb(er); - } - - var rs = stream._readableState; - rs.reading = false; - if (rs.needReadable || rs.length < rs.highWaterMark) { - stream._read(rs.highWaterMark); - } - } - - - function Transform(options) { - if (!(this instanceof Transform)) { - return new Transform(options); - } - - Duplex.call(this, options); - - this._transformState = new TransformState(options, this); - - // when the writable side finishes, then flush out anything remaining. - var stream = this; - - // start out asking for a readable event once data is transformed. - this._readableState.needReadable = true; - - // we have implemented the _read method, and done the other things - // that Readable wants before the first _read call, so unset the - // sync guard flag. - this._readableState.sync = false; - - this.once('prefinish', function() { - if (util.isFunction(this._flush)) { - this._flush(function(er) { - done(stream, er); - }); - } else { - done(stream); - } - }); - } - - Transform.prototype.push = function(chunk, encoding) { - this._transformState.needTransform = false; - return Duplex.prototype.push.call(this, chunk, encoding); - }; - - // This is the part where you do stuff! - // override this function in implementation classes. - // 'chunk' is an input chunk. - // - // Call `push(newChunk)` to pass along transformed output - // to the readable side. You may call 'push' zero or more times. - // - // Call `cb(err)` when you are done with this chunk. If you pass - // an error, then that'll put the hurt on the whole operation. If you - // never call cb(), then you'll never get another chunk. - Transform.prototype._transform = function(chunk, encoding, cb) { - throw new Error('not implemented'); - }; - - Transform.prototype._write = function(chunk, encoding, cb) { - var ts = this._transformState; - ts.writecb = cb; - ts.writechunk = chunk; - ts.writeencoding = encoding; - if (!ts.transforming) { - var rs = this._readableState; - if (ts.needTransform || - rs.needReadable || - rs.length < rs.highWaterMark) { - this._read(rs.highWaterMark); - } - } - }; - - // Doesn't matter what the args are here. - // _transform does all the work. - // That we got here means that the readable side wants more data. - Transform.prototype._read = function(n) { - var ts = this._transformState; - - if (!util.isNull(ts.writechunk) && ts.writecb && !ts.transforming) { - ts.transforming = true; - this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform); - } else { - // mark that we need a transform, so that any data that comes in - // will get processed, now that we've asked for it. - ts.needTransform = true; - } - }; - - - function done(stream, er) { - if (er) { - return stream.emit('error', er); - } - - // if there's nothing in the write buffer, then that means - // that nothing more will ever be provided - var ws = stream._writableState; - var ts = stream._transformState; - - if (ws.length) { - throw new Error('calling transform done when ws.length != 0'); - } - - if (ts.transforming) { - throw new Error('calling transform done when still transforming'); - } - - return stream.push(null); - } - - }, { - "./_stream_duplex": 53, - "core-util-is": 58, - "inherits": 48 - }], - 57: [function(require, module, exports) { - (function(process) { - // Copyright Joyent, Inc. and other Node contributors. - // - // Permission is hereby granted, free of charge, to any person obtaining a - // copy of this software and associated documentation files (the - // "Software"), to deal in the Software without restriction, including - // without limitation the rights to use, copy, modify, merge, publish, - // distribute, sublicense, and/or sell copies of the Software, and to permit - // persons to whom the Software is furnished to do so, subject to the - // following conditions: - // - // The above copyright notice and this permission notice shall be included - // in all copies or substantial portions of the Software. - // - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - // USE OR OTHER DEALINGS IN THE SOFTWARE. - - // A bit simpler than readable streams. - // Implement an async ._write(chunk, cb), and it'll handle all - // the drain event emission and buffering. - - module.exports = Writable; - - /**/ - var Buffer = require('buffer').Buffer; - /**/ - - Writable.WritableState = WritableState; - - - /**/ - var util = require('core-util-is'); - util.inherits = require('inherits'); - /**/ - - var Stream = require('stream'); - - util.inherits(Writable, Stream); - - function WriteReq(chunk, encoding, cb) { - this.chunk = chunk; - this.encoding = encoding; - this.callback = cb; - } - - function WritableState(options, stream) { - var Duplex = require('./_stream_duplex'); - - options = options || {}; - - // the point at which write() starts returning false - // Note: 0 is a valid value, means that we always return false if - // the entire buffer is not flushed immediately on write() - var hwm = options.highWaterMark; - var defaultHwm = options.objectMode ? 16 : 16 * 1024; - this.highWaterMark = (hwm || hwm === 0) ? hwm : defaultHwm; - - // object stream flag to indicate whether or not this stream - // contains buffers or objects. - this.objectMode = !!options.objectMode; - - if (stream instanceof Duplex) { - this.objectMode = this.objectMode || !!options.writableObjectMode; - } - - // cast to ints. - this.highWaterMark = ~~this.highWaterMark; - - this.needDrain = false; - // at the start of calling end() - this.ending = false; - // when end() has been called, and returned - this.ended = false; - // when 'finish' is emitted - this.finished = false; - - // should we decode strings into buffers before passing to _write? - // this is here so that some node-core streams can optimize string - // handling at a lower level. - var noDecode = options.decodeStrings === false; - this.decodeStrings = !noDecode; - - // Crypto is kind of old and crusty. Historically, its default string - // encoding is 'binary' so we have to make this configurable. - // Everything else in the universe uses 'utf8', though. - this.defaultEncoding = options.defaultEncoding || 'utf8'; - - // not an actual buffer we keep track of, but a measurement - // of how much we're waiting to get pushed to some underlying - // socket or file. - this.length = 0; - - // a flag to see when we're in the middle of a write. - this.writing = false; - - // when true all writes will be buffered until .uncork() call - this.corked = 0; - - // a flag to be able to tell if the onwrite cb is called immediately, - // or on a later tick. We set this to true at first, because any - // actions that shouldn't happen until "later" should generally also - // not happen before the first write call. - this.sync = true; - - // a flag to know if we're processing previously buffered items, which - // may call the _write() callback in the same tick, so that we don't - // end up in an overlapped onwrite situation. - this.bufferProcessing = false; - - // the callback that's passed to _write(chunk,cb) - this.onwrite = function(er) { - onwrite(stream, er); - }; - - // the callback that the user supplies to write(chunk,encoding,cb) - this.writecb = null; - - // the amount that is being written when _write is called. - this.writelen = 0; - - this.buffer = []; - - // number of pending user-supplied write callbacks - // this must be 0 before 'finish' can be emitted - this.pendingcb = 0; - - // emit prefinish if the only thing we're waiting for is _write cbs - // This is relevant for synchronous Transform streams - this.prefinished = false; - - // True if the error was already emitted and should not be thrown again - this.errorEmitted = false; - } - - function Writable(options) { - var Duplex = require('./_stream_duplex'); - - // Writable ctor is applied to Duplexes, though they're not - // instanceof Writable, they're instanceof Readable. - if (!(this instanceof Writable) && !(this instanceof Duplex)) { - return new Writable(options); - } - - this._writableState = new WritableState(options, this); - - // legacy. - this.writable = true; - - Stream.call(this); - } - - // Otherwise people can pipe Writable streams, which is just wrong. - Writable.prototype.pipe = function() { - this.emit('error', new Error('Cannot pipe. Not readable.')); - }; - - - function writeAfterEnd(stream, state, cb) { - var er = new Error('write after end'); - // TODO: defer error events consistently everywhere, not just the cb - stream.emit('error', er); - process.nextTick(function() { - cb(er); - }); - } - - // If we get something that is not a buffer, string, null, or undefined, - // and we're not in objectMode, then that's an error. - // Otherwise stream chunks are all considered to be of length=1, and the - // watermarks determine how many objects to keep in the buffer, rather than - // how many bytes or characters. - function validChunk(stream, state, chunk, cb) { - var valid = true; - if (!util.isBuffer(chunk) && - !util.isString(chunk) && - !util.isNullOrUndefined(chunk) && - !state.objectMode) { - var er = new TypeError('Invalid non-string/buffer chunk'); - stream.emit('error', er); - process.nextTick(function() { - cb(er); - }); - valid = false; - } - return valid; - } - - Writable.prototype.write = function(chunk, encoding, cb) { - var state = this._writableState; - var ret = false; - - if (util.isFunction(encoding)) { - cb = encoding; - encoding = null; - } - - if (util.isBuffer(chunk)) { - encoding = 'buffer'; - } else if (!encoding) { - encoding = state.defaultEncoding; - } - - if (!util.isFunction(cb)) { - cb = function() {}; - } - - if (state.ended) { - writeAfterEnd(this, state, cb); - } else if (validChunk(this, state, chunk, cb)) { - state.pendingcb++; - ret = writeOrBuffer(this, state, chunk, encoding, cb); - } - - return ret; - }; - - Writable.prototype.cork = function() { - var state = this._writableState; - - state.corked++; - }; - - Writable.prototype.uncork = function() { - var state = this._writableState; - - if (state.corked) { - state.corked--; - - if (!state.writing && - !state.corked && - !state.finished && - !state.bufferProcessing && - state.buffer.length) { - clearBuffer(this, state); - } - } - }; - - function decodeChunk(state, chunk, encoding) { - if (!state.objectMode && - state.decodeStrings !== false && - util.isString(chunk)) { - chunk = new Buffer(chunk, encoding); - } - return chunk; - } - - // if we're already writing something, then just put this - // in the queue, and wait our turn. Otherwise, call _write - // If we return false, then we need a drain event, so set that flag. - function writeOrBuffer(stream, state, chunk, encoding, cb) { - chunk = decodeChunk(state, chunk, encoding); - if (util.isBuffer(chunk)) { - encoding = 'buffer'; - } - var len = state.objectMode ? 1 : chunk.length; - - state.length += len; - - var ret = state.length < state.highWaterMark; - // we must ensure that previous needDrain will not be reset to false. - if (!ret) { - state.needDrain = true; - } - - if (state.writing || state.corked) { - state.buffer.push(new WriteReq(chunk, encoding, cb)); - } else { - doWrite(stream, state, false, len, chunk, encoding, cb); - } - - return ret; - } - - function doWrite(stream, state, writev, len, chunk, encoding, cb) { - state.writelen = len; - state.writecb = cb; - state.writing = true; - state.sync = true; - if (writev) { - stream._writev(chunk, state.onwrite); - } else { - stream._write(chunk, encoding, state.onwrite); - } - state.sync = false; - } - - function onwriteError(stream, state, sync, er, cb) { - if (sync) { - process.nextTick(function() { - state.pendingcb--; - cb(er); - }); - } else { - state.pendingcb--; - cb(er); - } - - stream._writableState.errorEmitted = true; - stream.emit('error', er); - } - - function onwriteStateUpdate(state) { - state.writing = false; - state.writecb = null; - state.length -= state.writelen; - state.writelen = 0; - } - - function onwrite(stream, er) { - var state = stream._writableState; - var sync = state.sync; - var cb = state.writecb; - - onwriteStateUpdate(state); - - if (er) { - onwriteError(stream, state, sync, er, cb); - } else { - // Check if we're actually ready to finish, but don't emit yet - var finished = needFinish(stream, state); - - if (!finished && - !state.corked && - !state.bufferProcessing && - state.buffer.length) { - clearBuffer(stream, state); - } - - if (sync) { - process.nextTick(function() { - afterWrite(stream, state, finished, cb); - }); - } else { - afterWrite(stream, state, finished, cb); - } - } - } - - function afterWrite(stream, state, finished, cb) { - if (!finished) { - onwriteDrain(stream, state); - } - state.pendingcb--; - cb(); - finishMaybe(stream, state); - } - - // Must force callback to be called on nextTick, so that we don't - // emit 'drain' before the write() consumer gets the 'false' return - // value, and has a chance to attach a 'drain' listener. - function onwriteDrain(stream, state) { - if (state.length === 0 && state.needDrain) { - state.needDrain = false; - stream.emit('drain'); - } - } - - - // if there's something in the buffer waiting, then process it - function clearBuffer(stream, state) { - state.bufferProcessing = true; - - if (stream._writev && state.buffer.length > 1) { - // Fast case, write everything using _writev() - var cbs = []; - for (var c = 0; c < state.buffer.length; c++) { - cbs.push(state.buffer[c].callback); - } - - // count the one we are adding, as well. - // TODO(isaacs) clean this up - state.pendingcb++; - doWrite(stream, state, true, state.length, state.buffer, '', function(err) { - for (var i = 0; i < cbs.length; i++) { - state.pendingcb--; - cbs[i](err); - } - }); - - // Clear buffer - state.buffer = []; - } else { - // Slow case, write chunks one-by-one - for (var c = 0; c < state.buffer.length; c++) { - var entry = state.buffer[c]; - var chunk = entry.chunk; - var encoding = entry.encoding; - var cb = entry.callback; - var len = state.objectMode ? 1 : chunk.length; - - doWrite(stream, state, false, len, chunk, encoding, cb); - - // if we didn't call the onwrite immediately, then - // it means that we need to wait until it does. - // also, that means that the chunk and cb are currently - // being processed, so move the buffer counter past them. - if (state.writing) { - c++; - break; - } - } - - if (c < state.buffer.length) { - state.buffer = state.buffer.slice(c); - } else { - state.buffer.length = 0; - } - } - - state.bufferProcessing = false; - } - - Writable.prototype._write = function(chunk, encoding, cb) { - cb(new Error('not implemented')); - - }; - - Writable.prototype._writev = null; - - Writable.prototype.end = function(chunk, encoding, cb) { - var state = this._writableState; - - if (util.isFunction(chunk)) { - cb = chunk; - chunk = null; - encoding = null; - } else if (util.isFunction(encoding)) { - cb = encoding; - encoding = null; - } - - if (!util.isNullOrUndefined(chunk)) { - this.write(chunk, encoding); - } - - // .end() fully uncorks - if (state.corked) { - state.corked = 1; - this.uncork(); - } - - // ignore unnecessary end() calls. - if (!state.ending && !state.finished) { - endWritable(this, state, cb); - } - }; - - - function needFinish(stream, state) { - return (state.ending && - state.length === 0 && - !state.finished && - !state.writing); - } - - function prefinish(stream, state) { - if (!state.prefinished) { - state.prefinished = true; - stream.emit('prefinish'); - } - } - - function finishMaybe(stream, state) { - var need = needFinish(stream, state); - if (need) { - if (state.pendingcb === 0) { - prefinish(stream, state); - state.finished = true; - stream.emit('finish'); - } else { - prefinish(stream, state); - } - } - return need; - } - - function endWritable(stream, state, cb) { - state.ending = true; - finishMaybe(stream, state); - if (cb) { - if (state.finished) { - process.nextTick(cb); - } else { - stream.once('finish', cb); - } - } - state.ended = true; - } - - }).call(this, require('_process')) - }, { - "./_stream_duplex": 53, - "_process": 51, - "buffer": 43, - "core-util-is": 58, - "inherits": 48, - "stream": 63 - }], - 58: [function(require, module, exports) { - (function(Buffer) { - // Copyright Joyent, Inc. and other Node contributors. - // - // Permission is hereby granted, free of charge, to any person obtaining a - // copy of this software and associated documentation files (the - // "Software"), to deal in the Software without restriction, including - // without limitation the rights to use, copy, modify, merge, publish, - // distribute, sublicense, and/or sell copies of the Software, and to permit - // persons to whom the Software is furnished to do so, subject to the - // following conditions: - // - // The above copyright notice and this permission notice shall be included - // in all copies or substantial portions of the Software. - // - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - // USE OR OTHER DEALINGS IN THE SOFTWARE. - - // NOTE: These type checking functions intentionally don't use `instanceof` - // because it is fragile and can be easily faked with `Object.create()`. - function isArray(ar) { - return Array.isArray(ar); - } - exports.isArray = isArray; - - function isBoolean(arg) { - return typeof arg === 'boolean'; - } - exports.isBoolean = isBoolean; - - function isNull(arg) { - return arg === null; - } - exports.isNull = isNull; - - function isNullOrUndefined(arg) { - return arg == null; - } - exports.isNullOrUndefined = isNullOrUndefined; - - function isNumber(arg) { - return typeof arg === 'number'; - } - exports.isNumber = isNumber; - - function isString(arg) { - return typeof arg === 'string'; - } - exports.isString = isString; - - function isSymbol(arg) { - return typeof arg === 'symbol'; - } - exports.isSymbol = isSymbol; - - function isUndefined(arg) { - return arg === void 0; - } - exports.isUndefined = isUndefined; - - function isRegExp(re) { - return isObject(re) && objectToString(re) === '[object RegExp]'; - } - exports.isRegExp = isRegExp; - - function isObject(arg) { - return typeof arg === 'object' && arg !== null; - } - exports.isObject = isObject; - - function isDate(d) { - return isObject(d) && objectToString(d) === '[object Date]'; - } - exports.isDate = isDate; - - function isError(e) { - return isObject(e) && - (objectToString(e) === '[object Error]' || e instanceof Error); - } - exports.isError = isError; - - function isFunction(arg) { - return typeof arg === 'function'; - } - exports.isFunction = isFunction; - - function isPrimitive(arg) { - return arg === null || - typeof arg === 'boolean' || - typeof arg === 'number' || - typeof arg === 'string' || - typeof arg === 'symbol' || // ES6 symbol - typeof arg === 'undefined'; - } - exports.isPrimitive = isPrimitive; - - function isBuffer(arg) { - return Buffer.isBuffer(arg); - } - exports.isBuffer = isBuffer; - - function objectToString(o) { - return Object.prototype.toString.call(o); - } - }).call(this, require("buffer").Buffer) - }, { - "buffer": 43 - }], - 59: [function(require, module, exports) { - module.exports = require("./lib/_stream_passthrough.js") - - }, { - "./lib/_stream_passthrough.js": 54 - }], - 60: [function(require, module, exports) { - exports = module.exports = require('./lib/_stream_readable.js'); - exports.Stream = require('stream'); - exports.Readable = exports; - exports.Writable = require('./lib/_stream_writable.js'); - exports.Duplex = require('./lib/_stream_duplex.js'); - exports.Transform = require('./lib/_stream_transform.js'); - exports.PassThrough = require('./lib/_stream_passthrough.js'); - - }, { - "./lib/_stream_duplex.js": 53, - "./lib/_stream_passthrough.js": 54, - "./lib/_stream_readable.js": 55, - "./lib/_stream_transform.js": 56, - "./lib/_stream_writable.js": 57, - "stream": 63 - }], - 61: [function(require, module, exports) { - module.exports = require("./lib/_stream_transform.js") - - }, { - "./lib/_stream_transform.js": 56 - }], - 62: [function(require, module, exports) { - module.exports = require("./lib/_stream_writable.js") - - }, { - "./lib/_stream_writable.js": 57 - }], - 63: [function(require, module, exports) { - // Copyright Joyent, Inc. and other Node contributors. - // - // Permission is hereby granted, free of charge, to any person obtaining a - // copy of this software and associated documentation files (the - // "Software"), to deal in the Software without restriction, including - // without limitation the rights to use, copy, modify, merge, publish, - // distribute, sublicense, and/or sell copies of the Software, and to permit - // persons to whom the Software is furnished to do so, subject to the - // following conditions: - // - // The above copyright notice and this permission notice shall be included - // in all copies or substantial portions of the Software. - // - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - // USE OR OTHER DEALINGS IN THE SOFTWARE. - - module.exports = Stream; - - var EE = require('events').EventEmitter; - var inherits = require('inherits'); - - inherits(Stream, EE); - Stream.Readable = require('readable-stream/readable.js'); - Stream.Writable = require('readable-stream/writable.js'); - Stream.Duplex = require('readable-stream/duplex.js'); - Stream.Transform = require('readable-stream/transform.js'); - Stream.PassThrough = require('readable-stream/passthrough.js'); - - // Backwards-compat with node 0.4.x - Stream.Stream = Stream; - - - - // old-style streams. Note that the pipe method (the only relevant - // part of this class) is overridden in the Readable class. - - function Stream() { - EE.call(this); - } - - Stream.prototype.pipe = function(dest, options) { - var source = this; - - function ondata(chunk) { - if (dest.writable) { - if (false === dest.write(chunk) && source.pause) { - source.pause(); - } - } - } - - source.on('data', ondata); - - function ondrain() { - if (source.readable && source.resume) { - source.resume(); - } - } - - dest.on('drain', ondrain); - - // If the 'end' option is not supplied, dest.end() will be called when - // source gets the 'end' or 'close' events. Only dest.end() once. - if (!dest._isStdio && (!options || options.end !== false)) { - source.on('end', onend); - source.on('close', onclose); - } - - var didOnEnd = false; - function onend() { - if (didOnEnd) { - return; - } - didOnEnd = true; - - dest.end(); - } - - - function onclose() { - if (didOnEnd) { - return; - } - didOnEnd = true; - - if (typeof dest.destroy === 'function') { - dest.destroy(); - } - } - - // don't leave dangling pipes when there are errors. - function onerror(er) { - cleanup(); - if (EE.listenerCount(this, 'error') === 0) { - throw er; // Unhandled stream error in pipe. - } - } - - source.on('error', onerror); - dest.on('error', onerror); - - // remove all the event listeners that were added. - function cleanup() { - source.removeListener('data', ondata); - dest.removeListener('drain', ondrain); - - source.removeListener('end', onend); - source.removeListener('close', onclose); - - source.removeListener('error', onerror); - dest.removeListener('error', onerror); - - source.removeListener('end', cleanup); - source.removeListener('close', cleanup); - - dest.removeListener('close', cleanup); - } - - source.on('end', cleanup); - source.on('close', cleanup); - - dest.on('close', cleanup); - - dest.emit('pipe', source); - - // Allow for unix-like usage: A.pipe(B).pipe(C) - return dest; - }; - - }, { - "events": 47, - "inherits": 48, - "readable-stream/duplex.js": 52, - "readable-stream/passthrough.js": 59, - "readable-stream/readable.js": 60, - "readable-stream/transform.js": 61, - "readable-stream/writable.js": 62 - }], - 64: [function(require, module, exports) { - // Copyright Joyent, Inc. and other Node contributors. - // - // Permission is hereby granted, free of charge, to any person obtaining a - // copy of this software and associated documentation files (the - // "Software"), to deal in the Software without restriction, including - // without limitation the rights to use, copy, modify, merge, publish, - // distribute, sublicense, and/or sell copies of the Software, and to permit - // persons to whom the Software is furnished to do so, subject to the - // following conditions: - // - // The above copyright notice and this permission notice shall be included - // in all copies or substantial portions of the Software. - // - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - // USE OR OTHER DEALINGS IN THE SOFTWARE. - - var Buffer = require('buffer').Buffer; - - var isBufferEncoding = Buffer.isEncoding - || function(encoding) { - switch (encoding && encoding.toLowerCase()) { - case 'hex': - case 'utf8': - case 'utf-8': - case 'ascii': - case 'binary': - case 'base64': - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - case 'raw': - return true; - default: - return false; - } - } - - - function assertEncoding(encoding) { - if (encoding && !isBufferEncoding(encoding)) { - throw new Error('Unknown encoding: ' + encoding); - } - } - - // StringDecoder provides an interface for efficiently splitting a series of - // buffers into a series of JS strings without breaking apart multi-byte - // characters. CESU-8 is handled as part of the UTF-8 encoding. - // - // @TODO Handling all encodings inside a single object makes it very difficult - // to reason about this code, so it should be split up in the future. - // @TODO There should be a utf8-strict encoding that rejects invalid UTF-8 code - // points as used by CESU-8. - var StringDecoder = exports.StringDecoder = function(encoding) { - this.encoding = (encoding || 'utf8').toLowerCase().replace(/[-_]/, ''); - assertEncoding(encoding); - switch (this.encoding) { - case 'utf8': - // CESU-8 represents each of Surrogate Pair by 3-bytes - this.surrogateSize = 3; - break; - case 'ucs2': - case 'utf16le': - // UTF-16 represents each of Surrogate Pair by 2-bytes - this.surrogateSize = 2; - this.detectIncompleteChar = utf16DetectIncompleteChar; - break; - case 'base64': - // Base-64 stores 3 bytes in 4 chars, and pads the remainder. - this.surrogateSize = 3; - this.detectIncompleteChar = base64DetectIncompleteChar; - break; - default: - this.write = passThroughWrite; - return; - } - - // Enough space to store all bytes of a single character. UTF-8 needs 4 - // bytes, but CESU-8 may require up to 6 (3 bytes per surrogate). - this.charBuffer = new Buffer(6); - // Number of bytes received for the current incomplete multi-byte character. - this.charReceived = 0; - // Number of bytes expected for the current incomplete multi-byte character. - this.charLength = 0; - }; - - - // write decodes the given buffer and returns it as JS string that is - // guaranteed to not contain any partial multi-byte characters. Any partial - // character found at the end of the buffer is buffered up, and will be - // returned when calling write again with the remaining bytes. - // - // Note: Converting a Buffer containing an orphan surrogate to a String - // currently works, but converting a String to a Buffer (via `new Buffer`, or - // Buffer#write) will replace incomplete surrogates with the unicode - // replacement character. See https://codereview.chromium.org/121173009/ . - StringDecoder.prototype.write = function(buffer) { - var charStr = ''; - // if our last write ended with an incomplete multibyte character - while (this.charLength) { - // determine how many remaining bytes this buffer has to offer for this char - var available = (buffer.length >= this.charLength - this.charReceived) ? - this.charLength - this.charReceived : - buffer.length; - - // add the new bytes to the char buffer - buffer.copy(this.charBuffer, this.charReceived, 0, available); - this.charReceived += available; - - if (this.charReceived < this.charLength) { - // still not enough chars in this buffer? wait for more ... - return ''; - } - - // remove bytes belonging to the current character from the buffer - buffer = buffer.slice(available, buffer.length); - - // get the character that was split - charStr = this.charBuffer.slice(0, this.charLength).toString(this.encoding); - - // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character - var charCode = charStr.charCodeAt(charStr.length - 1); - if (charCode >= 0xD800 && charCode <= 0xDBFF) { - this.charLength += this.surrogateSize; - charStr = ''; - continue; - } - this.charReceived = this.charLength = 0; - - // if there are no more bytes in this buffer, just emit our char - if (buffer.length === 0) { - return charStr; - } - break; - } - - // determine and set charLength / charReceived - this.detectIncompleteChar(buffer); - - var end = buffer.length; - if (this.charLength) { - // buffer the incomplete character bytes we got - buffer.copy(this.charBuffer, 0, buffer.length - this.charReceived, end); - end -= this.charReceived; - } - - charStr += buffer.toString(this.encoding, 0, end); - - var end = charStr.length - 1; - var charCode = charStr.charCodeAt(end); - // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character - if (charCode >= 0xD800 && charCode <= 0xDBFF) { - var size = this.surrogateSize; - this.charLength += size; - this.charReceived += size; - this.charBuffer.copy(this.charBuffer, size, 0, size); - buffer.copy(this.charBuffer, 0, 0, size); - return charStr.substring(0, end); - } - - // or just emit the charStr - return charStr; - }; - - // detectIncompleteChar determines if there is an incomplete UTF-8 character at - // the end of the given buffer. If so, it sets this.charLength to the byte - // length that character, and sets this.charReceived to the number of bytes - // that are available for this character. - StringDecoder.prototype.detectIncompleteChar = function(buffer) { - // determine how many bytes we have to check at the end of this buffer - var i = (buffer.length >= 3) ? 3 : buffer.length; - - // Figure out if one of the last i bytes of our buffer announces an - // incomplete char. - for (; i > 0; i--) { - var c = buffer[buffer.length - i]; - - // See http://en.wikipedia.org/wiki/UTF-8#Description - - // 110XXXXX - if (i == 1 && c >> 5 == 0x06) { - this.charLength = 2; - break; - } - - // 1110XXXX - if (i <= 2 && c >> 4 == 0x0E) { - this.charLength = 3; - break; - } - - // 11110XXX - if (i <= 3 && c >> 3 == 0x1E) { - this.charLength = 4; - break; - } - } - this.charReceived = i; - }; - - StringDecoder.prototype.end = function(buffer) { - var res = ''; - if (buffer && buffer.length) { - res = this.write(buffer); - } - - if (this.charReceived) { - var cr = this.charReceived; - var buf = this.charBuffer; - var enc = this.encoding; - res += buf.slice(0, cr).toString(enc); - } - - return res; - }; - - function passThroughWrite(buffer) { - return buffer.toString(this.encoding); - } - - function utf16DetectIncompleteChar(buffer) { - this.charReceived = buffer.length % 2; - this.charLength = this.charReceived ? 2 : 0; - } - - function base64DetectIncompleteChar(buffer) { - this.charReceived = buffer.length % 3; - this.charLength = this.charReceived ? 3 : 0; - } - - }, { - "buffer": 43 - }], - 65: [function(require, module, exports) { - module.exports = function isBuffer(arg) { - return arg && typeof arg === 'object' - && typeof arg.copy === 'function' - && typeof arg.fill === 'function' - && typeof arg.readUInt8 === 'function'; - } - }, {}], - 66: [function(require, module, exports) { - (function(process, global) { - // Copyright Joyent, Inc. and other Node contributors. - // - // Permission is hereby granted, free of charge, to any person obtaining a - // copy of this software and associated documentation files (the - // "Software"), to deal in the Software without restriction, including - // without limitation the rights to use, copy, modify, merge, publish, - // distribute, sublicense, and/or sell copies of the Software, and to permit - // persons to whom the Software is furnished to do so, subject to the - // following conditions: - // - // The above copyright notice and this permission notice shall be included - // in all copies or substantial portions of the Software. - // - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - // USE OR OTHER DEALINGS IN THE SOFTWARE. - - var formatRegExp = /%[sdj%]/g; - exports.format = function(f) { - if (!isString(f)) { - var objects = []; - for (var i = 0; i < arguments.length; i++) { - objects.push(inspect(arguments[i])); - } - return objects.join(' '); - } - - var i = 1; - var args = arguments; - var len = args.length; - var str = String(f).replace(formatRegExp, function(x) { - if (x === '%%') { - return '%'; - } - if (i >= len) { - return x; - } - switch (x) { - case '%s': - return String(args[i++]); - case '%d': - return Number(args[i++]); - case '%j': - try { - return JSON.stringify(args[i++]); - } catch (_) { - return '[Circular]'; - } - default: - return x; - } - }); - for (var x = args[i]; i < len; x = args[++i]) { - if (isNull(x) || !isObject(x)) { - str += ' ' + x; - } else { - str += ' ' + inspect(x); - } - } - return str; - }; - - - // Mark that a method should not be used. - // Returns a modified function which warns once by default. - // If --no-deprecation is set, then it is a no-op. - exports.deprecate = function(fn, msg) { - // Allow for deprecating things in the process of starting up. - if (isUndefined(global.process)) { - return function() { - return exports.deprecate(fn, msg).apply(this, arguments); - }; - } - - if (process.noDeprecation === true) { - return fn; - } - - var warned = false; - function deprecated() { - if (!warned) { - if (process.throwDeprecation) { - throw new Error(msg); - } else if (process.traceDeprecation) { - console.trace(msg); - } else { - console.error(msg); - } - warned = true; - } - return fn.apply(this, arguments); - } - - return deprecated; - }; - - - var debugs = {}; - var debugEnviron; - exports.debuglog = function(set) { - if (isUndefined(debugEnviron)) { - debugEnviron = process.env.NODE_DEBUG || ''; - } - set = set.toUpperCase(); - if (!debugs[set]) { - if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { - var pid = process.pid; - debugs[set] = function() { - var msg = exports.format.apply(exports, arguments); - console.error('%s %d: %s', set, pid, msg); - }; - } else { - debugs[set] = function() {}; - } - } - return debugs[set]; - }; - - - /** - * Echos the value of a value. Trys to print the value out - * in the best way possible given the different types. - * - * @param {Object} obj The object to print out. - * @param {Object} opts Optional options object that alters the output. - */ - /* legacy: obj, showHidden, depth, colors*/ - function inspect(obj, opts) { - // default options - var ctx = { - seen: [], - stylize: stylizeNoColor - }; - // legacy... - if (arguments.length >= 3) { - ctx.depth = arguments[2]; - } - if (arguments.length >= 4) { - ctx.colors = arguments[3]; - } - if (isBoolean(opts)) { - // legacy... - ctx.showHidden = opts; - } else if (opts) { - // got an "options" object - exports._extend(ctx, opts); - } - // set default options - if (isUndefined(ctx.showHidden)) { - ctx.showHidden = false; - } - if (isUndefined(ctx.depth)) { - ctx.depth = 2; - } - if (isUndefined(ctx.colors)) { - ctx.colors = false; - } - if (isUndefined(ctx.customInspect)) { - ctx.customInspect = true; - } - if (ctx.colors) { - ctx.stylize = stylizeWithColor; - } - return formatValue(ctx, obj, ctx.depth); - } - exports.inspect = inspect; - - - // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics - inspect.colors = { - 'bold': [1, 22], - 'italic': [3, 23], - 'underline': [4, 24], - 'inverse': [7, 27], - 'white': [37, 39], - 'grey': [90, 39], - 'black': [30, 39], - 'blue': [34, 39], - 'cyan': [36, 39], - 'green': [32, 39], - 'magenta': [35, 39], - 'red': [31, 39], - 'yellow': [33, 39] - }; - - // Don't use 'blue' not visible on cmd.exe - inspect.styles = { - 'special': 'cyan', - 'number': 'yellow', - 'boolean': 'yellow', - 'undefined': 'grey', - 'null': 'bold', - 'string': 'green', - 'date': 'magenta', - // "name": intentionally not styling - 'regexp': 'red' - }; - - - function stylizeWithColor(str, styleType) { - var style = inspect.styles[styleType]; - - if (style) { - return '\u001b[' + inspect.colors[style][0] + 'm' + str + - '\u001b[' + inspect.colors[style][1] + 'm'; - } else { - return str; - } - } - - - function stylizeNoColor(str, styleType) { - return str; - } - - - function arrayToHash(array) { - var hash = {}; - - array.forEach(function(val, idx) { - hash[val] = true; - }); - - return hash; - } - - - function formatValue(ctx, value, recurseTimes) { - // Provide a hook for user-specified inspect functions. - // Check that value is an object with an inspect function on it - if (ctx.customInspect && - value && - isFunction(value.inspect) && - // Filter out the util module, it's inspect function is special - value.inspect !== exports.inspect && - // Also filter out any prototype objects using the circular check. - !(value.constructor && value.constructor.prototype === value)) { - var ret = value.inspect(recurseTimes, ctx); - if (!isString(ret)) { - ret = formatValue(ctx, ret, recurseTimes); - } - return ret; - } - - // Primitive types cannot have properties - var primitive = formatPrimitive(ctx, value); - if (primitive) { - return primitive; - } - - // Look up the keys of the object. - var keys = Object.keys(value); - var visibleKeys = arrayToHash(keys); - - if (ctx.showHidden) { - keys = Object.getOwnPropertyNames(value); - } - - // IE doesn't make error fields non-enumerable - // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx - if (isError(value) - && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { - return formatError(value); - } - - // Some type of object without properties can be shortcutted. - if (keys.length === 0) { - if (isFunction(value)) { - var name = value.name ? ': ' + value.name : ''; - return ctx.stylize('[Function' + name + ']', 'special'); - } - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } - if (isDate(value)) { - return ctx.stylize(Date.prototype.toString.call(value), 'date'); - } - if (isError(value)) { - return formatError(value); - } - } - - var base = '', - array = false, - braces = ['{', '}']; - - // Make Array say that they are Array - if (isArray(value)) { - array = true; - braces = ['[', ']']; - } - - // Make functions say that they are functions - if (isFunction(value)) { - var n = value.name ? ': ' + value.name : ''; - base = ' [Function' + n + ']'; - } - - // Make RegExps say that they are RegExps - if (isRegExp(value)) { - base = ' ' + RegExp.prototype.toString.call(value); - } - - // Make dates with properties first say the date - if (isDate(value)) { - base = ' ' + Date.prototype.toUTCString.call(value); - } - - // Make error with message first say the error - if (isError(value)) { - base = ' ' + formatError(value); - } - - if (keys.length === 0 && (!array || value.length == 0)) { - return braces[0] + base + braces[1]; - } - - if (recurseTimes < 0) { - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } else { - return ctx.stylize('[Object]', 'special'); - } - } - - ctx.seen.push(value); - - var output; - if (array) { - output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); - } else { - output = keys.map(function(key) { - return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); - }); - } - - ctx.seen.pop(); - - return reduceToSingleString(output, base, braces); - } - - - function formatPrimitive(ctx, value) { - if (isUndefined(value)) { - return ctx.stylize('undefined', 'undefined'); - } - if (isString(value)) { - var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') - .replace(/'/g, "\\'") - .replace(/\\"/g, '"') + '\''; - return ctx.stylize(simple, 'string'); - } - if (isNumber(value)) { - return ctx.stylize('' + value, 'number'); - } - if (isBoolean(value)) { - return ctx.stylize('' + value, 'boolean'); - } - // For some reason typeof null is "object", so special case here. - if (isNull(value)) { - return ctx.stylize('null', 'null'); - } - } - - - function formatError(value) { - return '[' + Error.prototype.toString.call(value) + ']'; - } - - - function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { - var output = []; - for (var i = 0, l = value.length; i < l; ++i) { - if (hasOwnProperty(value, String(i))) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - String(i), true)); - } else { - output.push(''); - } - } - keys.forEach(function(key) { - if (!key.match(/^\d+$/)) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - key, true)); - } - }); - return output; - } - - - function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { - var name, - str, - desc; - desc = Object.getOwnPropertyDescriptor(value, key) || { - value: value[key] - }; - if (desc.get) { - if (desc.set) { - str = ctx.stylize('[Getter/Setter]', 'special'); - } else { - str = ctx.stylize('[Getter]', 'special'); - } - } else { - if (desc.set) { - str = ctx.stylize('[Setter]', 'special'); - } - } - if (!hasOwnProperty(visibleKeys, key)) { - name = '[' + key + ']'; - } - if (!str) { - if (ctx.seen.indexOf(desc.value) < 0) { - if (isNull(recurseTimes)) { - str = formatValue(ctx, desc.value, null); - } else { - str = formatValue(ctx, desc.value, recurseTimes - 1); - } - if (str.indexOf('\n') > -1) { - if (array) { - str = str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n').substr(2); - } else { - str = '\n' + str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n'); - } - } - } else { - str = ctx.stylize('[Circular]', 'special'); - } - } - if (isUndefined(name)) { - if (array && key.match(/^\d+$/)) { - return str; - } - name = JSON.stringify('' + key); - if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { - name = name.substr(1, name.length - 2); - name = ctx.stylize(name, 'name'); - } else { - name = name.replace(/'/g, "\\'") - .replace(/\\"/g, '"') - .replace(/(^"|"$)/g, "'"); - name = ctx.stylize(name, 'string'); - } - } - - return name + ': ' + str; - } - - - function reduceToSingleString(output, base, braces) { - var numLinesEst = 0; - var length = output.reduce(function(prev, cur) { - numLinesEst++; - if (cur.indexOf('\n') >= 0) { - numLinesEst++; - } - return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; - }, 0); - - if (length > 60) { - return braces[0] + - (base === '' ? '' : base + '\n ') + - ' ' + - output.join(',\n ') + - ' ' + - braces[1]; - } - - return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; - } - - - // NOTE: These type checking functions intentionally don't use `instanceof` - // because it is fragile and can be easily faked with `Object.create()`. - function isArray(ar) { - return Array.isArray(ar); - } - exports.isArray = isArray; - - function isBoolean(arg) { - return typeof arg === 'boolean'; - } - exports.isBoolean = isBoolean; - - function isNull(arg) { - return arg === null; - } - exports.isNull = isNull; - - function isNullOrUndefined(arg) { - return arg == null; - } - exports.isNullOrUndefined = isNullOrUndefined; - - function isNumber(arg) { - return typeof arg === 'number'; - } - exports.isNumber = isNumber; - - function isString(arg) { - return typeof arg === 'string'; - } - exports.isString = isString; - - function isSymbol(arg) { - return typeof arg === 'symbol'; - } - exports.isSymbol = isSymbol; - - function isUndefined(arg) { - return arg === void 0; - } - exports.isUndefined = isUndefined; - - function isRegExp(re) { - return isObject(re) && objectToString(re) === '[object RegExp]'; - } - exports.isRegExp = isRegExp; - - function isObject(arg) { - return typeof arg === 'object' && arg !== null; - } - exports.isObject = isObject; - - function isDate(d) { - return isObject(d) && objectToString(d) === '[object Date]'; - } - exports.isDate = isDate; - - function isError(e) { - return isObject(e) && - (objectToString(e) === '[object Error]' || e instanceof Error); - } - exports.isError = isError; - - function isFunction(arg) { - return typeof arg === 'function'; - } - exports.isFunction = isFunction; - - function isPrimitive(arg) { - return arg === null || - typeof arg === 'boolean' || - typeof arg === 'number' || - typeof arg === 'string' || - typeof arg === 'symbol' || // ES6 symbol - typeof arg === 'undefined'; - } - exports.isPrimitive = isPrimitive; - - exports.isBuffer = require('./support/isBuffer'); - - function objectToString(o) { - return Object.prototype.toString.call(o); - } - - - function pad(n) { - return n < 10 ? '0' + n.toString(10) : n.toString(10); - } - - - var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', - 'Oct', 'Nov', 'Dec']; - - // 26 Feb 16:19:34 - function timestamp() { - var d = new Date(); - var time = [pad(d.getHours()), - pad(d.getMinutes()), - pad(d.getSeconds())].join(':'); - return [d.getDate(), months[d.getMonth()], time].join(' '); - } - - - // log is just a thin wrapper to console.log that prepends a timestamp - exports.log = function() { - console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); - }; - - - /** - * Inherit the prototype methods from one constructor into another. - * - * The Function.prototype.inherits from lang.js rewritten as a standalone - * function (not on Function.prototype). NOTE: If this file is to be loaded - * during bootstrapping this function needs to be rewritten using some native - * functions as prototype setup using normal JavaScript does not work as - * expected during bootstrapping (see mirror.js in r114903). - * - * @param {function} ctor Constructor function which needs to inherit the - * prototype. - * @param {function} superCtor Constructor function to inherit prototype from. - */ - exports.inherits = require('inherits'); - - exports._extend = function(origin, add) { - // Don't do anything if add isn't an object - if (!add || !isObject(add)) { - return origin; - } - - var keys = Object.keys(add); - var i = keys.length; - while (i--) { - origin[keys[i]] = add[keys[i]]; - } - return origin; - }; - - function hasOwnProperty(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); - } - - }).call(this, require('_process'), typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) - }, { - "./support/isBuffer": 65, - "_process": 51, - "inherits": 48 - }], - 67: [function(require, module, exports) { - /* See LICENSE file for terms of use */ - - /* - * Text diff implementation. - * - * This library supports the following APIS: - * JsDiff.diffChars: Character by character diff - * JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace - * JsDiff.diffLines: Line based diff - * - * JsDiff.diffCss: Diff targeted at CSS content - * - * These methods are based on the implementation proposed in - * "An O(ND) Difference Algorithm and its Variations" (Myers, 1986). - * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927 - */ - (function(global, undefined) { - var objectPrototypeToString = Object.prototype.toString; - - /*istanbul ignore next*/ - function map(arr, mapper, that) { - if (Array.prototype.map) { - return Array.prototype.map.call(arr, mapper, that); - } - - var other = new Array(arr.length); - - for (var i = 0, n = arr.length; i < n; i++) { - other[i] = mapper.call(that, arr[i], i, arr); - } - return other; - } - function clonePath(path) { - return { - newPos: path.newPos, - components: path.components.slice(0) - }; - } - function removeEmpty(array) { - var ret = []; - for (var i = 0; i < array.length; i++) { - if (array[i]) { - ret.push(array[i]); - } - } - return ret; - } - function escapeHTML(s) { - var n = s; - n = n.replace(/&/g, '&'); - n = n.replace(//g, '>'); - n = n.replace(/"/g, '"'); - - return n; - } - - // This function handles the presence of circular references by bailing out when encountering an - // object that is already on the "stack" of items being processed. - function canonicalize(obj, stack, replacementStack) { - stack = stack || []; - replacementStack = replacementStack || []; - - var i; - - for (i = 0; i < stack.length; i += 1) { - if (stack[i] === obj) { - return replacementStack[i]; - } - } - - var canonicalizedObj; - - if ('[object Array]' === objectPrototypeToString.call(obj)) { - stack.push(obj); - canonicalizedObj = new Array(obj.length); - replacementStack.push(canonicalizedObj); - for (i = 0; i < obj.length; i += 1) { - canonicalizedObj[i] = canonicalize(obj[i], stack, replacementStack); - } - stack.pop(); - replacementStack.pop(); - } else if (typeof obj === 'object' && obj !== null) { - stack.push(obj); - canonicalizedObj = {}; - replacementStack.push(canonicalizedObj); - var sortedKeys = [], - key; - for (key in obj) { - sortedKeys.push(key); - } - sortedKeys.sort(); - for (i = 0; i < sortedKeys.length; i += 1) { - key = sortedKeys[i]; - canonicalizedObj[key] = canonicalize(obj[key], stack, replacementStack); - } - stack.pop(); - replacementStack.pop(); - } else { - canonicalizedObj = obj; - } - return canonicalizedObj; - } - - function buildValues(components, newString, oldString, useLongestToken) { - var componentPos = 0, - componentLen = components.length, - newPos = 0, - oldPos = 0; - - for (; componentPos < componentLen; componentPos++) { - var component = components[componentPos]; - if (!component.removed) { - if (!component.added && useLongestToken) { - var value = newString.slice(newPos, newPos + component.count); - value = map(value, function(value, i) { - var oldValue = oldString[oldPos + i]; - return oldValue.length > value.length ? oldValue : value; - }); - - component.value = value.join(''); - } else { - component.value = newString.slice(newPos, newPos + component.count).join(''); - } - newPos += component.count; - - // Common case - if (!component.added) { - oldPos += component.count; - } - } else { - component.value = oldString.slice(oldPos, oldPos + component.count).join(''); - oldPos += component.count; - - // Reverse add and remove so removes are output first to match common convention - // The diffing algorithm is tied to add then remove output and this is the simplest - // route to get the desired output with minimal overhead. - if (componentPos && components[componentPos - 1].added) { - var tmp = components[componentPos - 1]; - components[componentPos - 1] = components[componentPos]; - components[componentPos] = tmp; - } - } - } - - return components; - } - - function Diff(ignoreWhitespace) { - this.ignoreWhitespace = ignoreWhitespace; - } - Diff.prototype = { - diff: function(oldString, newString, callback) { - var self = this; - - function done(value) { - if (callback) { - setTimeout(function() { - callback(undefined, value); - }, 0); - return true; - } else { - return value; - } - } - - // Handle the identity case (this is due to unrolling editLength == 0 - if (newString === oldString) { - return done([{ - value: newString - }]); - } - if (!newString) { - return done([{ - value: oldString, - removed: true - }]); - } - if (!oldString) { - return done([{ - value: newString, - added: true - }]); - } - - newString = this.tokenize(newString); - oldString = this.tokenize(oldString); - - var newLen = newString.length, - oldLen = oldString.length; - var editLength = 1; - var maxEditLength = newLen + oldLen; - var bestPath = [{ - newPos: -1, - components: [] - }]; - - // Seed editLength = 0, i.e. the content starts with the same values - var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0); - if (bestPath[0].newPos + 1 >= newLen && oldPos + 1 >= oldLen) { - // Identity per the equality and tokenizer - return done([{ - value: newString.join('') - }]); - } - - // Main worker method. checks all permutations of a given edit length for acceptance. - function execEditLength() { - for (var diagonalPath = -1 * editLength; diagonalPath <= editLength; diagonalPath += 2) { - var basePath; - var addPath = bestPath[diagonalPath - 1], - removePath = bestPath[diagonalPath + 1], - oldPos = (removePath ? removePath.newPos : 0) - diagonalPath; - if (addPath) { - // No one else is going to attempt to use this value, clear it - bestPath[diagonalPath - 1] = undefined; - } - - var canAdd = addPath && addPath.newPos + 1 < newLen, - canRemove = removePath && 0 <= oldPos && oldPos < oldLen; - if (!canAdd && !canRemove) { - // If this path is a terminal then prune - bestPath[diagonalPath] = undefined; - continue; - } - - // Select the diagonal that we want to branch from. We select the prior - // path whose position in the new string is the farthest from the origin - // and does not pass the bounds of the diff graph - if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) { - basePath = clonePath(removePath); - self.pushComponent(basePath.components, undefined, true); - } else { - basePath = addPath; // No need to clone, we've pulled it from the list - basePath.newPos++; - self.pushComponent(basePath.components, true, undefined); - } - - oldPos = self.extractCommon(basePath, newString, oldString, diagonalPath); - - // If we have hit the end of both strings, then we are done - if (basePath.newPos + 1 >= newLen && oldPos + 1 >= oldLen) { - return done(buildValues(basePath.components, newString, oldString, self.useLongestToken)); - } else { - // Otherwise track this path as a potential candidate and continue. - bestPath[diagonalPath] = basePath; - } - } - - editLength++; - } - - // Performs the length of edit iteration. Is a bit fugly as this has to support the - // sync and async mode which is never fun. Loops over execEditLength until a value - // is produced. - if (callback) { - (function exec() { - setTimeout(function() { - // This should not happen, but we want to be safe. - /*istanbul ignore next */ - if (editLength > maxEditLength) { - return callback(); - } - - if (!execEditLength()) { - exec(); - } - }, 0); - }()); - } else { - while (editLength <= maxEditLength) { - var ret = execEditLength(); - if (ret) { - return ret; - } - } - } - }, - - pushComponent: function(components, added, removed) { - var last = components[components.length - 1]; - if (last && last.added === added && last.removed === removed) { - // We need to clone here as the component clone operation is just - // as shallow array clone - components[components.length - 1] = { - count: last.count + 1, - added: added, - removed: removed - }; - } else { - components.push({ - count: 1, - added: added, - removed: removed - }); - } - }, - extractCommon: function(basePath, newString, oldString, diagonalPath) { - var newLen = newString.length, - oldLen = oldString.length, - newPos = basePath.newPos, - oldPos = newPos - diagonalPath, - - commonCount = 0; - while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(newString[newPos + 1], oldString[oldPos + 1])) { - newPos++; - oldPos++; - commonCount++; - } - - if (commonCount) { - basePath.components.push({ - count: commonCount - }); - } - - basePath.newPos = newPos; - return oldPos; - }, - - equals: function(left, right) { - var reWhitespace = /\S/; - return left === right || (this.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right)); - }, - tokenize: function(value) { - return value.split(''); - } - }; - - var CharDiff = new Diff(); - - var WordDiff = new Diff(true); - var WordWithSpaceDiff = new Diff(); - WordDiff.tokenize = WordWithSpaceDiff.tokenize = function(value) { - return removeEmpty(value.split(/(\s+|\b)/)); - }; - - var CssDiff = new Diff(true); - CssDiff.tokenize = function(value) { - return removeEmpty(value.split(/([{}:;,]|\s+)/)); - }; - - var LineDiff = new Diff(); - - var TrimmedLineDiff = new Diff(); - TrimmedLineDiff.ignoreTrim = true; - - LineDiff.tokenize = TrimmedLineDiff.tokenize = function(value) { - var retLines = [], - lines = value.split(/^/m); - for (var i = 0; i < lines.length; i++) { - var line = lines[i], - lastLine = lines[i - 1], - lastLineLastChar = lastLine && lastLine[lastLine.length - 1]; - - // Merge lines that may contain windows new lines - if (line === '\n' && lastLineLastChar === '\r') { - retLines[retLines.length - 1] = retLines[retLines.length - 1].slice(0, -1) + '\r\n'; - } else { - if (this.ignoreTrim) { - line = line.trim(); - // add a newline unless this is the last line. - if (i < lines.length - 1) { - line += '\n'; - } - } - retLines.push(line); - } - } - - return retLines; - }; - - var PatchDiff = new Diff(); - PatchDiff.tokenize = function(value) { - var ret = [], - linesAndNewlines = value.split(/(\n|\r\n)/); - - // Ignore the final empty token that occurs if the string ends with a new line - if (!linesAndNewlines[linesAndNewlines.length - 1]) { - linesAndNewlines.pop(); - } - - // Merge the content and line separators into single tokens - for (var i = 0; i < linesAndNewlines.length; i++) { - var line = linesAndNewlines[i]; - - if (i % 2) { - ret[ret.length - 1] += line; - } else { - ret.push(line); - } - } - return ret; - }; - - var SentenceDiff = new Diff(); - SentenceDiff.tokenize = function(value) { - return removeEmpty(value.split(/(\S.+?[.!?])(?=\s+|$)/)); - }; - - var JsonDiff = new Diff(); - // Discriminate between two lines of pretty-printed, serialized JSON where one of them has a - // dangling comma and the other doesn't. Turns out including the dangling comma yields the nicest output: - JsonDiff.useLongestToken = true; - JsonDiff.tokenize = LineDiff.tokenize; - JsonDiff.equals = function(left, right) { - return LineDiff.equals(left.replace(/,([\r\n])/g, '$1'), right.replace(/,([\r\n])/g, '$1')); - }; - - var JsDiff = { - Diff: Diff, - - diffChars: function(oldStr, newStr, callback) { - return CharDiff.diff(oldStr, newStr, callback); - }, - diffWords: function(oldStr, newStr, callback) { - return WordDiff.diff(oldStr, newStr, callback); - }, - diffWordsWithSpace: function(oldStr, newStr, callback) { - return WordWithSpaceDiff.diff(oldStr, newStr, callback); - }, - diffLines: function(oldStr, newStr, callback) { - return LineDiff.diff(oldStr, newStr, callback); - }, - diffTrimmedLines: function(oldStr, newStr, callback) { - return TrimmedLineDiff.diff(oldStr, newStr, callback); - }, - - diffSentences: function(oldStr, newStr, callback) { - return SentenceDiff.diff(oldStr, newStr, callback); - }, - - diffCss: function(oldStr, newStr, callback) { - return CssDiff.diff(oldStr, newStr, callback); - }, - diffJson: function(oldObj, newObj, callback) { - return JsonDiff.diff( - typeof oldObj === 'string' ? oldObj : JSON.stringify(canonicalize(oldObj), undefined, ' '), - typeof newObj === 'string' ? newObj : JSON.stringify(canonicalize(newObj), undefined, ' '), - callback - ); - }, - - createTwoFilesPatch: function(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader) { - var ret = []; - - if (oldFileName == newFileName) { - ret.push('Index: ' + oldFileName); - } - ret.push('==================================================================='); - ret.push('--- ' + oldFileName + (typeof oldHeader === 'undefined' ? '' : '\t' + oldHeader)); - ret.push('+++ ' + newFileName + (typeof newHeader === 'undefined' ? '' : '\t' + newHeader)); - - var diff = PatchDiff.diff(oldStr, newStr); - diff.push({ - value: '', - lines: [] - }); // Append an empty value to make cleanup easier - - // Formats a given set of lines for printing as context lines in a patch - function contextLines(lines) { - return map(lines, function(entry) { - return ' ' + entry; - }); - } - - // Outputs the no newline at end of file warning if needed - function eofNL(curRange, i, current) { - var last = diff[diff.length - 2], - isLast = i === diff.length - 2, - isLastOfType = i === diff.length - 3 && current.added !== last.added; - - // Figure out if this is the last line for the given file and missing NL - if (!(/\n$/.test(current.value)) && (isLast || isLastOfType)) { - curRange.push('\\ No newline at end of file'); - } - } - - var oldRangeStart = 0, - newRangeStart = 0, - curRange = [], - oldLine = 1, - newLine = 1; - for (var i = 0; i < diff.length; i++) { - var current = diff[i], - lines = current.lines || current.value.replace(/\n$/, '').split('\n'); - current.lines = lines; - - if (current.added || current.removed) { - // If we have previous context, start with that - if (!oldRangeStart) { - var prev = diff[i - 1]; - oldRangeStart = oldLine; - newRangeStart = newLine; - - if (prev) { - curRange = contextLines(prev.lines.slice(-4)); - oldRangeStart -= curRange.length; - newRangeStart -= curRange.length; - } - } - - // Output our changes - curRange.push.apply(curRange, map(lines, function(entry) { - return (current.added ? '+' : '-') + entry; - })); - eofNL(curRange, i, current); - - // Track the updated file position - if (current.added) { - newLine += lines.length; - } else { - oldLine += lines.length; - } - } else { - // Identical context lines. Track line changes - if (oldRangeStart) { - // Close out any changes that have been output (or join overlapping) - if (lines.length <= 8 && i < diff.length - 2) { - // Overlapping - curRange.push.apply(curRange, contextLines(lines)); - } else { - // end the range and output - var contextSize = Math.min(lines.length, 4); - ret.push( - '@@ -' + oldRangeStart + ',' + (oldLine - oldRangeStart + contextSize) - + ' +' + newRangeStart + ',' + (newLine - newRangeStart + contextSize) - + ' @@'); - ret.push.apply(ret, curRange); - ret.push.apply(ret, contextLines(lines.slice(0, contextSize))); - if (lines.length <= 4) { - eofNL(ret, i, current); - } - - oldRangeStart = 0; - newRangeStart = 0; - curRange = []; - } - } - oldLine += lines.length; - newLine += lines.length; - } - } - - return ret.join('\n') + '\n'; - }, - - createPatch: function(fileName, oldStr, newStr, oldHeader, newHeader) { - return JsDiff.createTwoFilesPatch(fileName, fileName, oldStr, newStr, oldHeader, newHeader); - }, - - applyPatch: function(oldStr, uniDiff) { - var diffstr = uniDiff.split('\n'), - hunks = [], - i = 0, - remEOFNL = false, - addEOFNL = false; - - // Skip to the first change hunk - while (i < diffstr.length && !(/^@@/.test(diffstr[i]))) { - i++; - } - - // Parse the unified diff - for (; i < diffstr.length; i++) { - if (diffstr[i][0] === '@') { - var chnukHeader = diffstr[i].split(/@@ -(\d+),(\d+) \+(\d+),(\d+) @@/); - hunks.unshift({ - start: chnukHeader[3], - oldlength: +chnukHeader[2], - removed: [], - newlength: chnukHeader[4], - added: [] - }); - } else if (diffstr[i][0] === '+') { - hunks[0].added.push(diffstr[i].substr(1)); - } else if (diffstr[i][0] === '-') { - hunks[0].removed.push(diffstr[i].substr(1)); - } else if (diffstr[i][0] === ' ') { - hunks[0].added.push(diffstr[i].substr(1)); - hunks[0].removed.push(diffstr[i].substr(1)); - } else if (diffstr[i][0] === '\\') { - if (diffstr[i - 1][0] === '+') { - remEOFNL = true; - } else if (diffstr[i - 1][0] === '-') { - addEOFNL = true; - } - } - } - - // Apply the diff to the input - var lines = oldStr.split('\n'); - for (i = hunks.length - 1; i >= 0; i--) { - var hunk = hunks[i]; - // Sanity check the input string. Bail if we don't match. - for (var j = 0; j < hunk.oldlength; j++) { - if (lines[hunk.start - 1 + j] !== hunk.removed[j]) { - return false; - } - } - Array.prototype.splice.apply(lines, [hunk.start - 1, hunk.oldlength].concat(hunk.added)); - } - - // Handle EOFNL insertion/removal - if (remEOFNL) { - while (!lines[lines.length - 1]) { - lines.pop(); - } - } else if (addEOFNL) { - lines.push(''); - } - return lines.join('\n'); - }, - - convertChangesToXML: function(changes) { - var ret = []; - for (var i = 0; i < changes.length; i++) { - var change = changes[i]; - if (change.added) { - ret.push(''); - } else if (change.removed) { - ret.push(''); - } - - ret.push(escapeHTML(change.value)); - - if (change.added) { - ret.push(''); - } else if (change.removed) { - ret.push(''); - } - } - return ret.join(''); - }, - - // See: http://code.google.com/p/google-diff-match-patch/wiki/API - convertChangesToDMP: function(changes) { - var ret = [], - change, - operation; - for (var i = 0; i < changes.length; i++) { - change = changes[i]; - if (change.added) { - operation = 1; - } else if (change.removed) { - operation = -1; - } else { - operation = 0; - } - - ret.push([operation, change.value]); - } - return ret; - }, - - canonicalize: canonicalize - }; - - /*istanbul ignore next */ - /*global module */ - if (typeof module !== 'undefined' && module.exports) { - module.exports = JsDiff; - } else if (typeof define === 'function' && define.amd) { - /*global define */ - define([], function() { - return JsDiff; - }); - } else if (typeof global.JsDiff === 'undefined') { - global.JsDiff = JsDiff; - } - }(this)); - - }, {}], - 68: [function(require, module, exports) { - 'use strict'; - - var matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g; - - module.exports = function(str) { - if (typeof str !== 'string') { - throw new TypeError('Expected a string'); - } - - return str.replace(matchOperatorsRe, '\\$&'); - }; - - }, {}], - 69: [function(require, module, exports) { - (function(process) { - // Growl - Copyright TJ Holowaychuk (MIT Licensed) - - /** - * Module dependencies. - */ - - var exec = require('child_process').exec, - fs = require('fs'), - path = require('path'), - exists = fs.existsSync || path.existsSync, - os = require('os'), - quote = JSON.stringify, - cmd; - - function which(name) { - var paths = process.env.PATH.split(':'); - var loc; - - for (var i = 0, len = paths.length; i < len; ++i) { - loc = path.join(paths[i], name); - if (exists(loc)) { - return loc; - } - } - } - - switch (os.type()) { - case 'Darwin': - if (which('terminal-notifier')) { - cmd = { - type: "Darwin-NotificationCenter", - pkg: "terminal-notifier", - msg: '-message', - title: '-title', - subtitle: '-subtitle', - priority: { - cmd: '-execute', - range: [] - } - }; - } else { - cmd = { - type: "Darwin-Growl", - pkg: "growlnotify", - msg: '-m', - sticky: '--sticky', - priority: { - cmd: '--priority', - range: [ - -2 - , -1 - , 0 - , 1 - , 2 - , "Very Low" - , "Moderate" - , "Normal" - , "High" - , "Emergency" - ] - } - }; - } - break; - case 'Linux': - cmd = { - type: "Linux", - pkg: "notify-send", - msg: '', - sticky: '-t 0', - icon: '-i', - priority: { - cmd: '-u', - range: [ - "low" - , "normal" - , "critical" - ] - } - }; - break; - case 'Windows_NT': - cmd = { - type: "Windows", - pkg: "growlnotify", - msg: '', - sticky: '/s:true', - title: '/t:', - icon: '/i:', - priority: { - cmd: '/p:', - range: [ - -2 - , -1 - , 0 - , 1 - , 2 - ] - } - }; - break; - } - - /** - * Expose `growl`. - */ - - exports = module.exports = growl; - - /** - * Node-growl version. - */ - - exports.version = '1.4.1' - - /** - * Send growl notification _msg_ with _options_. - * - * Options: - * - * - title Notification title - * - sticky Make the notification stick (defaults to false) - * - priority Specify an int or named key (default is 0) - * - name Application name (defaults to growlnotify) - * - image - * - path to an icon sets --iconpath - * - path to an image sets --image - * - capitalized word sets --appIcon - * - filename uses extname as --icon - * - otherwise treated as --icon - * - * Examples: - * - * growl('New email') - * growl('5 new emails', { title: 'Thunderbird' }) - * growl('Email sent', function(){ - * // ... notification sent - * }) - * - * @param {string} msg - * @param {object} options - * @param {function} fn - * @api public - */ - - function growl(msg, options, fn) { - var image, - args, - options = options || {}, - fn = fn || function() {}; - - // noop - if (!cmd) { - return fn(new Error('growl not supported on this platform')); - } - args = [cmd.pkg]; - - // image - if (image = options.image) { - switch (cmd.type) { - case 'Darwin-Growl': - var flag, - ext = path.extname(image).substr(1) - flag = flag || ext == 'icns' && 'iconpath' - flag = flag || /^[A-Z]/.test(image) && 'appIcon' - flag = flag || /^png|gif|jpe?g$/.test(ext) && 'image' - flag = flag || ext && (image = ext) && 'icon' - flag = flag || 'icon' - args.push('--' + flag, quote(image)) - break; - case 'Linux': - args.push(cmd.icon, quote(image)); - // libnotify defaults to sticky, set a hint for transient notifications - if (!options.sticky) { - args.push('--hint=int:transient:1'); - } - break; - case 'Windows': - args.push(cmd.icon + quote(image)); - break; - } - } - - // sticky - if (options.sticky) { - args.push(cmd.sticky); - } - - // priority - if (options.priority) { - var priority = options.priority + ''; - var checkindexOf = cmd.priority.range.indexOf(priority); - if (~cmd.priority.range.indexOf(priority)) { - args.push(cmd.priority, options.priority); - } - } - - // name - if (options.name && cmd.type === "Darwin-Growl") { - args.push('--name', options.name); - } - - switch (cmd.type) { - case 'Darwin-Growl': - args.push(cmd.msg); - args.push(quote(msg)); - if (options.title) { - args.push(quote(options.title)); - } - break; - case 'Darwin-NotificationCenter': - args.push(cmd.msg); - args.push(quote(msg)); - if (options.title) { - args.push(cmd.title); - args.push(quote(options.title)); - } - if (options.subtitle) { - args.push(cmd.subtitle); - args.push(quote(options.subtitle)); - } - break; - case 'Darwin-Growl': - args.push(cmd.msg); - args.push(quote(msg)); - if (options.title) { - args.push(quote(options.title)); - } - break; - case 'Linux': - if (options.title) { - args.push(quote(options.title)); - args.push(cmd.msg); - args.push(quote(msg)); - } else { - args.push(quote(msg)); - } - break; - case 'Windows': - args.push(quote(msg)); - if (options.title) { - args.push(cmd.title + quote(options.title)); - } - break; - } - - // execute - exec(args.join(' '), fn); - } - ; - - }).call(this, require('_process')) - }, { - "_process": 51, - "child_process": 41, - "fs": 41, - "os": 50, - "path": 41 - }], - 70: [function(require, module, exports) { - (function(process, global) { - /** - * Shim process.stdout. - */ - - process.stdout = require('browser-stdout')(); - - var Mocha = require('../'); - - /** - * Create a Mocha instance. - * - * @return {undefined} - */ - - var mocha = new Mocha({ - reporter: 'html' - }); - - /** - * Save timer references to avoid Sinon interfering (see GH-237). - */ - - var Date = global.Date; - var setTimeout = global.setTimeout; - var setInterval = global.setInterval; - var clearTimeout = global.clearTimeout; - var clearInterval = global.clearInterval; - - var uncaughtExceptionHandlers = []; - - var originalOnerrorHandler = global.onerror; - - /** - * Remove uncaughtException listener. - * Revert to original onerror handler if previously defined. - */ - - process.removeListener = function(e, fn) { - if ('uncaughtException' == e) { - if (originalOnerrorHandler) { - global.onerror = originalOnerrorHandler; - } else { - global.onerror = function() {}; - } - var i = Mocha.utils.indexOf(uncaughtExceptionHandlers, fn); - if (i != -1) { - uncaughtExceptionHandlers.splice(i, 1); - } - } - }; - - /** - * Implements uncaughtException listener. - */ - - process.on = function(e, fn) { - if ('uncaughtException' == e) { - global.onerror = function(err, url, line) { - fn(new Error(err + ' (' + url + ':' + line + ')')); - return !mocha.allowUncaught; - }; - uncaughtExceptionHandlers.push(fn); - } - }; - - // The BDD UI is registered by default, but no UI will be functional in the - // browser without an explicit call to the overridden `mocha.ui` (see below). - // Ensure that this default UI does not expose its methods to the global scope. - mocha.suite.removeAllListeners('pre-require'); - - var immediateQueue = [], - immediateTimeout; - - function timeslice() { - var immediateStart = new Date().getTime(); - while (immediateQueue.length && (new Date().getTime() - immediateStart) < 100) { - immediateQueue.shift()(); - } - if (immediateQueue.length) { - immediateTimeout = setTimeout(timeslice, 0); - } else { - immediateTimeout = null; - } - } - - /** - * High-performance override of Runner.immediately. - */ - - Mocha.Runner.immediately = function(callback) { - immediateQueue.push(callback); - if (!immediateTimeout) { - immediateTimeout = setTimeout(timeslice, 0); - } - }; - - /** - * Function to allow assertion libraries to throw errors directly into mocha. - * This is useful when running tests in a browser because window.onerror will - * only receive the 'message' attribute of the Error. - */ - mocha.throwError = function(err) { - Mocha.utils.forEach(uncaughtExceptionHandlers, function(fn) { - fn(err); - }); - throw err; - }; - - /** - * Override ui to ensure that the ui functions are initialized. - * Normally this would happen in Mocha.prototype.loadFiles. - */ - - mocha.ui = function(ui) { - Mocha.prototype.ui.call(this, ui); - this.suite.emit('pre-require', global, null, this); - return this; - }; - - /** - * Setup mocha with the given setting options. - */ - - mocha.setup = function(opts) { - if ('string' == typeof opts) { - opts = { - ui: opts - }; - } - for (var opt in opts) { - this[opt](opts[opt]); - } - return this; - }; - - /** - * Run mocha, returning the Runner. - */ - - mocha.run = function(fn) { - var options = mocha.options; - mocha.globals('location'); - - var query = Mocha.utils.parseQuery(global.location.search || ''); - if (query.grep) { - mocha.grep(new RegExp(query.grep)); - } - if (query.fgrep) { - mocha.grep(query.fgrep); - } - if (query.invert) { - mocha.invert(); - } - - return Mocha.prototype.run.call(mocha, function(err) { - // The DOM Document is not available in Web Workers. - var document = global.document; - if (document && document.getElementById('mocha') && options.noHighlighting !== true) { - Mocha.utils.highlightTags('code'); - } - if (fn) { - fn(err); - } - }); - }; - - /** - * Expose the process shim. - * https://github.com/mochajs/mocha/pull/916 - */ - - Mocha.process = process; - - /** - * Expose mocha. - */ - - window.Mocha = Mocha; - window.mocha = mocha; - - }).call(this, require('_process'), typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) - }, { - "../": 1, - "_process": 51, - "browser-stdout": 40 - }] -}, {}, [70]); diff --git a/tests/browser/slim.html b/tests/browser/slim.html new file mode 100644 index 00000000..7b6f80ca --- /dev/null +++ b/tests/browser/slim.html @@ -0,0 +1,65 @@ + + + + + Mocha Tests (slim) + + + +
    + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/compiler.js b/tests/compiler.js index a3ee748b..81a71a82 100644 --- a/tests/compiler.js +++ b/tests/compiler.js @@ -1,15 +1,19 @@ (function() { 'use strict'; - var expect, - util, - Template, - fs; + var expect; + var util; + var Template; + var fs; + var render; + var equal; + var finish; + var isSlim; if (typeof require !== 'undefined') { expect = require('expect.js'); util = require('./util'); - Template = require('../src/environment').Template; + Template = require('../nunjucks/src/environment').Template; fs = require('fs'); } else { expect = window.expect; @@ -17,9 +21,10 @@ Template = nunjucks.Template; } - var render = util.render; - var equal = util.equal; - var finish = util.finish; + render = util.render; + equal = util.equal; + finish = util.finish; + isSlim = util.isSlim; describe('compiler', function() { it('should compile templates', function(done) { @@ -210,7 +215,7 @@ equal('{% if "pizza" in food %}yum{% endif %}', { food: { - 'pizza': true + pizza: true } }, 'yum'); @@ -298,137 +303,220 @@ finish(done); }); - function runLoopTests(block, end) { - equal('{% ' + block + ' i in arr %}{{ i }}{% ' + end + ' %}', - { - arr: [1, 2, 3, 4, 5] - }, '12345'); - - equal('{% ' + block + ' i in arr %}{{ i }}{% else %}empty{% ' + end + ' %}', - { - arr: [1, 2, 3, 4, 5] - }, '12345'); - - equal('{% ' + block + ' i in arr %}{{ i }}{% else %}empty{% ' + end + ' %}', - { - arr: [] - }, 'empty'); - - equal( - '{% ' + block + ' a, b, c in arr %}' + - '{{ a }},{{ b }},{{ c }}.{% ' + end + ' %}', - { - arr: [['x', 'y', 'z'], ['1', '2', '3']] - }, 'x,y,z.1,2,3.'); - - equal('{% ' + block + ' item in arr | batch(2) %}{{ item[0] }}{% ' + end + ' %}', - { - arr: ['a', 'b', 'c', 'd'] - }, 'ac'); - - equal( - '{% ' + block + ' k, v in { one: 1, two: 2 } %}' + - '-{{ k }}:{{ v }}-{% ' + end + ' %}', '-one:1--two:2-'); - - equal('{% ' + block + ' i in [7,3,6] %}{{ loop.index }}{% ' + end + ' %}', '123'); - equal('{% ' + block + ' i in [7,3,6] %}{{ loop.index0 }}{% ' + end + ' %}', '012'); - equal('{% ' + block + ' i in [7,3,6] %}{{ loop.revindex }}{% ' + end + ' %}', '321'); - equal('{% ' + block + ' i in [7,3,6] %}{{ loop.revindex0 }}{% ' + end + ' %}', '210'); - equal('{% ' + block + ' i in [7,3,6] %}{% if loop.first %}{{ i }}{% endif %}{% ' + end + ' %}', - '7'); - equal('{% ' + block + ' i in [7,3,6] %}{% if loop.last %}{{ i }}{% endif %}{% ' + end + ' %}', - '6'); - equal('{% ' + block + ' i in [7,3,6] %}{{ loop.length }}{% ' + end + ' %}', '333'); - equal('{% ' + block + ' i in foo %}{{ i }}{% ' + end + ' %}', ''); - equal('{% ' + block + ' i in foo.bar %}{{ i }}{% ' + end + ' %}', { - foo: {} - }, ''); - equal('{% ' + block + ' i in foo %}{{ i }}{% ' + end + ' %}', { - foo: null - }, ''); - - equal('{% ' + block + ' x, y in points %}[{{ x }},{{ y }}]{% ' + end + ' %}', - { - points: [[1, 2], [3, 4], [5, 6]] - }, - '[1,2][3,4][5,6]'); - - equal('{% ' + block + ' x, y in points %}{{ loop.index }}{% ' + end + ' %}', - { - points: [[1, 2], [3, 4], [5, 6]] - }, - '123'); + function runLoopTests(block) { + var end = { + asyncAll: 'endall', + asyncEach: 'endeach', + for: 'endfor' + }[block]; - equal('{% ' + block + ' x, y in points %}{{ loop.revindex }}{% ' + end + ' %}', - { - points: [[1, 2], [3, 4], [5, 6]] - }, - '321'); - - equal('{% ' + block + ' k, v in items %}({{ k }},{{ v }}){% ' + end + ' %}', - { - items: { - foo: 1, - bar: 2 - } - }, - '(foo,1)(bar,2)'); - - equal('{% ' + block + ' k, v in items %}{{ loop.index }}{% ' + end + ' %}', - { - items: { - foo: 1, - bar: 2 - } - }, - '12'); - - equal('{% ' + block + ' k, v in items %}{{ loop.revindex }}{% ' + end + ' %}', - { - items: { - foo: 1, - bar: 2 - } - }, - '21'); - - equal('{% ' + block + ' k, v in items %}{{ loop.length }}{% ' + end + ' %}', - { - items: { - foo: 1, - bar: 2 + describe('the ' + block + ' tag', function() { + it('should loop over simple arrays', function() { + equal( + '{% ' + block + ' i in arr %}{{ i }}{% ' + end + ' %}', + { arr: [1, 2, 3, 4, 5] }, + '12345'); + }); + it('should loop normally with an {% else %} tag and non-empty array', function() { + equal( + '{% ' + block + ' i in arr %}{{ i }}{% else %}empty{% ' + end + ' %}', + { arr: [1, 2, 3, 4, 5] }, + '12345'); + }); + it('should execute the {% else %} block when looping over an empty array', function() { + equal( + '{% ' + block + ' i in arr %}{{ i }}{% else %}empty{% ' + end + ' %}', + { arr: [] }, + 'empty'); + }); + it('should support destructured looping', function() { + equal( + '{% ' + block + ' a, b, c in arr %}' + + '{{ a }},{{ b }},{{ c }}.{% ' + end + ' %}', + { arr: [['x', 'y', 'z'], ['1', '2', '3']] }, + 'x,y,z.1,2,3.'); + }); + it('should do loop over key-values of a literal in-template Object', function() { + equal( + '{% ' + block + ' k, v in { one: 1, two: 2 } %}' + + '-{{ k }}:{{ v }}-{% ' + end + ' %}', '-one:1--two:2-'); + }); + it('should support loop.index', function() { + equal('{% ' + block + ' i in [7,3,6] %}{{ loop.index }}{% ' + end + ' %}', '123'); + }); + it('should support loop.index0', function() { + equal('{% ' + block + ' i in [7,3,6] %}{{ loop.index0 }}{% ' + end + ' %}', '012'); + }); + it('should support loop.revindex', function() { + equal('{% ' + block + ' i in [7,3,6] %}{{ loop.revindex }}{% ' + end + ' %}', '321'); + }); + it('should support loop.revindex0', function() { + equal('{% ' + block + ' i in [7,3,6] %}{{ loop.revindex0 }}{% ' + end + ' %}', '210'); + }); + it('should support loop.first', function() { + equal( + '{% ' + block + ' i in [7,3,6] %}' + + '{% if loop.first %}{{ i }}{% endif %}' + + '{% ' + end + ' %}', + '7'); + }); + it('should support loop.last', function() { + equal( + '{% ' + block + ' i in [7,3,6] %}' + + '{% if loop.last %}{{ i }}{% endif %}' + + '{% ' + end + ' %}', + '6'); + }); + it('should support loop.length', function() { + equal('{% ' + block + ' i in [7,3,6] %}{{ loop.length }}{% ' + end + ' %}', '333'); + }); + it('should fail silently when looping over an undefined variable', function() { + equal('{% ' + block + ' i in foo %}{{ i }}{% ' + end + ' %}', ''); + }); + it('should fail silently when looping over an undefined property', function() { + equal( + '{% ' + block + ' i in foo.bar %}{{ i }}{% ' + end + ' %}', + { foo: {} }, + ''); + }); + // TODO: this behavior differs from jinja2 + it('should fail silently when looping over a null variable', function() { + equal( + '{% ' + block + ' i in foo %}{{ i }}{% ' + end + ' %}', + { foo: null }, + ''); + }); + it('should loop over two-dimensional arrays', function() { + equal('{% ' + block + ' x, y in points %}[{{ x }},{{ y }}]{% ' + end + ' %}', + { points: [[1, 2], [3, 4], [5, 6]] }, + '[1,2][3,4][5,6]'); + }); + it('should loop over four-dimensional arrays', function() { + equal( + '{% ' + block + ' a, b, c, d in arr %}[{{ a }},{{ b }},{{ c }},{{ d }}]{% ' + end + '%}', + { arr: [[1, 2, 3, 4], [5, 6, 7, 8]] }, + '[1,2,3,4][5,6,7,8]'); + }); + it('should support loop.index with two-dimensional loops', function() { + equal('{% ' + block + ' x, y in points %}{{ loop.index }}{% ' + end + ' %}', + { + points: [[1, 2], [3, 4], [5, 6]] + }, + '123'); + }); + it('should support loop.revindex with two-dimensional loops', function() { + equal('{% ' + block + ' x, y in points %}{{ loop.revindex }}{% ' + end + ' %}', + { + points: [[1, 2], [3, 4], [5, 6]] + }, + '321'); + }); + it('should support key-value looping over an Object variable', function() { + equal('{% ' + block + ' k, v in items %}({{ k }},{{ v }}){% ' + end + ' %}', + { + items: { + foo: 1, + bar: 2 + } + }, + '(foo,1)(bar,2)'); + }); + it('should support loop.index when looping over an Object\'s key-value pairs', function() { + equal('{% ' + block + ' k, v in items %}{{ loop.index }}{% ' + end + ' %}', + { + items: { + foo: 1, + bar: 2 + } + }, + '12'); + }); + it('should support loop.revindex when looping over an Object\'s key-value pairs', function() { + equal('{% ' + block + ' k, v in items %}{{ loop.revindex }}{% ' + end + ' %}', + { + items: { + foo: 1, + bar: 2 + } + }, + '21'); + }); + it('should support loop.length when looping over an Object\'s key-value pairs', function() { + equal('{% ' + block + ' k, v in items %}{{ loop.length }}{% ' + end + ' %}', + { + items: { + foo: 1, + bar: 2 + } + }, + '22'); + }); + it('should support include tags in the body of the loop', function() { + equal('{% ' + block + ' item, v in items %}{% include "item.njk" %}{% ' + end + ' %}', + { + items: { + foo: 1, + bar: 2 + } + }, + 'showing fooshowing bar'); + }); + it('should work with {% set %} and {% include %} tags', function() { + equal( + '{% set item = passed_var %}' + + '{% include "item.njk" %}\n' + + '{% ' + block + ' i in passed_iter %}' + + '{% set item = i %}' + + '{% include "item.njk" %}\n' + + '{% ' + end + ' %}', + { + passed_var: 'test', + passed_iter: ['1', '2', '3'] + }, + 'showing test\nshowing 1\nshowing 2\nshowing 3\n'); + }); + /* global Set */ + it('should work with Set builtin', function() { + if (typeof Set === 'undefined') { + this.skip(); + } else { + equal('{% ' + block + ' i in set %}{{ i }}{% ' + end + ' %}', + { set: new Set([1, 2, 3, 4, 5]) }, + '12345'); + + equal('{% ' + block + ' i in set %}{{ i }}{% else %}empty{% ' + end + ' %}', + { set: new Set([1, 2, 3, 4, 5]) }, + '12345'); + + equal('{% ' + block + ' i in set %}{{ i }}{% else %}empty{% ' + end + ' %}', + { set: new Set() }, + 'empty'); } - }, - '22'); - - equal('{% ' + block + ' item, v in items %}{% include "item.njk" %}{% ' + end + ' %}', - { - items: { - foo: 1, - bar: 2 + }); + /* global Map */ + it('should work with Map builtin', function() { + if (typeof Map === 'undefined') { + this.skip(); + } else { + equal('{% ' + block + ' k, v in map %}[{{ k }},{{ v }}]{% ' + end + ' %}', + { map: new Map([[1, 2], [3, 4], [5, 6]]) }, + '[1,2][3,4][5,6]'); + + equal('{% ' + block + ' k, v in map %}[{{ k }},{{ v }}]{% else %}empty{% ' + end + ' %}', + { map: new Map([[1, 2], [3, 4], [5, 6]]) }, + '[1,2][3,4][5,6]'); + + equal('{% ' + block + ' k, v in map %}[{{ k }},{{ v }}]{% else %}empty{% ' + end + ' %}', + { map: new Map() }, + 'empty'); } - }, - 'showing fooshowing bar'); - - var res = render( - '{% set item = passed_var %}' + - '{% include "item.njk" %}\n' + - '{% ' + block + ' i in passed_iter %}' + - '{% set item = i %}' + - '{% include "item.njk" %}\n' + - '{% ' + end + ' %}', - { - passed_var: 'test', - passed_iter: ['1', '2', '3'] - } - ); - expect(res).to.be('showing test\nshowing 1\nshowing 2\nshowing 3\n'); + }); + }); } - it('should compile for blocks', function(done) { - runLoopTests('for', 'endfor'); - finish(done); - }); + runLoopTests('for'); + runLoopTests('asyncEach'); + runLoopTests('asyncAll'); it('should allow overriding var with none inside nested scope', function(done) { equal( @@ -439,19 +527,12 @@ finish(done); }); - it('should compile asyncEach', function(done) { - runLoopTests('asyncEach', 'endeach'); - finish(done); - }); - - it('should compile asyncAll', function(done) { - runLoopTests('asyncAll', 'endall'); - finish(done); - }); - it('should compile async control', function(done) { - if (fs) { - var opts = { + var opts; + if (!fs) { + this.skip(); + } else { + opts = { asyncFilters: { getContents: function(tmpl, cb) { fs.readFile(tmpl, cb); @@ -593,13 +674,27 @@ finish(done); }); - it('should compile operators', function(done) { + it('should compile basic arithmetic operators', function() { equal('{{ 3 + 4 - 5 * 6 / 10 }}', '4'); + }); + + it('should compile the exponentiation (**) operator', function() { equal('{{ 4**5 }}', '1024'); + }); + + it('should compile the integer division (//) operator', function() { equal('{{ 9//5 }}', '1'); + }); + + it('should compile the modulus operator', function() { equal('{{ 9%5 }}', '4'); + }); + + it('should compile numeric negation operator', function() { equal('{{ -5 }}', '-5'); + }); + it('should compile comparison operators', function() { equal('{% if 3 < 4 %}yes{% endif %}', 'yes'); equal('{% if 3 > 4 %}yes{% endif %}', ''); equal('{% if 9 >= 10 %}yes{% endif %}', ''); @@ -625,34 +720,39 @@ bar: 15 }, 'yes'); + }); + it('should compile python-style ternary operators', function() { equal('{{ "yes" if 1 is odd else "no" }}', 'yes'); equal('{{ "yes" if 2 is even else "no" }}', 'yes'); equal('{{ "yes" if 2 is odd else "no" }}', 'no'); equal('{{ "yes" if 1 is even else "no" }}', 'no'); + }); + it('should compile the "in" operator for Arrays', function() { equal('{% if 1 in [1, 2] %}yes{% endif %}', 'yes'); equal('{% if 1 in [2, 3] %}yes{% endif %}', ''); equal('{% if 1 not in [1, 2] %}yes{% endif %}', ''); equal('{% if 1 not in [2, 3] %}yes{% endif %}', 'yes'); equal('{% if "a" in vals %}yes{% endif %}', - { - 'vals': ['a', 'b'] - }, 'yes'); + { vals: ['a', 'b'] }, + 'yes'); + }); + + it('should compile the "in" operator for objects', function() { equal('{% if "a" in obj %}yes{% endif %}', - { - 'obj': { - a: true - } - }, 'yes'); + { obj: { a: true } }, + 'yes'); equal('{% if "a" in obj %}yes{% endif %}', - { - 'obj': { - b: true - } - }, ''); + { obj: { b: true } }, + ''); + }); + + it('should compile the "in" operator for strings', function() { equal('{% if "foo" in "foobar" %}yes{% endif %}', 'yes'); + }); + it('should throw an error when using the "in" operator on unexpected types', function(done) { render( '{% if "a" in 1 %}yes{% endif %}', {}, @@ -960,29 +1060,6 @@ finish(done); }); - it('should import template objects', function(done) { - var tmpl = new Template('{% macro foo() %}Inside a macro{% endmacro %}' + - '{% set bar = "BAZ" %}'); - - equal( - '{% import tmpl as imp %}' + - '{{ imp.foo() }} {{ imp.bar }}', - { - tmpl: tmpl - }, - 'Inside a macro BAZ'); - - equal( - '{% from tmpl import foo as baz, bar %}' + - '{{ bar }} {{ baz() }}', - { - tmpl: tmpl - }, - 'BAZ Inside a macro'); - - finish(done); - }); - it('should import templates with context', function(done) { equal( '{% set bar = "BAR" %}' + @@ -1069,20 +1146,17 @@ 'FooBARBAZFizzle'); equal('hola {% extends tmpl %} hizzle mumble', - { - tmpl: 'base.njk' - }, + { tmpl: 'base.njk' }, 'FooBarBazFizzle'); + finish(done); + }); + it('should not call blocks not defined from template inheritance', function(done) { var count = 0; render( '{% extends "base.njk" %}' + '{% block notReal %}{{ foo() }}{% endblock %}', - { - foo: function() { - count++; - } - }, + { foo: function() { count++; } }, function() { expect(count).to.be(0); }); @@ -1090,28 +1164,6 @@ finish(done); }); - it('should inherit template objects', function(done) { - var tmpl = new Template('Foo{% block block1 %}Bar{% endblock %}' + - '{% block block2 %}Baz{% endblock %}Whizzle'); - - equal('hola {% extends tmpl %} fizzle mumble', - { - tmpl: tmpl - }, - 'FooBarBazWhizzle'); - - equal( - '{% extends tmpl %}' + - '{% block block1 %}BAR{% endblock %}' + - '{% block block2 %}BAZ{% endblock %}', - { - tmpl: tmpl - }, - 'FooBARBAZWhizzle'); - - finish(done); - }); - it('should conditionally inherit templates', function(done) { equal( '{% if false %}{% extends "base.njk" %}{% endif %}' + @@ -1294,19 +1346,6 @@ finish(done); }); - it('should include template objects', function(done) { - var tmpl = new Template('FooInclude {{ name }}'); - - equal('hello world {% include tmpl %}', - { - name: 'thedude', - tmpl: tmpl - }, - 'hello world FooInclude thedude'); - - finish(done); - }); - it('should throw an error when including a file that does not exist', function(done) { render( '{% include "missing.njk" %}', @@ -1346,8 +1385,8 @@ equal('{% for k,v in items %}{% include "include-in-loop.njk" %}{% endfor %}', { items: { - 'a': 'A', - 'b': 'B' + a: 'A', + b: 'B' } }, '1,0,true\n2,1,false\n'); @@ -1564,15 +1603,16 @@ }); it('should allow custom tag compilation', function(done) { - function testExtension() { - // jshint validthis: true + function TestExtension() { this.tags = ['test']; this.parse = function(parser, nodes) { + var content; + var tag; parser.advanceAfterBlockEnd(); - var content = parser.parseUntilBlocks('endtest'); - var tag = new nodes.CallExtension(this, 'run', null, [content]); + content = parser.parseUntilBlocks('endtest'); + tag = new nodes.CallExtension(this, 'run', null, [content]); parser.advanceAfterBlockEnd(); return tag; @@ -1584,20 +1624,15 @@ }; } - var opts = { - extensions: { - 'testExtension': new testExtension() - } - }; - render('{% test %}123456789{% endtest %}', null, opts, function(err, res) { - expect(res).to.be('987654321'); - }); + equal('{% test %}123456789{% endtest %}', null, + { extensions: { TestExtension: new TestExtension() } }, + '987654321'); finish(done); }); it('should allow custom tag compilation without content', function(done) { - function testExtension() { + function TestExtension() { // jshint validthis: true this.tags = ['test']; @@ -1615,29 +1650,25 @@ }; } - var opts = { - extensions: { - 'testExtension': new testExtension() - } - }; - render('{% test "123456" %}', null, opts, function(err, res) { - expect(res).to.be('654321'); - }); + equal('{% test "123456" %}', null, + { extensions: { TestExtension: new TestExtension() } }, + '654321'); finish(done); }); it('should allow complicated custom tag compilation', function(done) { - function testExtension() { + function TestExtension() { // jshint validthis: true this.tags = ['test']; /* normally this is automatically done by Environment */ - this._name = 'testExtension'; + this._name = TestExtension; this.parse = function(parser, nodes, lexer) { - var body, - intermediate = null; + var body; + var intermediate = null; + parser.advanceAfterBlockEnd(); body = parser.parseUntilBlocks('intermediate', 'endtest'); @@ -1662,37 +1693,31 @@ }; } - var opts = { - extensions: { - 'testExtension': new testExtension() - } - }; - - render('{% test %}abcdefg{% endtest %}', null, opts, function(err, res) { - expect(res).to.be('a,b,c,d,e,f,g'); - }); + equal('{% test %}abcdefg{% endtest %}', null, + { extensions: { TestExtension: new TestExtension() } }, + 'a,b,c,d,e,f,g'); - render('{% test %}abcdefg{% intermediate %}second half{% endtest %}', + equal('{% test %}abcdefg{% intermediate %}second half{% endtest %}', null, - opts, - function(err, res) { - expect(res).to.be('a,b,c,d,e,f,gflah dnoces'); - }); + { extensions: { TestExtension: new TestExtension() } }, + 'a,b,c,d,e,f,gflah dnoces'); finish(done); }); it('should allow custom tag with args compilation', function(done) { - function testExtension() { + var opts; + + function TestExtension() { // jshint validthis: true this.tags = ['test']; /* normally this is automatically done by Environment */ - this._name = 'testExtension'; + this._name = TestExtension; this.parse = function(parser, nodes) { - var body, - args = null; + var body; + var args; var tok = parser.nextToken(); // passing true makes it tolerate when no args exist @@ -1706,6 +1731,7 @@ }; this.run = function(context, prefix, kwargs, body) { + var output; if (typeof prefix === 'function') { body = prefix; prefix = ''; @@ -1715,7 +1741,7 @@ kwargs = {}; } - var output = prefix + body().split('').reverse().join(''); + output = prefix + body().split('').reverse().join(''); if (kwargs.cutoff) { output = output.slice(0, kwargs.cutoff); } @@ -1724,23 +1750,23 @@ }; } - var opts = { + opts = { extensions: { - 'testExtension': new testExtension() + TestExtension: new TestExtension() } }; - render('{% test %}foobar{% endtest %}', null, opts, function(err, res) { - expect(res).to.be('raboof'); - }); + equal( + '{% test %}foobar{% endtest %}', null, opts, + 'raboof'); - render('{% test("biz") %}foobar{% endtest %}', null, opts, function(err, res) { - expect(res).to.be('bizraboof'); - }); + equal( + '{% test("biz") %}foobar{% endtest %}', null, opts, + 'bizraboof'); - render('{% test("biz", cutoff=5) %}foobar{% endtest %}', null, opts, function(err, res) { - expect(res).to.be('bizra'); - }); + equal( + '{% test("biz", cutoff=5) %}foobar{% endtest %}', null, opts, + 'bizra'); finish(done); }); @@ -1753,105 +1779,73 @@ }); it('should autoescape if autoescape is on', function(done) { - render('{{ foo }}', { - foo: '"\'<>&' - }, { - autoescape: true - }, function(err, res) { - expect(res).to.be('"'<>&'); - }); + equal( + '{{ foo }}', + { foo: '"\'<>&' }, + { autoescape: true }, + '"'<>&'); - render('{{ foo|reverse }}', { - foo: '"\'<>&' - }, { - autoescape: true - }, function(err, res) { - expect(res).to.be('&><'"'); - }); + equal('{{ foo|reverse }}', + { foo: '"\'<>&' }, + { autoescape: true }, + '&><'"'); - render('{{ foo|reverse|safe }}', { - foo: '"\'<>&' - }, { - autoescape: true - }, function(err, res) { - expect(res).to.be('&><\'"'); - }); + equal( + '{{ foo|reverse|safe }}', + { foo: '"\'<>&' }, + { autoescape: true }, + '&><\'"'); - render('{{ foo }}', { - foo: null - }, { - autoescape: true - }, function(err, res) { - expect(res).to.be(''); - }); + equal( + '{{ foo }}', + { foo: null }, + { autoescape: true }, + ''); - render('{{ foo }}', { - foo: ['

    foo

    '] - }, { - autoescape: true - }, function(err, res) { - expect(res).to.be('<p>foo</p>'); - }); + equal( + '{{ foo }}', + { foo: ['

    foo

    '] }, + { autoescape: true }, + '<p>foo</p>'); - render('{{ foo }}', { - foo: { - toString: function() { - return '

    foo

    '; - } - } - }, { - autoescape: true - }, function(err, res) { - expect(res).to.be('<p>foo</p>'); - }); + equal( + '{{ foo }}', + { foo: { toString: function() { return '

    foo

    '; } } }, + { autoescape: true }, + '<p>foo</p>'); - render('{{ foo | safe }}', { - foo: null - }, { - autoescape: true - }, function(err, res) { - expect(res).to.be(''); - }); + equal('{{ foo | safe }}', + { foo: null }, + { autoescape: true }, + ''); - render('{{ foo | safe }}', { - foo: '

    foo

    ' - }, { - autoescape: true - }, function(err, res) { - expect(res).to.be('

    foo

    '); - }); + equal( + '{{ foo | safe }}', + { foo: '

    foo

    ' }, + { autoescape: true }, + '

    foo

    '); - render('{{ foo | safe }}', { - foo: ['

    foo

    '] - }, { - autoescape: true - }, function(err, res) { - expect(res).to.be('

    foo

    '); - }); + equal( + '{{ foo | safe }}', + { foo: ['

    foo

    '] }, + { autoescape: true }, + '

    foo

    '); - render('{{ foo | safe }}', { - foo: { - toString: function() { - return '

    foo

    '; - } - } - }, { - autoescape: true - }, function(err, res) { - expect(res).to.be('

    foo

    '); - }); + equal( + '{{ foo | safe }}', + { foo: { toString: function() { return '

    foo

    '; } } }, + { autoescape: true }, + '

    foo

    '); finish(done); }); it('should not autoescape safe strings', function(done) { - render('{{ foo|safe }}', { - foo: '"\'<>&' - }, { - autoescape: true - }, function(err, res) { - expect(res).to.be('"\'<>&'); - }); + equal( + '{{ foo|safe }}', + { foo: '"\'<>&' }, + { autoescape: true }, + '"\'<>&'); finish(done); }); @@ -1901,7 +1895,7 @@ }); it('should not autoescape when extension set false', function(done) { - function testExtension() { + function TestExtension() { // jshint validthis: true this.tags = ['test']; @@ -1920,17 +1914,13 @@ }; } - var opts = { - extensions: { - 'testExtension': new testExtension() - }, - autoescape: true - }; - render( '{% test "123456" %}', null, - opts, + { + extensions: { TestExtension: new TestExtension() }, + autoescape: true + }, function(err, res) { expect(res).to.be('Foo'); } @@ -1942,13 +1932,10 @@ it('should pass context as this to filters', function(done) { render( '{{ foo | hallo }}', - { - foo: 1, - bar: 2 - }, + { foo: 1, bar: 2 }, { filters: { - 'hallo': function(foo) { + hallo: function(foo) { return foo + this.lookup('bar'); } } @@ -1971,34 +1958,17 @@ finish(done); }); - describe('the filter tag', function() { - - it('should apply the title filter to the body', function(done) { - equal('{% filter title %}may the force be with you{% endfilter %}', - 'May The Force Be With You'); - finish(done); - }); - - it('should apply the replace filter to the body', function(done) { - - equal('{% filter replace("force", "forth") %}may the force be with you{% endfilter %}', - 'may the forth be with you'); - finish(done); - }); - - it('should work with variables in the body', function(done) { - equal('{% set foo = "force" %}{% filter replace("force", "forth") %}may the {{ foo }} be with you{% endfilter %}', - 'may the forth be with you'); - finish(done); - }); + it('should throw an error when {% call %} is passed an object that is not a function', function(done) { + render( + '{% call foo() %}{% endcall %}', + {foo: 'bar'}, + {noThrow: true}, + function(err, res) { + expect(res).to.be(undefined); + expect(err).to.match(/Unable to call `\w+`, which is not a function/); + }); - it('should work with blocks in the body', function(done) { - equal( - '{% extends "filter-block.html" %}' + - '{% block block1 %}force{% endblock %}', - 'may the forth be with you\n'); - finish(done); - }); + finish(done); }); it('should throw an error when including a file that calls an undefined macro', function(done) { @@ -2036,12 +2006,8 @@ it('should throw an error when including a file that imports macro that calls an undefined macro', function(done) { render( '{% include "import-macro-call-undefined-macro.njk" %}', - { - 'list': [1, 2, 3] - }, - { - noThrow: true - }, + { list: [1, 2, 3] }, + { noThrow: true }, function(err, res) { expect(res).to.be(undefined); expect(err).to.match(/Unable to call `\w+`, which is undefined or falsey/); @@ -2055,19 +2021,16 @@ it('should control whitespaces correctly', function(done) { equal( '{% if true -%}{{"hello"}} {{"world"}}{% endif %}', - 'hello world' - ); + 'hello world'); equal( '{% if true -%}{% if true %} {{"hello"}} {{"world"}}' + '{% endif %}{% endif %}', - ' hello world' - ); + ' hello world'); equal( '{% if true -%}{# comment #} {{"hello"}}{% endif %}', - ' hello' - ); + ' hello'); finish(done); }); @@ -2086,18 +2049,6 @@ equal(' {{ 2 + 2 -}} ', ' 4'); - render( - ' {{ 2 + 2- }}', - {}, - { - noThrow: true - }, - function(err, res) { - expect(res).to.be(undefined); - expect(err).to.match(/unexpected token: }}/); - } - ); - finish(done); }); @@ -2174,5 +2125,109 @@ finish(done); }); + + if (!isSlim) { + it('should import template objects', function(done) { + var tmpl = new Template('{% macro foo() %}Inside a macro{% endmacro %}' + + '{% set bar = "BAZ" %}'); + + equal( + '{% import tmpl as imp %}' + + '{{ imp.foo() }} {{ imp.bar }}', + { + tmpl: tmpl + }, + 'Inside a macro BAZ'); + + equal( + '{% from tmpl import foo as baz, bar %}' + + '{{ bar }} {{ baz() }}', + { + tmpl: tmpl + }, + 'BAZ Inside a macro'); + + finish(done); + }); + + it('should inherit template objects', function(done) { + var tmpl = new Template('Foo{% block block1 %}Bar{% endblock %}' + + '{% block block2 %}Baz{% endblock %}Whizzle'); + + equal('hola {% extends tmpl %} fizzle mumble', + { + tmpl: tmpl + }, + 'FooBarBazWhizzle'); + + equal( + '{% extends tmpl %}' + + '{% block block1 %}BAR{% endblock %}' + + '{% block block2 %}BAZ{% endblock %}', + { + tmpl: tmpl + }, + 'FooBARBAZWhizzle'); + + finish(done); + }); + + it('should include template objects', function(done) { + var tmpl = new Template('FooInclude {{ name }}'); + + equal('hello world {% include tmpl %}', + { + name: 'thedude', + tmpl: tmpl + }, + 'hello world FooInclude thedude'); + + finish(done); + }); + + it('should throw an error when invalid expression whitespaces are used', function(done) { + render( + ' {{ 2 + 2- }}', + {}, + { + noThrow: true + }, + function(err, res) { + expect(res).to.be(undefined); + expect(err).to.match(/unexpected token: }}/); + } + ); + + finish(done); + }); + } + }); + + describe('the filter tag', function() { + it('should apply the title filter to the body', function(done) { + equal('{% filter title %}may the force be with you{% endfilter %}', + 'May The Force Be With You'); + finish(done); + }); + + it('should apply the replace filter to the body', function(done) { + equal('{% filter replace("force", "forth") %}may the force be with you{% endfilter %}', + 'may the forth be with you'); + finish(done); + }); + + it('should work with variables in the body', function(done) { + equal('{% set foo = "force" %}{% filter replace("force", "forth") %}may the {{ foo }} be with you{% endfilter %}', + 'may the forth be with you'); + finish(done); + }); + + it('should work with blocks in the body', function(done) { + equal( + '{% extends "filter-block.html" %}' + + '{% block block1 %}force{% endblock %}', + 'may the forth be with you\n'); + finish(done); + }); }); -})(); +}()); diff --git a/tests/express-sample/js/nunjucks-dev.js b/tests/express-sample/js/nunjucks-dev.js deleted file mode 100644 index f940bfc7..00000000 --- a/tests/express-sample/js/nunjucks-dev.js +++ /dev/null @@ -1,4911 +0,0 @@ -(function() { - var modules = {}; - (function() { - - // A simple class system, more documentation to come - - function extend(cls, name, props) { - // This does that same thing as Object.create, but with support for IE8 - var F = function() {}; - F.prototype = cls.prototype; - var prototype = new F(); - - var fnTest = /xyz/.test(function() { - xyz; - }) ? /\bparent\b/ : /.*/; - props = props || {}; - - for (var k in props) { - var src = props[k]; - var parent = prototype[k]; - - if (typeof parent == "function" && - typeof src == "function" && - fnTest.test(src)) { - prototype[k] = (function(src, parent) { - return function() { - // Save the current parent method - var tmp = this.parent; - - // Set parent to the previous method, call, and restore - this.parent = parent; - var res = src.apply(this, arguments); - this.parent = tmp; - - return res; - }; - })(src, parent); - } else { - prototype[k] = src; - } - } - - prototype.typename = name; - - var new_cls = function() { - if (prototype.init) { - prototype.init.apply(this, arguments); - } - }; - - new_cls.prototype = prototype; - new_cls.prototype.constructor = new_cls; - - new_cls.extend = function(name, props) { - if (typeof name == "object") { - props = name; - name = "anonymous"; - } - return extend(new_cls, name, props); - }; - - return new_cls; - } - - modules['object'] = extend(Object, "Object", {}); - })(); - (function() { - var ArrayProto = Array.prototype; - var ObjProto = Object.prototype; - - var escapeMap = { - '&': '&', - '"': '"', - "'": ''', - "<": '<', - ">": '>' - }; - - var lookupEscape = function(ch) { - return escapeMap[ch]; - }; - - var exports = modules['lib'] = {}; - - exports.withPrettyErrors = function(path, withInternals, func) { - try { - return func(); - } catch (e) { - if (!e.Update) { - // not one of ours, cast it - e = new exports.TemplateError(e); - } - e.Update(path); - - // Unless they marked the dev flag, show them a trace from here - if (!withInternals) { - var old = e; - e = new Error(old.message); - e.name = old.name; - } - - throw e; - } - }; - - exports.TemplateError = function(message, lineno, colno) { - var err = this; - - if (message instanceof Error) { // for casting regular js errors - err = message; - message = message.name + ": " + message.message; - } else { - if (Error.captureStackTrace) { - Error.captureStackTrace(err); - } - } - - err.name = 'Template render error'; - err.message = message; - err.lineno = lineno; - err.colno = colno; - err.firstUpdate = true; - - err.Update = function(path) { - var message = "(" + (path || "unknown path") + ")"; - - // only show lineno + colno next to path of template - // where error occurred - if (this.firstUpdate) { - if (this.lineno && this.colno) { - message += ' [Line ' + this.lineno + ', Column ' + this.colno + ']'; - } else if (this.lineno) { - message += ' [Line ' + this.lineno + ']'; - } - } - - message += '\n '; - if (this.firstUpdate) { - message += ' '; - } - - this.message = message + (this.message || ''); - this.firstUpdate = false; - return this; - }; - - return err; - }; - - exports.TemplateError.prototype = Error.prototype; - - exports.escape = function(val) { - return val.replace(/[&"'<>]/g, lookupEscape); - }; - - exports.isFunction = function(obj) { - return ObjProto.toString.call(obj) == '[object Function]'; - }; - - exports.isArray = Array.isArray || function(obj) { - return ObjProto.toString.call(obj) == '[object Array]'; - }; - - exports.isString = function(obj) { - return ObjProto.toString.call(obj) == '[object String]'; - }; - - exports.isObject = function(obj) { - return obj === Object(obj); - }; - - exports.groupBy = function(obj, val) { - var result = {}; - var iterator = exports.isFunction(val) ? val : function(obj) { - return obj[val]; - }; - for (var i = 0; i < obj.length; i++) { - var value = obj[i]; - var key = iterator(value, i); - (result[key] || (result[key] = [])).push(value); - } - return result; - }; - - exports.toArray = function(obj) { - return Array.prototype.slice.call(obj); - }; - - exports.without = function(array) { - var result = []; - if (!array) { - return result; - } - var index = -1, - length = array.length, - contains = exports.toArray(arguments).slice(1); - - while (++index < length) { - if (contains.indexOf(array[index]) === -1) { - result.push(array[index]); - } - } - return result; - }; - - exports.extend = function(obj, obj2) { - for (var k in obj2) { - obj[k] = obj2[k]; - } - return obj; - }; - - exports.repeat = function(char_, n) { - var str = ''; - for (var i = 0; i < n; i++) { - str += char_; - } - return str; - }; - - exports.each = function(obj, func, context) { - if (obj == null) { - return; - } - - if (ArrayProto.each && obj.each == ArrayProto.each) { - obj.forEach(func, context); - } else if (obj.length === +obj.length) { - for (var i = 0, l = obj.length; i < l; i++) { - func.call(context, obj[i], i, obj); - } - } - }; - - exports.map = function(obj, func) { - var results = []; - if (obj == null) { - return results; - } - - if (ArrayProto.map && obj.map === ArrayProto.map) { - return obj.map(func); - } - - for (var i = 0; i < obj.length; i++) { - results[results.length] = func(obj[i], i); - } - - if (obj.length === +obj.length) { - results.length = obj.length; - } - - return results; - }; - - exports.asyncParallel = function(funcs, done) { - var count = funcs.length, - result = new Array(count), - current = 0; - - var makeNext = function(i) { - return function(res) { - result[i] = res; - current += 1; - - if (current === count) { - done(result); - } - }; - }; - - for (var i = 0; i < count; i++) { - funcs[i](makeNext(i)); - } - }; - - exports.asyncIter = function(arr, iter, cb) { - var i = -1; - - function next() { - i++; - - if (i < arr.length) { - iter(arr[i], i, next, cb); - } else { - cb(); - } - } - - next(); - }; - - exports.asyncFor = function(obj, iter, cb) { - var keys = exports.keys(obj); - var len = keys.length; - var i = -1; - - function next() { - i++; - var k = keys[i]; - - if (i < len) { - iter(k, obj[k], i, len, next); - } else { - cb(); - } - } - - next(); - }; - - if (!Array.prototype.indexOf) { - Array.prototype.indexOf = function(array, searchElement /*, fromIndex */ ) { - if (array == null) { - throw new TypeError(); - } - var t = Object(array); - var len = t.length >>> 0; - if (len === 0) { - return -1; - } - var n = 0; - if (arguments.length > 2) { - n = Number(arguments[2]); - if (n != n) { // shortcut for verifying if it's NaN - n = 0; - } else if (n != 0 && n != Infinity && n != -Infinity) { - n = (n > 0 || -1) * Math.floor(Math.abs(n)); - } - } - if (n >= len) { - return -1; - } - var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); - for (; k < len; k++) { - if (k in t && t[k] === searchElement) { - return k; - } - } - return -1; - }; - } - - if (!Array.prototype.map) { - Array.prototype.map = function() { - throw new Error("map is unimplemented for this js engine"); - }; - } - - exports.keys = function(obj) { - if (Object.prototype.keys) { - return obj.keys(); - } else { - var keys = []; - for (var k in obj) { - if (obj.hasOwnProperty(k)) { - keys.push(k); - } - } - return keys; - } - } - })(); - (function() { - var util = modules["util"]; - var lib = modules["lib"]; - var Object = modules["object"]; - - function traverseAndCheck(obj, type, results) { - if (obj instanceof type) { - results.push(obj); - } - - if (obj instanceof Node) { - obj.findAll(type, results); - } - } - - var Node = Object.extend("Node", { - init: function(lineno, colno) { - this.lineno = lineno; - this.colno = colno; - - var fields = this.fields; - for (var i = 0, l = fields.length; i < l; i++) { - var field = fields[i]; - - // The first two args are line/col numbers, so offset by 2 - var val = arguments[i + 2]; - - // Fields should never be undefined, but null. It makes - // testing easier to normalize values. - if (val === undefined) { - val = null; - } - - this[field] = val; - } - }, - - findAll: function(type, results) { - results = results || []; - - if (this instanceof NodeList) { - var children = this.children; - - for (var i = 0, l = children.length; i < l; i++) { - traverseAndCheck(children[i], type, results); - } - } else { - var fields = this.fields; - - for (var i = 0, l = fields.length; i < l; i++) { - traverseAndCheck(this[fields[i]], type, results); - } - } - - return results; - }, - - iterFields: function(func) { - lib.each(this.fields, function(field) { - func(this[field], field); - }, this); - } - }); - - // Abstract nodes - var Value = Node.extend("Value", { - fields: ['value'] - }); - - // Concrete nodes - var NodeList = Node.extend("NodeList", { - fields: ['children'], - - init: function(lineno, colno, nodes) { - this.parent(lineno, colno, nodes || []); - }, - - addChild: function(node) { - this.children.push(node); - } - }); - - var Root = NodeList.extend("Root"); - var Literal = Value.extend("Literal"); - var Symbol = Value.extend("Symbol"); - var Group = NodeList.extend("Group"); - var Array = NodeList.extend("Array"); - var Pair = Node.extend("Pair", { - fields: ['key', 'value'] - }); - var Dict = NodeList.extend("Dict"); - var LookupVal = Node.extend("LookupVal", { - fields: ['target', 'val'] - }); - var If = Node.extend("If", { - fields: ['cond', 'body', 'else_'] - }); - var IfAsync = If.extend("IfAsync"); - var InlineIf = Node.extend("InlineIf", { - fields: ['cond', 'body', 'else_'] - }); - var For = Node.extend("For", { - fields: ['arr', 'name', 'body'] - }); - var AsyncEach = For.extend("AsyncEach"); - var AsyncAll = For.extend("AsyncAll"); - var Macro = Node.extend("Macro", { - fields: ['name', 'args', 'body'] - }); - var Import = Node.extend("Import", { - fields: ['template', 'target'] - }); - var FromImport = Node.extend("FromImport", { - fields: ['template', 'names'], - - init: function(lineno, colno, template, names) { - this.parent(lineno, colno, - template, - names || new NodeList()); - } - }); - var FunCall = Node.extend("FunCall", { - fields: ['name', 'args'] - }); - var Filter = FunCall.extend("Filter"); - var FilterAsync = Filter.extend("FilterAsync", { - fields: ['name', 'args', 'symbol'] - }); - var KeywordArgs = Dict.extend("KeywordArgs"); - var Block = Node.extend("Block", { - fields: ['name', 'body'] - }); - var Super = Node.extend("Super", { - fields: ['blockName', 'symbol'] - }); - var TemplateRef = Node.extend("TemplateRef", { - fields: ['template'] - }); - var Extends = TemplateRef.extend("Extends"); - var Include = TemplateRef.extend("Include"); - var Set = Node.extend("Set", { - fields: ['targets', 'value'] - }); - var Output = NodeList.extend("Output"); - var TemplateData = Literal.extend("TemplateData"); - var UnaryOp = Node.extend("UnaryOp", { - fields: ['target'] - }); - var BinOp = Node.extend("BinOp", { - fields: ['left', 'right'] - }); - var Or = BinOp.extend("Or"); - var And = BinOp.extend("And"); - var Not = UnaryOp.extend("Not"); - var Add = BinOp.extend("Add"); - var Sub = BinOp.extend("Sub"); - var Mul = BinOp.extend("Mul"); - var Div = BinOp.extend("Div"); - var FloorDiv = BinOp.extend("FloorDiv"); - var Mod = BinOp.extend("Mod"); - var Pow = BinOp.extend("Pow"); - var Neg = UnaryOp.extend("Neg"); - var Pos = UnaryOp.extend("Pos"); - var Compare = Node.extend("Compare", { - fields: ['expr', 'ops'] - }); - var CompareOperand = Node.extend("CompareOperand", { - fields: ['expr', 'type'] - }); - - var CustomTag = Node.extend("CustomTag", { - init: function(lineno, colno, name) { - this.lineno = lineno; - this.colno = colno; - this.name = name; - } - }); - - var CallExtension = Node.extend("CallExtension", { - fields: ['extName', 'prop', 'args', 'contentArgs'], - - init: function(ext, prop, args, contentArgs) { - this.extName = ext._name || ext; - this.prop = prop; - this.args = args || new NodeList(); - this.contentArgs = contentArgs || []; - } - }); - - var CallExtensionAsync = CallExtension.extend("CallExtensionAsync"); - - // Print the AST in a nicely formatted tree format for debuggin - function printNodes(node, indent) { - indent = indent || 0; - - // This is hacky, but this is just a debugging function anyway - function print(str, indent, inline) { - var lines = str.split("\n"); - - for (var i = 0; i < lines.length; i++) { - if (lines[i]) { - if ((inline && i > 0) || !inline) { - for (var j = 0; j < indent; j++) { - util.print(" "); - } - } - } - - if (i === lines.length - 1) { - util.print(lines[i]); - } else { - util.puts(lines[i]); - } - } - } - - print(node.typename + ": ", indent); - - if (node instanceof NodeList) { - print('\n'); - lib.each(node.children, function(n) { - printNodes(n, indent + 2); - }); - } else if (node instanceof CallExtension) { - print(node.extName + '.' + node.prop); - print('\n'); - - if (node.args) { - printNodes(node.args, indent + 2); - } - - if (node.contentArgs) { - lib.each(node.contentArgs, function(n) { - printNodes(n, indent + 2); - }); - } - } else { - var nodes = null; - var props = null; - - node.iterFields(function(val, field) { - if (val instanceof Node) { - nodes = nodes || {}; - nodes[field] = val; - } else { - props = props || {}; - props[field] = val; - } - }); - - if (props) { - print(util.inspect(props, true, null) + '\n', null, true); - } else { - print('\n'); - } - - if (nodes) { - for (var k in nodes) { - printNodes(nodes[k], indent + 2); - } - } - - } - } - - // var t = new NodeList(0, 0, - // [new Value(0, 0, 3), - // new Value(0, 0, 10), - // new Pair(0, 0, - // new Value(0, 0, 'key'), - // new Value(0, 0, 'value'))]); - // printNodes(t); - - modules['nodes'] = { - Node: Node, - Root: Root, - NodeList: NodeList, - Value: Value, - Literal: Literal, - Symbol: Symbol, - Group: Group, - Array: Array, - Pair: Pair, - Dict: Dict, - Output: Output, - TemplateData: TemplateData, - If: If, - IfAsync: IfAsync, - InlineIf: InlineIf, - For: For, - AsyncEach: AsyncEach, - AsyncAll: AsyncAll, - Macro: Macro, - Import: Import, - FromImport: FromImport, - FunCall: FunCall, - Filter: Filter, - FilterAsync: FilterAsync, - KeywordArgs: KeywordArgs, - Block: Block, - Super: Super, - Extends: Extends, - Include: Include, - Set: Set, - LookupVal: LookupVal, - BinOp: BinOp, - Or: Or, - And: And, - Not: Not, - Add: Add, - Sub: Sub, - Mul: Mul, - Div: Div, - FloorDiv: FloorDiv, - Mod: Mod, - Pow: Pow, - Neg: Neg, - Pos: Pos, - Compare: Compare, - CompareOperand: CompareOperand, - - CallExtension: CallExtension, - CallExtensionAsync: CallExtensionAsync, - - printNodes: printNodes - }; - })(); - (function() { - - var lib = modules["lib"]; - var Object = modules["object"]; - - // Frames keep track of scoping both at compile-time and run-time so - // we know how to access variables. Block tags can introduce special - // variables, for example. - var Frame = Object.extend({ - init: function(parent) { - this.variables = {}; - this.parent = parent; - }, - - set: function(name, val) { - // Allow variables with dots by automatically creating the - // nested structure - var parts = name.split('.'); - var obj = this.variables; - - for (var i = 0; i < parts.length - 1; i++) { - var id = parts[i]; - - if (!obj[id]) { - obj[id] = {}; - } - obj = obj[id]; - } - - obj[parts[parts.length - 1]] = val; - }, - - get: function(name) { - var val = this.variables[name]; - if (val !== undefined && val !== null) { - return val; - } - return null; - }, - - lookup: function(name) { - var p = this.parent; - var val = this.variables[name]; - if (val !== undefined && val !== null) { - return val; - } - return p && p.lookup(name); - }, - - push: function() { - return new Frame(this); - }, - - pop: function() { - return this.parent; - } - }); - - function makeMacro(argNames, kwargNames, func) { - return function() { - var argCount = numArgs(arguments); - var args; - var kwargs = getKeywordArgs(arguments); - - if (argCount > argNames.length) { - args = Array.prototype.slice.call(arguments, 0, argNames.length); - - // Positional arguments that should be passed in as - // keyword arguments (essentially default values) - var vals = Array.prototype.slice.call(arguments, args.length, argCount); - for (var i = 0; i < vals.length; i++) { - if (i < kwargNames.length) { - kwargs[kwargNames[i]] = vals[i]; - } - } - - args.push(kwargs); - } else if (argCount < argNames.length) { - args = Array.prototype.slice.call(arguments, 0, argCount); - - for (var i = argCount; i < argNames.length; i++) { - var arg = argNames[i]; - - // Keyword arguments that should be passed as - // positional arguments, i.e. the caller explicitly - // used the name of a positional arg - args.push(kwargs[arg]); - delete kwargs[arg]; - } - - args.push(kwargs); - } else { - args = arguments; - } - - return func.apply(this, args); - }; - } - - function makeKeywordArgs(obj) { - obj.__keywords = true; - return obj; - } - - function getKeywordArgs(args) { - var len = args.length; - if (len) { - var lastArg = args[len - 1]; - if (lastArg && lastArg.hasOwnProperty('__keywords')) { - return lastArg; - } - } - return {}; - } - - function numArgs(args) { - var len = args.length; - if (len === 0) { - return 0; - } - - var lastArg = args[len - 1]; - if (lastArg && lastArg.hasOwnProperty('__keywords')) { - return len - 1; - } else { - return len; - } - } - - // A SafeString object indicates that the string should not be - // autoescaped. This happens magically because autoescaping only - // occurs on primitive string objects. - function SafeString(val) { - if (typeof val != 'string') { - return val; - } - - this.toString = function() { - return val; - }; - - this.length = val.length; - - var methods = [ - 'charAt', 'charCodeAt', 'concat', 'contains', - 'endsWith', 'fromCharCode', 'indexOf', 'lastIndexOf', - 'length', 'localeCompare', 'match', 'quote', 'replace', - 'search', 'slice', 'split', 'startsWith', 'substr', - 'substring', 'toLocaleLowerCase', 'toLocaleUpperCase', - 'toLowerCase', 'toUpperCase', 'trim', 'trimLeft', 'trimRight' - ]; - - for (var i = 0; i < methods.length; i++) { - this[methods[i]] = markSafe(val[methods[i]]); - } - } - - function copySafeness(dest, target) { - if (dest instanceof SafeString) { - return new SafeString(target); - } - return target.toString(); - } - - function markSafe(val) { - var type = typeof val; - - if (type === 'string') { - return new SafeString(val); - } else if (type !== 'function') { - return val; - } else { - return function() { - var ret = val.apply(this, arguments); - - if (typeof ret === 'string') { - return new SafeString(ret); - } - - return ret; - }; - } - } - - function suppressValue(val, autoescape) { - val = (val !== undefined && val !== null) ? val : ""; - - if (autoescape && typeof val === "string") { - val = lib.escape(val); - } - - return val; - } - - function memberLookup(obj, val) { - obj = obj || {}; - - if (typeof obj[val] === 'function') { - return function() { - return obj[val].apply(obj, arguments); - }; - } - - return obj[val]; - } - - function callWrap(obj, name, args) { - if (!obj) { - throw new Error('Unable to call `' + name + '`, which is undefined or falsey'); - } else if (typeof obj !== 'function') { - throw new Error('Unable to call `' + name + '`, which is not a function'); - } - - return obj.apply(this, args); - } - - function contextOrFrameLookup(context, frame, name) { - var val = frame.lookup(name); - return (val !== undefined && val !== null) ? - val : - context.lookup(name); - } - - function handleError(error, lineno, colno) { - if (error.lineno) { - return error; - } else { - return new lib.TemplateError(error, lineno, colno); - } - } - - function asyncEach(arr, dimen, iter, cb) { - if (lib.isArray(arr)) { - var len = arr.length; - - lib.asyncIter(arr, function(item, i, next) { - switch (dimen) { - case 1: - iter(item, i, len, next); - break; - case 2: - iter(item[0], item[1], i, len, next); - break; - case 3: - iter(item[0], item[1], item[2], i, len, next); - break; - default: - item.push(i, next); - iter.apply(this, item); - } - }, cb); - } else { - lib.asyncFor(arr, function(key, val, i, len, next) { - iter(key, val, i, len, next); - }, cb); - } - } - - function asyncAll(arr, dimen, func, cb) { - var finished = 0; - var len; - var outputArr; - - function done(i, output) { - finished++; - outputArr[i] = output; - - if (finished == len) { - cb(null, outputArr.join('')); - } - } - - if (lib.isArray(arr)) { - len = arr.length; - outputArr = new Array(len); - - if (len == 0) { - cb(null, ''); - } else { - for (var i = 0; i < arr.length; i++) { - var item = arr[i]; - - switch (dimen) { - case 1: - func(item, i, len, done); - break; - case 2: - func(item[0], item[1], i, len, done); - break; - case 3: - func(item[0], item[1], item[2], i, len, done); - break; - default: - item.push(i, done); - func.apply(this, item); - } - } - } - } else { - var keys = lib.keys(arr); - len = keys.length; - outputArr = new Array(len); - - if (len == 0) { - cb(null, ''); - } else { - for (var i = 0; i < keys.length; i++) { - var k = keys[i]; - func(k, arr[k], i, len, done); - } - } - } - } - - modules['runtime'] = { - Frame: Frame, - makeMacro: makeMacro, - makeKeywordArgs: makeKeywordArgs, - numArgs: numArgs, - suppressValue: suppressValue, - memberLookup: memberLookup, - contextOrFrameLookup: contextOrFrameLookup, - callWrap: callWrap, - handleError: handleError, - isArray: lib.isArray, - asyncEach: lib.asyncEach, - keys: lib.keys, - SafeString: SafeString, - copySafeness: copySafeness, - markSafe: markSafe, - asyncEach: asyncEach, - asyncAll: asyncAll - }; - })(); - (function() { - var lib = modules["lib"]; - - var whitespaceChars = " \n\t\r"; - var delimChars = "()[]{}%*-+/#,:|.<>=!"; - var intChars = "0123456789"; - - var BLOCK_START = "{%"; - var BLOCK_END = "%}"; - var VARIABLE_START = "{{"; - var VARIABLE_END = "}}"; - var COMMENT_START = "{#"; - var COMMENT_END = "#}"; - - var TOKEN_STRING = "string"; - var TOKEN_WHITESPACE = "whitespace"; - var TOKEN_DATA = "data"; - var TOKEN_BLOCK_START = "block-start"; - var TOKEN_BLOCK_END = "block-end"; - var TOKEN_VARIABLE_START = "variable-start"; - var TOKEN_VARIABLE_END = "variable-end"; - var TOKEN_COMMENT = "comment"; - var TOKEN_LEFT_PAREN = "left-paren"; - var TOKEN_RIGHT_PAREN = "right-paren"; - var TOKEN_LEFT_BRACKET = "left-bracket"; - var TOKEN_RIGHT_BRACKET = "right-bracket"; - var TOKEN_LEFT_CURLY = "left-curly"; - var TOKEN_RIGHT_CURLY = "right-curly"; - var TOKEN_OPERATOR = "operator"; - var TOKEN_COMMA = "comma"; - var TOKEN_COLON = "colon"; - var TOKEN_PIPE = "pipe"; - var TOKEN_INT = "int"; - var TOKEN_FLOAT = "float"; - var TOKEN_BOOLEAN = "boolean"; - var TOKEN_SYMBOL = "symbol"; - var TOKEN_SPECIAL = "special"; - - function token(type, value, lineno, colno) { - return { - type: type, - value: value, - lineno: lineno, - colno: colno - }; - } - - function Tokenizer(str) { - this.str = str; - this.index = 0; - this.len = str.length; - this.lineno = 0; - this.colno = 0; - - this.in_code = false; - } - - Tokenizer.prototype.nextToken = function() { - var lineno = this.lineno; - var colno = this.colno; - - if (this.in_code) { - // Otherwise, if we are in a block parse it as code - var cur = this.current(); - var tok; - - if (this.is_finished()) { - // We have nothing else to parse - return null; - } else if (cur == "\"" || cur == "'") { - // We've hit a string - return token(TOKEN_STRING, this.parseString(cur), lineno, colno); - } else if( (tok = this._extract(whitespaceChars)) ) { - // We hit some whitespace - return token(TOKEN_WHITESPACE, tok, lineno, colno); - } else if ((tok = this._extractString(BLOCK_END)) || - (tok = this._extractString('-' + BLOCK_END))) { - // Special check for the block end tag - // - // It is a requirement that start and end tags are composed of - // delimiter characters (%{}[] etc), and our code always - // breaks on delimiters so we can assume the token parsing - // doesn't consume these elsewhere - this.in_code = false; - return token(TOKEN_BLOCK_END, tok, lineno, colno); - } else if( (tok = this._extractString(VARIABLE_END)) ) { - // Special check for variable end tag (see above) - this.in_code = false; - return token(TOKEN_VARIABLE_END, tok, lineno, colno); - } else if (delimChars.indexOf(cur) != -1) { - // We've hit a delimiter (a special char like a bracket) - this.forward(); - var complexOps = ['==', '!=', '<=', '>=', '//', '**']; - var curComplex = cur + this.current(); - var type; - - if (complexOps.indexOf(curComplex) !== -1) { - this.forward(); - cur = curComplex; - } - - switch (cur) { - case "(": - type = TOKEN_LEFT_PAREN; - break; - case ")": - type = TOKEN_RIGHT_PAREN; - break; - case "[": - type = TOKEN_LEFT_BRACKET; - break; - case "]": - type = TOKEN_RIGHT_BRACKET; - break; - case "{": - type = TOKEN_LEFT_CURLY; - break; - case "}": - type = TOKEN_RIGHT_CURLY; - break; - case ",": - type = TOKEN_COMMA; - break; - case ":": - type = TOKEN_COLON; - break; - case "|": - type = TOKEN_PIPE; - break; - default: - type = TOKEN_OPERATOR; - } - - return token(type, cur, lineno, colno); - } else { - // We are not at whitespace or a delimiter, so extract the - // text and parse it - tok = this._extractUntil(whitespaceChars + delimChars); - - if (tok.match(/^[-+]?[0-9]+$/)) { - if (this.current() == '.') { - this.forward(); - var dec = this._extract(intChars); - return token(TOKEN_FLOAT, tok + '.' + dec, lineno, colno); - } else { - return token(TOKEN_INT, tok, lineno, colno); - } - } else if (tok.match(/^(true|false)$/)) { - return token(TOKEN_BOOLEAN, tok, lineno, colno); - } else if (tok) { - return token(TOKEN_SYMBOL, tok, lineno, colno); - } else { - throw new Error("Unexpected value while parsing: " + tok); - } - } - } else { - // Parse out the template text, breaking on tag - // delimiters because we need to look for block/variable start - // tags (don't use the full delimChars for optimization) - var beginChars = (BLOCK_START.charAt(0) + - VARIABLE_START.charAt(0) + - COMMENT_START.charAt(0) + - COMMENT_END.charAt(0)); - var tok; - - if (this.is_finished()) { - return null; - } else if ((tok = this._extractString(BLOCK_START + '-')) || - (tok = this._extractString(BLOCK_START))) { - this.in_code = true; - return token(TOKEN_BLOCK_START, tok, lineno, colno); - } else if( (tok = this._extractString(VARIABLE_START)) ) { - this.in_code = true; - return token(TOKEN_VARIABLE_START, tok, lineno, colno); - } else { - tok = ''; - var data; - var in_comment = false; - - if (this._matches(COMMENT_START)) { - in_comment = true; - tok = this._extractString(COMMENT_START); - } - - // Continually consume text, breaking on the tag delimiter - // characters and checking to see if it's a start tag. - // - // We could hit the end of the template in the middle of - // our looping, so check for the null return value from - // _extractUntil - while ((data = this._extractUntil(beginChars)) !== null) { - tok += data; - - if ((this._matches(BLOCK_START) || - this._matches(VARIABLE_START) || - this._matches(COMMENT_START)) && - !in_comment) { - // If it is a start tag, stop looping - break; - } else if (this._matches(COMMENT_END)) { - if (!in_comment) { - throw new Error("unexpected end of comment"); - } - tok += this._extractString(COMMENT_END); - break; - } else { - // It does not match any tag, so add the character and - // carry on - tok += this.current(); - this.forward(); - } - } - - if (data === null && in_comment) { - throw new Error("expected end of comment, got end of file"); - } - - return token(in_comment ? TOKEN_COMMENT : TOKEN_DATA, - tok, - lineno, - colno); - } - } - - throw new Error("Could not parse text"); - }; - - Tokenizer.prototype.parseString = function(delimiter) { - this.forward(); - - var lineno = this.lineno; - var colno = this.colno; - var str = ""; - - while (!this.is_finished() && this.current() != delimiter) { - var cur = this.current(); - - if (cur == "\\") { - this.forward(); - switch (this.current()) { - case "n": - str += "\n"; - break; - case "t": - str += "\t"; - break; - case "r": - str += "\r"; - break; - default: - str += this.current(); - } - this.forward(); - } else { - str += cur; - this.forward(); - } - } - - this.forward(); - return str; - }; - - Tokenizer.prototype._matches = function(str) { - if (this.index + str.length > this.length) { - return null; - } - - var m = this.str.slice(this.index, this.index + str.length); - return m == str; - }; - - Tokenizer.prototype._extractString = function(str) { - if (this._matches(str)) { - this.index += str.length; - return str; - } - return null; - }; - - Tokenizer.prototype._extractUntil = function(charString) { - // Extract all non-matching chars, with the default matching set - // to everything - return this._extractMatching(true, charString || ""); - }; - - Tokenizer.prototype._extract = function(charString) { - // Extract all matching chars (no default, so charString must be - // explicit) - return this._extractMatching(false, charString); - }; - - Tokenizer.prototype._extractMatching = function(breakOnMatch, charString) { - // Pull out characters until a breaking char is hit. - // If breakOnMatch is false, a non-matching char stops it. - // If breakOnMatch is true, a matching char stops it. - - if (this.is_finished()) { - return null; - } - - var first = charString.indexOf(this.current()); - - // Only proceed if the first character doesn't meet our condition - if ((breakOnMatch && first == -1) || - (!breakOnMatch && first != -1)) { - var t = this.current(); - this.forward(); - - // And pull out all the chars one at a time until we hit a - // breaking char - var idx = charString.indexOf(this.current()); - - while (((breakOnMatch && idx == -1) || - (!breakOnMatch && idx != -1)) && !this.is_finished()) { - t += this.current(); - this.forward(); - - idx = charString.indexOf(this.current()); - } - - return t; - } - - return ""; - }; - - Tokenizer.prototype.is_finished = function() { - return this.index >= this.len; - }; - - Tokenizer.prototype.forwardN = function(n) { - for (var i = 0; i < n; i++) { - this.forward(); - } - }; - - Tokenizer.prototype.forward = function() { - this.index++; - - if (this.previous() == "\n") { - this.lineno++; - this.colno = 0; - } else { - this.colno++; - } - }; - - Tokenizer.prototype.backN = function(n) { - for (var i = 0; i < n; i++) { - self.back(); - } - }; - - Tokenizer.prototype.back = function() { - this.index--; - - if (this.current() == "\n") { - this.lineno--; - - var idx = this.src.lastIndexOf("\n", this.index - 1); - if (idx == -1) { - this.colno = this.index; - } else { - this.colno = this.index - idx; - } - } else { - this.colno--; - } - }; - - Tokenizer.prototype.current = function() { - if (!this.is_finished()) { - return this.str.charAt(this.index); - } - return ""; - }; - - Tokenizer.prototype.previous = function() { - return this.str.charAt(this.index - 1); - }; - - modules['lexer'] = { - lex: function(src) { - return new Tokenizer(src); - }, - - setTags: function(tags) { - BLOCK_START = tags.blockStart || BLOCK_START; - BLOCK_END = tags.blockEnd || BLOCK_END; - VARIABLE_START = tags.variableStart || VARIABLE_START; - VARIABLE_END = tags.variableEnd || VARIABLE_END; - COMMENT_START = tags.commentStart || COMMENT_START; - COMMENT_END = tags.commentEnd || COMMENT_END; - }, - - TOKEN_STRING: TOKEN_STRING, - TOKEN_WHITESPACE: TOKEN_WHITESPACE, - TOKEN_DATA: TOKEN_DATA, - TOKEN_BLOCK_START: TOKEN_BLOCK_START, - TOKEN_BLOCK_END: TOKEN_BLOCK_END, - TOKEN_VARIABLE_START: TOKEN_VARIABLE_START, - TOKEN_VARIABLE_END: TOKEN_VARIABLE_END, - TOKEN_COMMENT: TOKEN_COMMENT, - TOKEN_LEFT_PAREN: TOKEN_LEFT_PAREN, - TOKEN_RIGHT_PAREN: TOKEN_RIGHT_PAREN, - TOKEN_LEFT_BRACKET: TOKEN_LEFT_BRACKET, - TOKEN_RIGHT_BRACKET: TOKEN_RIGHT_BRACKET, - TOKEN_LEFT_CURLY: TOKEN_LEFT_CURLY, - TOKEN_RIGHT_CURLY: TOKEN_RIGHT_CURLY, - TOKEN_OPERATOR: TOKEN_OPERATOR, - TOKEN_COMMA: TOKEN_COMMA, - TOKEN_COLON: TOKEN_COLON, - TOKEN_PIPE: TOKEN_PIPE, - TOKEN_INT: TOKEN_INT, - TOKEN_FLOAT: TOKEN_FLOAT, - TOKEN_BOOLEAN: TOKEN_BOOLEAN, - TOKEN_SYMBOL: TOKEN_SYMBOL, - TOKEN_SPECIAL: TOKEN_SPECIAL - }; - })(); - (function() { - var lexer = modules["lexer"]; - var nodes = modules["nodes"]; - var Object = modules["object"]; - var lib = modules["lib"]; - - var Parser = Object.extend({ - init: function(tokens) { - this.tokens = tokens; - this.peeked = null; - this.breakOnBlocks = null; - this.dropLeadingWhitespace = false; - - this.extensions = []; - }, - - nextToken: function(withWhitespace) { - var tok; - - if (this.peeked) { - if (!withWhitespace && this.peeked.type == lexer.TOKEN_WHITESPACE) { - this.peeked = null; - } else { - tok = this.peeked; - this.peeked = null; - return tok; - } - } - - tok = this.tokens.nextToken(); - - if (!withWhitespace) { - while (tok && tok.type == lexer.TOKEN_WHITESPACE) { - tok = this.tokens.nextToken(); - } - } - - return tok; - }, - - peekToken: function() { - this.peeked = this.peeked || this.nextToken(); - return this.peeked; - }, - - pushToken: function(tok) { - if (this.peeked) { - throw new Error("pushToken: can only push one token on between reads"); - } - this.peeked = tok; - }, - - fail: function(msg, lineno, colno) { - if ((lineno === undefined || colno === undefined) && this.peekToken()) { - var tok = this.peekToken(); - lineno = tok.lineno; - colno = tok.colno; - } - if (lineno !== undefined) { - lineno += 1; - } - if (colno !== undefined) { - colno += 1; - } - - throw new lib.TemplateError(msg, lineno, colno); - }, - - skip: function(type) { - var tok = this.nextToken(); - if (!tok || tok.type != type) { - this.pushToken(tok); - return false; - } - return true; - }, - - expect: function(type) { - var tok = this.nextToken(); - if (!tok.type == type) { - this.fail('expected ' + type + ', got ' + tok.type, - tok.lineno, - tok.colno); - } - return tok; - }, - - skipValue: function(type, val) { - var tok = this.nextToken(); - if (!tok || tok.type != type || tok.value != val) { - this.pushToken(tok); - return false; - } - return true; - }, - - skipWhitespace: function() { - return this.skip(lexer.TOKEN_WHITESPACE); - }, - - skipSymbol: function(val) { - return this.skipValue(lexer.TOKEN_SYMBOL, val); - }, - - advanceAfterBlockEnd: function(name) { - if (!name) { - var tok = this.peekToken(); - - if (!tok) { - this.fail('unexpected end of file'); - } - - if (tok.type != lexer.TOKEN_SYMBOL) { - this.fail("advanceAfterBlockEnd: expected symbol token or " + - "explicit name to be passed"); - } - - name = this.nextToken().value; - } - - var tok = this.nextToken(); - - if (tok && tok.type == lexer.TOKEN_BLOCK_END) { - if (tok.value.charAt(0) === '-') { - this.dropLeadingWhitespace = true; - } - } else { - this.fail("expected block end in " + name + " statement"); - } - }, - - advanceAfterVariableEnd: function() { - if (!this.skip(lexer.TOKEN_VARIABLE_END)) { - this.fail("expected variable end"); - } - }, - - parseFor: function() { - var forTok = this.peekToken(); - var node; - var endBlock; - - if (this.skipSymbol('for')) { - node = new nodes.For(forTok.lineno, forTok.colno); - endBlock = 'endfor'; - } else if (this.skipSymbol('asyncEach')) { - node = new nodes.AsyncEach(forTok.lineno, forTok.colno); - endBlock = 'endeach'; - } else if (this.skipSymbol('asyncAll')) { - node = new nodes.AsyncAll(forTok.lineno, forTok.colno); - endBlock = 'endall'; - } else { - this.fail("parseFor: expected for{Async}", forTok.lineno, forTok.colno); - } - - node.name = this.parsePrimary(); - - if (!(node.name instanceof nodes.Symbol)) { - this.fail('parseFor: variable name expected for loop'); - } - - var type = this.peekToken().type; - if (type == lexer.TOKEN_COMMA) { - // key/value iteration - var key = node.name; - node.name = new nodes.Array(key.lineno, key.colno); - node.name.addChild(key); - - while (this.skip(lexer.TOKEN_COMMA)) { - var prim = this.parsePrimary(); - node.name.addChild(prim); - } - } - - if (!this.skipSymbol('in')) { - this.fail('parseFor: expected "in" keyword for loop', - forTok.lineno, - forTok.colno); - } - - node.arr = this.parseExpression(); - this.advanceAfterBlockEnd(forTok.value); - - node.body = this.parseUntilBlocks(endBlock); - this.advanceAfterBlockEnd(); - - return node; - }, - - parseMacro: function() { - var macroTok = this.peekToken(); - if (!this.skipSymbol('macro')) { - this.fail("expected macro"); - } - - var name = this.parsePrimary(true); - var args = this.parseSignature(); - var node = new nodes.Macro(macroTok.lineno, - macroTok.colno, - name, - args); - - this.advanceAfterBlockEnd(macroTok.value); - node.body = this.parseUntilBlocks('endmacro'); - this.advanceAfterBlockEnd(); - - return node; - }, - - parseImport: function() { - var importTok = this.peekToken(); - if (!this.skipSymbol('import')) { - this.fail("parseImport: expected import", - importTok.lineno, - importTok.colno); - } - - var template = this.parsePrimary(); - - if (!this.skipSymbol('as')) { - this.fail('parseImport: expected "as" keyword', - importTok.lineno, - importTok.colno); - } - - var target = this.parsePrimary(); - var node = new nodes.Import(importTok.lineno, - importTok.colno, - template, - target); - this.advanceAfterBlockEnd(importTok.value); - - return node; - }, - - parseFrom: function() { - var fromTok = this.peekToken(); - if (!this.skipSymbol('from')) { - this.fail("parseFrom: expected from"); - } - - var template = this.parsePrimary(); - var node = new nodes.FromImport(fromTok.lineno, - fromTok.colno, - template, - new nodes.NodeList()); - - if (!this.skipSymbol('import')) { - this.fail("parseFrom: expected import", - fromTok.lineno, - fromTok.colno); - } - - var names = node.names; - - while (1) { - var nextTok = this.peekToken(); - if (nextTok.type == lexer.TOKEN_BLOCK_END) { - if (!names.children.length) { - this.fail('parseFrom: Expected at least one import name', - fromTok.lineno, - fromTok.colno); - } - - // Since we are manually advancing past the block end, - // need to keep track of whitespace control (normally - // this is done in `advanceAfterBlockEnd` - if (nextTok.value.charAt(0) == '-') { - this.dropLeadingWhitespace = true; - } - - this.nextToken(); - break; - } - - if (names.children.length > 0 && !this.skip(lexer.TOKEN_COMMA)) { - this.fail('parseFrom: expected comma', - fromTok.lineno, - fromTok.colno); - } - - var name = this.parsePrimary(); - if (name.value.charAt(0) == '_') { - this.fail('parseFrom: names starting with an underscore ' + - 'cannot be imported', - name.lineno, - name.colno); - } - - if (this.skipSymbol('as')) { - var alias = this.parsePrimary(); - names.addChild(new nodes.Pair(name.lineno, - name.colno, - name, - alias)); - } else { - names.addChild(name); - } - } - - return node; - }, - - parseBlock: function() { - var tag = this.peekToken(); - if (!this.skipSymbol('block')) { - this.fail('parseBlock: expected block', tag.lineno, tag.colno); - } - - var node = new nodes.Block(tag.lineno, tag.colno); - - node.name = this.parsePrimary(); - if (!(node.name instanceof nodes.Symbol)) { - this.fail('parseBlock: variable name expected', - tag.lineno, - tag.colno); - } - - this.advanceAfterBlockEnd(tag.value); - - node.body = this.parseUntilBlocks('endblock'); - - if (!this.peekToken()) { - this.fail('parseBlock: expected endblock, got end of file'); - } - - this.advanceAfterBlockEnd(); - - return node; - }, - - parseTemplateRef: function(tagName, nodeType) { - var tag = this.peekToken(); - if (!this.skipSymbol(tagName)) { - this.fail('parseTemplateRef: expected ' + tagName); - } - - var node = new nodeType(tag.lineno, tag.colno); - node.template = this.parsePrimary(); - - this.advanceAfterBlockEnd(tag.value); - return node; - }, - - parseExtends: function() { - return this.parseTemplateRef('extends', nodes.Extends); - }, - - parseInclude: function() { - return this.parseTemplateRef('include', nodes.Include); - }, - - parseIf: function() { - var tag = this.peekToken(); - var node; - - if (this.skipSymbol('if') || this.skipSymbol('elif')) { - node = new nodes.If(tag.lineno, tag.colno); - } else if (this.skipSymbol('ifAsync')) { - node = new nodes.IfAsync(tag.lineno, tag.colno); - } else { - this.fail("parseIf: expected if or elif", - tag.lineno, - tag.colno); - } - - node.cond = this.parseExpression(); - this.advanceAfterBlockEnd(tag.value); - - node.body = this.parseUntilBlocks('elif', 'else', 'endif'); - var tok = this.peekToken(); - - switch (tok && tok.value) { - case "elif": - node.else_ = this.parseIf(); - break; - case "else": - this.advanceAfterBlockEnd(); - node.else_ = this.parseUntilBlocks("endif"); - this.advanceAfterBlockEnd(); - break; - case "endif": - node.else_ = null; - this.advanceAfterBlockEnd(); - break; - default: - this.fail('parseIf: expected endif, else, or endif, ' + - 'got end of file'); - } - - return node; - }, - - parseSet: function() { - var tag = this.peekToken(); - if (!this.skipSymbol('set')) { - this.fail('parseSet: expected set', tag.lineno, tag.colno); - } - - var node = new nodes.Set(tag.lineno, tag.colno, []); - - var target; - while ((target = this.parsePrimary())) { - node.targets.push(target); - - if (!this.skip(lexer.TOKEN_COMMA)) { - break; - } - } - - if (!this.skipValue(lexer.TOKEN_OPERATOR, '=')) { - this.fail('parseSet: expected = in set tag', - tag.lineno, - tag.colno); - } - - node.value = this.parseExpression(); - this.advanceAfterBlockEnd(tag.value); - - return node; - }, - - parseStatement: function() { - var tok = this.peekToken(); - var node; - - if (tok.type != lexer.TOKEN_SYMBOL) { - this.fail('tag name expected', tok.lineno, tok.colno); - } - - if (this.breakOnBlocks && - this.breakOnBlocks.indexOf(tok.value) !== -1) { - return null; - } - - switch (tok.value) { - case 'raw': - return this.parseRaw(); - case 'if': - case 'ifAsync': - return this.parseIf(); - case 'for': - case 'asyncEach': - case 'asyncAll': - return this.parseFor(); - case 'block': - return this.parseBlock(); - case 'extends': - return this.parseExtends(); - case 'include': - return this.parseInclude(); - case 'set': - return this.parseSet(); - case 'macro': - return this.parseMacro(); - case 'import': - return this.parseImport(); - case 'from': - return this.parseFrom(); - default: - if (this.extensions.length) { - for (var i = 0; i < this.extensions.length; i++) { - var ext = this.extensions[i]; - if ((ext.tags || []).indexOf(tok.value) !== -1) { - return ext.parse(this, nodes, lexer); - } - } - } - this.fail('unknown block tag: ' + tok.value, tok.lineno, tok.colno); - } - - return node; - }, - - parseRaw: function() { - this.advanceAfterBlockEnd(); - var str = ''; - var begun = this.peekToken(); - - while (1) { - // Passing true gives us all the whitespace tokens as - // well, which are usually ignored. - var tok = this.nextToken(true); - - if (!tok) { - this.fail("expected endraw, got end of file"); - } - - if (tok.type == lexer.TOKEN_BLOCK_START) { - // We need to look for the `endraw` block statement, - // which involves a lookahead so carefully keep track - // of whitespace - var ws = null; - var name = this.nextToken(true); - - if (name.type == lexer.TOKEN_WHITESPACE) { - ws = name; - name = this.nextToken(); - } - - if (name.type == lexer.TOKEN_SYMBOL && - name.value == 'endraw') { - this.advanceAfterBlockEnd(name.value); - break; - } else { - str += tok.value; - if (ws) { - str += ws.value; - } - str += name.value; - } - } else { - str += tok.value; - } - } - - - var output = new nodes.Output( - begun.lineno, - begun.colno, - [new nodes.TemplateData(begun.lineno, begun.colno, str)] - ); - - return output; - }, - - parsePostfix: function(node) { - var tok = this.peekToken(); - - while (tok) { - if (tok.type == lexer.TOKEN_LEFT_PAREN) { - // Function call - node = new nodes.FunCall(tok.lineno, - tok.colno, - node, - this.parseSignature()); - } else if (tok.type == lexer.TOKEN_LEFT_BRACKET) { - // Reference - var lookup = this.parseAggregate(); - if (lookup.children.length > 1) { - this.fail('invalid index'); - } - - node = new nodes.LookupVal(tok.lineno, - tok.colno, - node, - lookup.children[0]); - } else if (tok.type == lexer.TOKEN_OPERATOR && tok.value == '.') { - // Reference - this.nextToken(); - var val = this.nextToken(); - - if (val.type != lexer.TOKEN_SYMBOL) { - this.fail('expected name as lookup value, got ' + val.value, - val.lineno, - val.colno); - } - - // Make a literal string because it's not a variable - // reference - var lookup = new nodes.Literal(val.lineno, - val.colno, - val.value); - - node = new nodes.LookupVal(tok.lineno, - tok.colno, - node, - lookup); - } else { - break; - } - - tok = this.peekToken(); - } - - return node; - }, - - parseExpression: function() { - var node = this.parseInlineIf(); - return node; - }, - - parseInlineIf: function() { - var node = this.parseOr(); - if (this.skipSymbol('if')) { - var cond_node = this.parseOr(); - var body_node = node; - node = new nodes.InlineIf(node.lineno, node.colno); - node.body = body_node; - node.cond = cond_node; - if (this.skipSymbol('else')) { - node.else_ = this.parseOr(); - } else { - node.else_ = null; - } - } - - return node; - }, - - parseOr: function() { - var node = this.parseAnd(); - while (this.skipSymbol('or')) { - var node2 = this.parseAnd(); - node = new nodes.Or(node.lineno, - node.colno, - node, - node2); - } - return node; - }, - - parseAnd: function() { - var node = this.parseNot(); - while (this.skipSymbol('and')) { - var node2 = this.parseNot(); - node = new nodes.And(node.lineno, - node.colno, - node, - node2); - } - return node; - }, - - parseNot: function() { - var tok = this.peekToken(); - if (this.skipSymbol('not')) { - return new nodes.Not(tok.lineno, - tok.colno, - this.parseNot()); - } - return this.parseCompare(); - }, - - parseCompare: function() { - var compareOps = ['==', '!=', '<', '>', '<=', '>=']; - var expr = this.parseAdd(); - var ops = []; - - while (1) { - var tok = this.nextToken(); - - if (!tok) { - break; - } else if (compareOps.indexOf(tok.value) !== -1) { - ops.push(new nodes.CompareOperand(tok.lineno, - tok.colno, - this.parseAdd(), - tok.value)); - } else if (tok.type == lexer.TOKEN_SYMBOL && - tok.value == 'in') { - ops.push(new nodes.CompareOperand(tok.lineno, - tok.colno, - this.parseAdd(), - 'in')); - } else if (tok.type == lexer.TOKEN_SYMBOL && - tok.value == 'not' && - this.skipSymbol('in')) { - ops.push(new nodes.CompareOperand(tok.lineno, - tok.colno, - this.parseAdd(), - 'notin')); - } else { - this.pushToken(tok); - break; - } - } - - if (ops.length) { - return new nodes.Compare(ops[0].lineno, - ops[0].colno, - expr, - ops); - } else { - return expr; - } - }, - - parseAdd: function() { - var node = this.parseSub(); - while (this.skipValue(lexer.TOKEN_OPERATOR, '+')) { - var node2 = this.parseSub(); - node = new nodes.Add(node.lineno, - node.colno, - node, - node2); - } - return node; - }, - - parseSub: function() { - var node = this.parseMul(); - while (this.skipValue(lexer.TOKEN_OPERATOR, '-')) { - var node2 = this.parseMul(); - node = new nodes.Sub(node.lineno, - node.colno, - node, - node2); - } - return node; - }, - - parseMul: function() { - var node = this.parseDiv(); - while (this.skipValue(lexer.TOKEN_OPERATOR, '*')) { - var node2 = this.parseDiv(); - node = new nodes.Mul(node.lineno, - node.colno, - node, - node2); - } - return node; - }, - - parseDiv: function() { - var node = this.parseFloorDiv(); - while (this.skipValue(lexer.TOKEN_OPERATOR, '/')) { - var node2 = this.parseFloorDiv(); - node = new nodes.Div(node.lineno, - node.colno, - node, - node2); - } - return node; - }, - - parseFloorDiv: function() { - var node = this.parseMod(); - while (this.skipValue(lexer.TOKEN_OPERATOR, '//')) { - var node2 = this.parseMod(); - node = new nodes.FloorDiv(node.lineno, - node.colno, - node, - node2); - } - return node; - }, - - parseMod: function() { - var node = this.parsePow(); - while (this.skipValue(lexer.TOKEN_OPERATOR, '%')) { - var node2 = this.parsePow(); - node = new nodes.Mod(node.lineno, - node.colno, - node, - node2); - } - return node; - }, - - parsePow: function() { - var node = this.parseUnary(); - while (this.skipValue(lexer.TOKEN_OPERATOR, '**')) { - var node2 = this.parseUnary(); - node = new nodes.Pow(node.lineno, - node.colno, - node, - node2); - } - return node; - }, - - parseUnary: function(noFilters) { - var tok = this.peekToken(); - var node; - - if (this.skipValue(lexer.TOKEN_OPERATOR, '-')) { - node = new nodes.Neg(tok.lineno, - tok.colno, - this.parseUnary(true)); - } else if (this.skipValue(lexer.TOKEN_OPERATOR, '+')) { - node = new nodes.Pos(tok.lineno, - tok.colno, - this.parseUnary(true)); - } else { - node = this.parsePrimary(); - } - - if (!noFilters) { - node = this.parseFilter(node); - } - - return node; - }, - - parsePrimary: function(noPostfix) { - var tok = this.nextToken(); - var val = null; - var node = null; - - if (!tok) { - this.fail('expected expression, got end of file'); - } else if (tok.type == lexer.TOKEN_STRING) { - val = tok.value; - } else if (tok.type == lexer.TOKEN_INT) { - val = parseInt(tok.value, 10); - } else if (tok.type == lexer.TOKEN_FLOAT) { - val = parseFloat(tok.value); - } else if (tok.type == lexer.TOKEN_BOOLEAN) { - if (tok.value == "true") { - val = true; - } else if (tok.value == "false") { - val = false; - } else { - this.fail("invalid boolean: " + tok.val, - tok.lineno, - tok.colno); - } - } - - if (val !== null) { - node = new nodes.Literal(tok.lineno, tok.colno, val); - } else if (tok.type == lexer.TOKEN_SYMBOL) { - node = new nodes.Symbol(tok.lineno, tok.colno, tok.value); - - if (!noPostfix) { - node = this.parsePostfix(node); - } - } else { - // See if it's an aggregate type, we need to push the - // current delimiter token back on - this.pushToken(tok); - node = this.parseAggregate(); - } - - if (node) { - return node; - } else { - this.fail('unexpected token: ' + tok.value, - tok.lineno, - tok.colno); - } - }, - - parseFilter: function(node) { - while (this.skip(lexer.TOKEN_PIPE)) { - var tok = this.expect(lexer.TOKEN_SYMBOL); - var name = tok.value; - - while (this.skipValue(lexer.TOKEN_OPERATOR, '.')) { - name += '.' + this.expect(lexer.TOKEN_SYMBOL).value; - } - - node = new nodes.Filter( - tok.lineno, - tok.colno, - new nodes.Symbol(tok.lineno, - tok.colno, - name), - new nodes.NodeList( - tok.lineno, - tok.colno, - [node]) - ); - - if (this.peekToken().type == lexer.TOKEN_LEFT_PAREN) { - // Get a FunCall node and add the parameters to the - // filter - var call = this.parsePostfix(node); - node.args.children = node.args.children.concat(call.args.children); - } - } - - return node; - }, - - parseAggregate: function() { - var tok = this.nextToken(); - var node; - - switch (tok.type) { - case lexer.TOKEN_LEFT_PAREN: - node = new nodes.Group(tok.lineno, tok.colno); - break; - case lexer.TOKEN_LEFT_BRACKET: - node = new nodes.Array(tok.lineno, tok.colno); - break; - case lexer.TOKEN_LEFT_CURLY: - node = new nodes.Dict(tok.lineno, tok.colno); - break; - default: - return null; - } - - while (1) { - var type = this.peekToken().type; - if (type == lexer.TOKEN_RIGHT_PAREN || - type == lexer.TOKEN_RIGHT_BRACKET || - type == lexer.TOKEN_RIGHT_CURLY) { - this.nextToken(); - break; - } - - if (node.children.length > 0) { - if (!this.skip(lexer.TOKEN_COMMA)) { - this.fail("parseAggregate: expected comma after expression", - tok.lineno, - tok.colno); - } - } - - if (node instanceof nodes.Dict) { - // TODO: check for errors - var key = this.parsePrimary(); - - // We expect a key/value pair for dicts, separated by a - // colon - if (!this.skip(lexer.TOKEN_COLON)) { - this.fail("parseAggregate: expected colon after dict key", - tok.lineno, - tok.colno); - } - - // TODO: check for errors - var value = this.parseExpression(); - node.addChild(new nodes.Pair(key.lineno, - key.colno, - key, - value)); - } else { - // TODO: check for errors - var expr = this.parseExpression(); - node.addChild(expr); - } - } - - return node; - }, - - parseSignature: function(tolerant, noParens) { - var tok = this.peekToken(); - if (!noParens && tok.type != lexer.TOKEN_LEFT_PAREN) { - if (tolerant) { - return null; - } else { - this.fail('expected arguments', tok.lineno, tok.colno); - } - } - - if (tok.type == lexer.TOKEN_LEFT_PAREN) { - tok = this.nextToken(); - } - - var args = new nodes.NodeList(tok.lineno, tok.colno); - var kwargs = new nodes.KeywordArgs(tok.lineno, tok.colno); - var kwnames = []; - var checkComma = false; - - while (1) { - tok = this.peekToken(); - if (!noParens && tok.type == lexer.TOKEN_RIGHT_PAREN) { - this.nextToken(); - break; - } else if (noParens && tok.type == lexer.TOKEN_BLOCK_END) { - break; - } - - if (checkComma && !this.skip(lexer.TOKEN_COMMA)) { - this.fail("parseSignature: expected comma after expression", - tok.lineno, - tok.colno); - } else { - var arg = this.parseExpression(); - - if (this.skipValue(lexer.TOKEN_OPERATOR, '=')) { - kwargs.addChild( - new nodes.Pair(arg.lineno, - arg.colno, - arg, - this.parseExpression()) - ); - } else { - args.addChild(arg); - } - } - - checkComma = true; - } - - if (kwargs.children.length) { - args.addChild(kwargs); - } - - return args; - }, - - parseUntilBlocks: function( /* blockNames */ ) { - var prev = this.breakOnBlocks; - this.breakOnBlocks = lib.toArray(arguments); - - var ret = this.parse(); - - this.breakOnBlocks = prev; - return ret; - }, - - parseNodes: function() { - var tok; - var buf = []; - - while ((tok = this.nextToken())) { - if (tok.type == lexer.TOKEN_DATA) { - var data = tok.value; - var nextToken = this.peekToken(); - var nextVal = nextToken && nextToken.value; - - // If the last token has "-" we need to trim the - // leading whitespace of the data. This is marked with - // the `dropLeadingWhitespace` variable. - if (this.dropLeadingWhitespace) { - // TODO: this could be optimized (don't use regex) - data = data.replace(/^\s*/, ''); - this.dropLeadingWhitespace = false; - } - - // Same for the succeding block start token - if (nextToken && - nextToken.type == lexer.TOKEN_BLOCK_START && - nextVal.charAt(nextVal.length - 1) == '-') { - // TODO: this could be optimized (don't use regex) - data = data.replace(/\s*$/, ''); - } - - buf.push(new nodes.Output(tok.lineno, - tok.colno, - [new nodes.TemplateData(tok.lineno, - tok.colno, - data)])); - } else if (tok.type == lexer.TOKEN_BLOCK_START) { - var n = this.parseStatement(); - if (!n) { - break; - } - buf.push(n); - } else if (tok.type == lexer.TOKEN_VARIABLE_START) { - var e = this.parseExpression(); - this.advanceAfterVariableEnd(); - buf.push(new nodes.Output(tok.lineno, tok.colno, [e])); - } else if (tok.type != lexer.TOKEN_COMMENT) { - // Ignore comments, otherwise this should be an error - this.fail("Unexpected token at top-level: " + - tok.type, tok.lineno, tok.colno); - } - } - - return buf; - }, - - parse: function() { - return new nodes.NodeList(0, 0, this.parseNodes()); - }, - - parseAsRoot: function() { - return new nodes.Root(0, 0, this.parseNodes()); - } - }); - - // var util = modules["util"]; - - // var l = lexer.lex('{%- if x -%}\n hello {% endif %}'); - // var t; - // while((t = l.nextToken())) { - // console.log(util.inspect(t)); - // } - - // var p = new Parser(lexer.lex('hello {% foo %} {{ "hi" | bar }} {% endfoo %} end')); - // p.extensions = [new FooExtension()]; - // var n = p.parseAsRoot(); - // nodes.printNodes(n); - - modules['parser'] = { - parse: function(src, extensions) { - var p = new Parser(lexer.lex(src)); - if (extensions !== undefined) { - p.extensions = extensions; - } - return p.parseAsRoot(); - } - }; - })(); - (function() { - var nodes = modules["nodes"]; - - var sym = 0; - function gensym() { - return 'hole_' + sym++; - } - - // copy-on-write version of map - function mapCOW(arr, func) { - var res = null; - - for (var i = 0; i < arr.length; i++) { - var item = func(arr[i]); - - if (item !== arr[i]) { - if (!res) { - res = arr.slice(); - } - - res[i] = item; - } - } - - return res || arr; - } - - function walk(ast, func, depthFirst) { - if (!(ast instanceof nodes.Node)) { - return ast; - } - - if (!depthFirst) { - var astT = func(ast); - - if (astT && astT !== ast) { - return astT; - } - } - - if (ast instanceof nodes.NodeList) { - var children = mapCOW(ast.children, function(node) { - return walk(node, func, depthFirst); - }); - - if (children !== ast.children) { - ast = new nodes[ast.typename](ast.lineno, ast.colno, children); - } - } else if (ast instanceof nodes.CallExtension) { - var args = walk(ast.args, func, depthFirst); - - var contentArgs = mapCOW(ast.contentArgs, function(node) { - return walk(node, func, depthFirst); - }); - - if (args !== ast.args || contentArgs !== ast.contentArgs) { - ast = new nodes[ast.typename](ast.extName, - ast.prop, - args, - contentArgs); - } - } else { - var props = ast.fields.map(function(field) { - return ast[field]; - }); - - var propsT = mapCOW(props, function(prop) { - return walk(prop, func, depthFirst); - }); - - if (propsT !== props) { - ast = new nodes[ast.typename](ast.lineno, ast.colno); - - propsT.forEach(function(prop, i) { - ast[ast.fields[i]] = prop; - }); - } - } - - return depthFirst ? (func(ast) || ast) : ast; - } - - function depthWalk(ast, func) { - return walk(ast, func, true); - } - - function _liftFilters(node, asyncFilters, prop) { - var children = []; - - var walked = depthWalk(prop ? node[prop] : node, function(node) { - if (node instanceof nodes.Block) { - return node; - } else if (node instanceof nodes.Filter && - asyncFilters.indexOf(node.name.value) !== -1) { - var symbol = new nodes.Symbol(node.lineno, - node.colno, - gensym()); - - children.push(new nodes.FilterAsync(node.lineno, - node.colno, - node.name, - node.args, - symbol)); - return symbol; - } - }); - - if (prop) { - node[prop] = walked; - } else { - node = walked; - } - - if (children.length) { - children.push(node); - - return new nodes.NodeList( - node.lineno, - node.colno, - children - ); - } else { - return node; - } - } - - function liftFilters(ast, asyncFilters) { - return depthWalk(ast, function(node) { - if (node instanceof nodes.Output) { - return _liftFilters(node, asyncFilters); - } else if (node instanceof nodes.For) { - return _liftFilters(node, asyncFilters, 'arr'); - } else if (node instanceof nodes.If) { - return _liftFilters(node, asyncFilters, 'cond'); - } else if (node instanceof nodes.CallExtension) { - return _liftFilters(node, asyncFilters, 'args'); - } - }); - } - - function liftSuper(ast) { - return walk(ast, function(blockNode) { - if (!(blockNode instanceof nodes.Block)) { - return; - } - - var hasSuper = false; - var symbol = gensym(); - - blockNode.body = walk(blockNode.body, function(node) { - if (node instanceof nodes.FunCall && - node.name.value == 'super') { - hasSuper = true; - return new nodes.Symbol(node.lineno, node.colno, symbol); - } - }); - - if (hasSuper) { - blockNode.body.children.unshift(new nodes.Super( - 0, 0, blockNode.name, new nodes.Symbol(0, 0, symbol) - )); - } - }); - } - - function convertStatements(ast) { - return depthWalk(ast, function(node) { - if (!(node instanceof nodes.If) && - !(node instanceof nodes.For)) { - return; - } - - var async = false; - walk(node, function(node) { - if (node instanceof nodes.FilterAsync || - node instanceof nodes.IfAsync || - node instanceof nodes.AsyncEach || - node instanceof nodes.AsyncAll) { - async = true; - // Stop iterating by returning the node - return node; - } - }); - - if (async) { - if (node instanceof nodes.If) { - return new nodes.IfAsync( - node.lineno, - node.colno, - node.cond, - node.body, - node.else_ - ); - } else if (node instanceof nodes.For) { - return new nodes.AsyncEach( - node.lineno, - node.colno, - node.arr, - node.name, - node.body - ); - } - } - }); - } - - function cps(ast, asyncFilters) { - return convertStatements(liftSuper(liftFilters(ast, asyncFilters))); - } - - function transform(ast, asyncFilters, name) { - return cps(ast, asyncFilters || []); - } - - // var parser = modules["parser"]; - // var src = 'hello {% foo %}{% endfoo %} end'; - // var ast = transform(parser.parse(src, [new FooExtension()]), ['bar']); - // nodes.printNodes(ast); - - modules['transformer'] = { - transform: transform - }; - })(); - (function() { - var lib = modules["lib"]; - var parser = modules["parser"]; - var transformer = modules["transformer"]; - var nodes = modules["nodes"]; - var Object = modules["object"]; - var Frame = modules["runtime"].Frame; - - // These are all the same for now, but shouldn't be passed straight - // through - var compareOps = { - '==': '==', - '!=': '!=', - '<': '<', - '>': '>', - '<=': '<=', - '>=': '>=' - }; - - // A common pattern is to emit binary operators - function binOpEmitter(str) { - return function(node, frame) { - this.compile(node.left, frame); - this.emit(str); - this.compile(node.right, frame); - }; - } - - // Generate an array of strings - function quotedArray(arr) { - return '[' + - lib.map(arr, function(x) { - return '"' + x + '"'; - }) + - ']'; - } - - var Compiler = Object.extend({ - init: function() { - this.codebuf = []; - this.lastId = 0; - this.buffer = null; - this.bufferStack = []; - this.isChild = false; - this.scopeClosers = ''; - }, - - fail: function(msg, lineno, colno) { - if (lineno !== undefined) { - lineno += 1; - } - if (colno !== undefined) { - colno += 1; - } - - throw new lib.TemplateError(msg, lineno, colno); - }, - - pushBufferId: function(id) { - this.bufferStack.push(this.buffer); - this.buffer = id; - this.emit('var ' + this.buffer + ' = "";'); - }, - - popBufferId: function() { - this.buffer = this.bufferStack.pop(); - }, - - emit: function(code) { - this.codebuf.push(code); - }, - - emitLine: function(code) { - this.emit(code + "\n"); - }, - - emitLines: function() { - lib.each(lib.toArray(arguments), function(line) { - this.emitLine(line); - }, this); - }, - - emitFuncBegin: function(name) { - this.buffer = 'output'; - this.scopeClosers = ''; - this.emitLine('function ' + name + '(env, context, frame, runtime, cb) {'); - this.emitLine('var lineno = null;'); - this.emitLine('var colno = null;'); - this.emitLine('var ' + this.buffer + ' = "";'); - this.emitLine('try {'); - }, - - emitFuncEnd: function(noReturn) { - if (!noReturn) { - this.emitLine('cb(null, ' + this.buffer + ');'); - } - - this.closeScopeLevels(); - this.emitLine('} catch (e) {'); - this.emitLine(' cb(runtime.handleError(e, lineno, colno));'); - this.emitLine('}'); - this.emitLine('}'); - this.buffer = null; - }, - - addScopeLevel: function(closingDelim) { - this.scopeClosers += closingDelim || '})'; - }, - - closeScopeLevels: function() { - this.emitLine(this.scopeClosers + ';'); - this.scopeClosers = ''; - }, - - withScopedSyntax: function(func) { - var scopeClosers = this.scopeClosers; - this.scopeClosers = ''; - - func.call(this); - - this.closeScopeLevels(); - this.scopeClosers = scopeClosers; - }, - - makeCallback: function(res) { - var err = this.tmpid(); - - return 'function(' + err + (res ? ',' + res : '') + ') {\n' + - 'if(' + err + ') { cb(' + err + '); return; }'; - }, - - tmpid: function() { - this.lastId++; - return 't_' + this.lastId; - }, - - _bufferAppend: function(func) { - this.emit(this.buffer + ' += runtime.suppressValue('); - func.call(this); - this.emit(', env.autoesc);\n'); - }, - - _compileChildren: function(node, frame) { - var children = node.children; - for (var i = 0, l = children.length; i < l; i++) { - this.compile(children[i], frame); - } - }, - - _compileAggregate: function(node, frame, startChar, endChar) { - if (startChar) { - this.emit(startChar); - } - - for (var i = 0; i < node.children.length; i++) { - if (i > 0) { - this.emit(','); - } - - this.compile(node.children[i], frame); - } - - if (endChar) { - this.emit(endChar); - } - }, - - _compileExpression: function(node, frame) { - // TODO: I'm not really sure if this type check is worth it or - // not. - this.assertType( - node, - nodes.Literal, - nodes.Symbol, - nodes.Group, - nodes.Array, - nodes.Dict, - nodes.FunCall, - nodes.Filter, - nodes.LookupVal, - nodes.Compare, - nodes.InlineIf, - nodes.And, - nodes.Or, - nodes.Not, - nodes.Add, - nodes.Sub, - nodes.Mul, - nodes.Div, - nodes.FloorDiv, - nodes.Mod, - nodes.Pow, - nodes.Neg, - nodes.Pos, - nodes.Compare, - nodes.NodeList - ); - this.compile(node, frame); - }, - - assertType: function(node /*, types */ ) { - var types = lib.toArray(arguments).slice(1); - var success = false; - - for (var i = 0; i < types.length; i++) { - if (node instanceof types[i]) { - success = true; - } - } - - if (!success) { - this.fail("assertType: invalid type: " + node.typename, - node.lineno, - node.colno); - } - }, - - compileCallExtension: function(node, frame, async) { - var name = node.extName; - var args = node.args; - var contentArgs = node.contentArgs; - var transformedArgs = []; - - if (!async) { - this.emit(this.buffer + ' += runtime.suppressValue('); - } - - this.emit('env.getExtension("' + node.extName + '")["' + node.prop + '"]('); - this.emit('context'); - - if (args || contentArgs) { - this.emit(','); - } - - if (args) { - if (!(args instanceof nodes.NodeList)) { - this.fail('compileCallExtension: arguments must be a NodeList, ' + - 'use `parser.parseSignature`'); - } - - lib.each(args.children, function(arg, i) { - // Tag arguments are passed normally to the call. Note - // that keyword arguments are turned into a single js - // object as the last argument, if they exist. - this._compileExpression(arg, frame); - - if (i != args.children.length - 1 || contentArgs.length) { - this.emit(','); - } - }, this); - } - - if (contentArgs.length) { - lib.each(contentArgs, function(arg, i) { - if (i > 0) { - this.emit(','); - } - - if (arg) { - var id = this.tmpid(); - - this.emitLine('function(cb) {'); - this.emitLine('if(!cb) { cb = function(err) { if(err) { throw err; }}}'); - this.pushBufferId(id); - - this.withScopedSyntax(function() { - this.compile(arg, frame); - this.emitLine('cb(null, ' + id + ');'); - }); - - this.popBufferId(); - this.emitLine('return ' + id + ';'); - this.emitLine('}'); - } else { - this.emit('null'); - } - }, this); - } - - if (async) { - var res = this.tmpid(); - this.emitLine(', ' + this.makeCallback(res)); - this.emitLine(this.buffer + ' += runtime.suppressValue(' + res + ', env.autoesc);'); - this.addScopeLevel(); - } else { - this.emit(')'); - this.emit(', env.autoesc);\n'); - } - }, - - compileCallExtensionAsync: function(node, frame) { - this.compileCallExtension(node, frame, true); - }, - - compileNodeList: function(node, frame) { - this._compileChildren(node, frame); - }, - - compileLiteral: function(node, frame) { - if (typeof node.value == "string") { - var val = node.value.replace(/\\/g, '\\\\'); - val = val.replace(/"/g, '\\"'); - val = val.replace(/\n/g, "\\n"); - val = val.replace(/\r/g, "\\r"); - val = val.replace(/\t/g, "\\t"); - this.emit('"' + val + '"'); - } else { - this.emit(node.value.toString()); - } - }, - - compileSymbol: function(node, frame) { - var name = node.value; - var v; - - if( (v = frame.lookup(name)) ) { - this.emit(v); - } else { - this.emit('runtime.contextOrFrameLookup(' + - 'context, frame, "' + name + '")'); - } - }, - - compileGroup: function(node, frame) { - this._compileAggregate(node, frame, '(', ')'); - }, - - compileArray: function(node, frame) { - this._compileAggregate(node, frame, '[', ']'); - }, - - compileDict: function(node, frame) { - this._compileAggregate(node, frame, '{', '}'); - }, - - compilePair: function(node, frame) { - var key = node.key; - var val = node.value; - - if (key instanceof nodes.Symbol) { - key = new nodes.Literal(key.lineno, key.colno, key.value); - } else if (!(key instanceof nodes.Literal && - typeof key.value == "string")) { - this.fail("compilePair: Dict keys must be strings or names", - key.lineno, - key.colno); - } - - this.compile(key, frame); - this.emit(': '); - this._compileExpression(val, frame); - }, - - compileInlineIf: function(node, frame) { - this.emit('('); - this.compile(node.cond, frame); - this.emit('?'); - this.compile(node.body, frame); - this.emit(':'); - if (node.else_ !== null) { - this.compile(node.else_, frame); - } else { - this.emit('""'); - } - this.emit(')'); - }, - - compileOr: binOpEmitter(' || '), - compileAnd: binOpEmitter(' && '), - compileAdd: binOpEmitter(' + '), - compileSub: binOpEmitter(' - '), - compileMul: binOpEmitter(' * '), - compileDiv: binOpEmitter(' / '), - compileMod: binOpEmitter(' % '), - - compileNot: function(node, frame) { - this.emit('!'); - this.compile(node.target, frame); - }, - - compileFloorDiv: function(node, frame) { - this.emit('Math.floor('); - this.compile(node.left, frame); - this.emit(' / '); - this.compile(node.right, frame); - this.emit(')'); - }, - - compilePow: function(node, frame) { - this.emit('Math.pow('); - this.compile(node.left, frame); - this.emit(', '); - this.compile(node.right, frame); - this.emit(')'); - }, - - compileNeg: function(node, frame) { - this.emit('-'); - this.compile(node.target, frame); - }, - - compilePos: function(node, frame) { - this.emit('+'); - this.compile(node.target, frame); - }, - - compileCompare: function(node, frame) { - this.compile(node.expr, frame); - - for (var i = 0; i < node.ops.length; i++) { - var n = node.ops[i]; - this.emit(' ' + compareOps[n.type] + ' '); - this.compile(n.expr, frame); - } - }, - - compileLookupVal: function(node, frame) { - this.emit('runtime.memberLookup(('); - this._compileExpression(node.target, frame); - this.emit('),'); - this._compileExpression(node.val, frame); - this.emit(', env.autoesc)'); - }, - - _getNodeName: function(node) { - switch (node.typename) { - case 'Symbol': - return node.value; - case 'FunCall': - return 'the return value of (' + this._getNodeName(node.name) + ')'; - case 'LookupVal': - return this._getNodeName(node.target) + '["' + - this._getNodeName(node.val) + '"]'; - case 'Literal': - return node.value.toString().substr(0, 10); - default: - return '--expression--'; - } - }, - - compileFunCall: function(node, frame) { - // Keep track of line/col info at runtime by settings - // variables within an expression. An expression in javascript - // like (x, y, z) returns the last value, and x and y can be - // anything - this.emit('(lineno = ' + node.lineno + - ', colno = ' + node.colno + ', '); - - this.emit('runtime.callWrap('); - // Compile it as normal. - this._compileExpression(node.name, frame); - - // Output the name of what we're calling so we can get friendly errors - // if the lookup fails. - this.emit(', "' + this._getNodeName(node.name).replace(/"/g, '\\"') + '", '); - - this._compileAggregate(node.args, frame, '[', '])'); - - this.emit(')'); - }, - - compileFilter: function(node, frame) { - var name = node.name; - this.assertType(name, nodes.Symbol); - - this.emit('env.getFilter("' + name.value + '").call(context, '); - this._compileAggregate(node.args, frame); - this.emit(')'); - }, - - compileFilterAsync: function(node, frame) { - var name = node.name; - this.assertType(name, nodes.Symbol); - - var symbol = node.symbol.value; - frame.set(symbol, symbol); - - this.emit('env.getFilter("' + name.value + '").call(context, '); - this._compileAggregate(node.args, frame); - this.emitLine(', ' + this.makeCallback(symbol)); - - this.addScopeLevel(); - }, - - compileKeywordArgs: function(node, frame) { - var names = []; - - lib.each(node.children, function(pair) { - names.push(pair.key.value); - }); - - this.emit('runtime.makeKeywordArgs('); - this.compileDict(node, frame); - this.emit(')'); - }, - - compileSet: function(node, frame) { - var ids = []; - - // Lookup the variable names for each identifier and create - // new ones if necessary - lib.each(node.targets, function(target) { - var name = target.value; - var id = frame.get(name); - - if (id === null) { - id = this.tmpid(); - - // Note: This relies on js allowing scope across - // blocks, in case this is created inside an `if` - this.emitLine('var ' + id + ';'); - } - - ids.push(id); - }, this); - - this.emit(ids.join(' = ') + ' = '); - this._compileExpression(node.value, frame); - this.emitLine(';'); - - lib.each(node.targets, function(target, i) { - var id = ids[i]; - var name = target.value; - - this.emitLine('frame.set("' + name + '", ' + id + ');'); - if (frame.get(name) === null) { - frame.set(name, id); - } - - // We are running this for every var, but it's very - // uncommon to assign to multiple vars anyway - this.emitLine('if(!frame.parent) {'); - this.emitLine('context.setVariable("' + name + '", ' + id + ');'); - if (name.charAt(0) != '_') { - this.emitLine('context.addExport("' + name + '");'); - } - this.emitLine('}'); - }, this); - }, - - compileIf: function(node, frame, async) { - this.emit('if('); - this._compileExpression(node.cond, frame); - this.emitLine(') {'); - - this.withScopedSyntax(function() { - this.compile(node.body, frame); - - if (async) { - this.emit('cb()'); - } - }); - - if (node.else_) { - this.emitLine('}\nelse {'); - - this.withScopedSyntax(function() { - this.compile(node.else_, frame); - - if (async) { - this.emit('cb()'); - } - }); - } - - this.emitLine('}'); - }, - - compileIfAsync: function(node, frame) { - this.emit('(function(cb) {'); - this.compileIf(node, frame, true); - this.emit('})(function() {'); - this.addScopeLevel(); - }, - - scanLoop: function(node) { - var loopUses = {}; - - node.iterFields(function(field) { - var lookups = field.findAll(nodes.LookupVal); - - lib.each(lookups, function(lookup) { - if (lookup.target instanceof nodes.Symbol && - lookup.target.value == 'loop' && - lookup.val instanceof nodes.Literal) { - loopUses[lookup.val.value] = true; - } - }); - }); - - return loopUses; - }, - - emitLoopBindings: function(node, loopUses, arr, i, len) { - len = len || arr + '.length'; - - var bindings = { - index: i + ' + 1', - index0: i, - revindex: len + ' - ' + i, - revindex0: len + ' - ' + i + ' - 1', - first: i + ' === 0', - last: i + ' === ' + len + ' - 1', - length: len - }; - - for (var name in bindings) { - if (name in loopUses) { - this.emitLine('frame.set("loop.' + name + '", ' + bindings[name] + ');'); - } - } - }, - - compileFor: function(node, frame) { - // Some of this code is ugly, but it keeps the generated code - // as fast as possible. ForAsync also shares some of this, but - // not much. - - var i = this.tmpid(); - var len = this.tmpid(); - var arr = this.tmpid(); - var loopUses = this.scanLoop(node); - frame = frame.push(); - - this.emitLine('frame = frame.push();'); - - this.emit('var ' + arr + ' = '); - this._compileExpression(node.arr, frame); - this.emitLine(';'); - - this.emit('if(' + arr + ') {'); - - // If multiple names are passed, we need to bind them - // appropriately - if (node.name instanceof nodes.Array) { - this.emitLine('var ' + i + ';'); - - // The object could be an arroy or object. Note that the - // body of the loop is duplicated for each condition, but - // we are optimizing for speed over size. - this.emitLine('if(runtime.isArray(' + arr + ')) {'); - { - this.emitLine('for(' + i + '=0; ' + i + ' < ' + arr + '.length; ' - + i + '++) {'); - - // Bind each declared var - for (var u = 0; u < node.name.children.length; u++) { - var tid = this.tmpid(); - this.emitLine('var ' + tid + ' = ' + arr + '[' + i + '][' + u + ']'); - this.emitLine('frame.set("' + node.name.children[u].value - + '", ' + arr + '[' + i + '][' + u + ']' + ');'); - frame.set(node.name.children[u].value, tid); - } - - this.emitLoopBindings(node, loopUses, arr, i); - this.compile(node.body, frame); - this.emitLine('}'); - } - - this.emitLine('} else {'); - { - // Iterate over the key/values of an object - var key = node.name.children[0]; - var val = node.name.children[1]; - var k = this.tmpid(); - var v = this.tmpid(); - frame.set(key.value, k); - frame.set(val.value, v); - - this.emitLine(i + ' = -1;'); - - if (loopUses['revindex'] || loopUses['revindex0'] || - loopUses['last'] || loopUses['length']) { - this.emitLine('var ' + len + ' = runtime.keys(' + arr + ').length;'); - } - - this.emitLine('for(var ' + k + ' in ' + arr + ') {'); - this.emitLine(i + '++;'); - this.emitLine('var ' + v + ' = ' + arr + '[' + k + '];'); - this.emitLine('frame.set("' + key.value + '", ' + k + ');'); - this.emitLine('frame.set("' + val.value + '", ' + v + ');'); - - this.emitLoopBindings(node, loopUses, arr, i, len); - this.compile(node.body, frame); - this.emitLine('}'); - } - - this.emitLine('}'); - } else { - // Generate a typical array iteration - var v = this.tmpid(); - frame.set(node.name.value, v); - - this.emitLine('for(var ' + i + '=0; ' + i + ' < ' + arr + '.length; ' + - i + '++) {'); - this.emitLine('var ' + v + ' = ' + arr + '[' + i + '];'); - this.emitLine('frame.set("' + node.name.value + '", ' + v + ');'); - - this.emitLoopBindings(node, loopUses, arr, i); - - this.withScopedSyntax(function() { - this.compile(node.body, frame); - }); - - this.emitLine('}'); - } - - this.emitLine('}'); - this.emitLine('frame = frame.pop();'); - }, - - _compileAsyncLoop: function(node, frame, parallel) { - // This shares some code with the For tag, but not enough to - // worry about. This iterates across an object asynchronously, - // but not in parallel. - - var i = this.tmpid(); - var len = this.tmpid(); - var arr = this.tmpid(); - var loopUses = this.scanLoop(node); - var asyncMethod = parallel ? 'asyncAll' : 'asyncEach'; - frame = frame.push(); - - this.emitLine('frame = frame.push();'); - - this.emit('var ' + arr + ' = '); - this._compileExpression(node.arr, frame); - this.emitLine(';'); - - if (node.name instanceof nodes.Array) { - this.emit('runtime.' + asyncMethod + '(' + arr + ', ' + - node.name.children.length + ', function('); - - lib.each(node.name.children, function(name) { - this.emit(name.value + ','); - }, this); - - this.emit(i + ',' + len + ',next) {'); - - lib.each(node.name.children, function(name) { - var id = name.value; - frame.set(id, id); - this.emitLine('frame.set("' + id + '", ' + id + ');'); - }, this); - } else { - var id = node.name.value; - this.emitLine('runtime.' + asyncMethod + '(' + arr + ', 1, function(' + id + ', ' + i + ', ' + len + ',next) {'); - this.emitLine('frame.set("' + id + '", ' + id + ');'); - frame.set(id, id); - } - - this.emitLoopBindings(node, loopUses, arr, i, len); - - this.withScopedSyntax(function() { - var buf; - if (parallel) { - buf = this.tmpid(); - this.pushBufferId(buf); - } - - this.compile(node.body, frame); - this.emitLine('next(' + i + (buf ? ',' + buf : '') + ');'); - - if (parallel) { - this.popBufferId(); - } - }); - - var output = this.tmpid(); - this.emitLine('}, ' + this.makeCallback(output)); - this.addScopeLevel(); - - if (parallel) { - this.emitLine(this.buffer + ' += ' + output + ';'); - } - - this.emitLine('frame = frame.pop();'); - }, - - compileAsyncEach: function(node, frame) { - this._compileAsyncLoop(node, frame); - }, - - compileAsyncAll: function(node, frame) { - this._compileAsyncLoop(node, frame, true); - }, - - _emitMacroBegin: function(node, frame) { - var args = []; - var kwargs = null; - var funcId = 'macro_' + this.tmpid(); - - // Type check the definition of the args - lib.each(node.args.children, function(arg, i) { - if (i === node.args.children.length - 1 && - arg instanceof nodes.Dict) { - kwargs = arg; - } else { - this.assertType(arg, nodes.Symbol); - args.push(arg); - } - }, this); - - var realNames = lib.map(args, function(n) { - return 'l_' + n.value; - }); - realNames.push('kwargs'); - - // Quoted argument names - var argNames = lib.map(args, function(n) { - return '"' + n.value + '"'; - }); - var kwargNames = lib.map((kwargs && kwargs.children) || [], - function(n) { - return '"' + n.key.value + '"'; - }); - - // We pass a function to makeMacro which destructures the - // arguments so support setting positional args with keywords - // args and passing keyword args as positional args - // (essentially default values). See runtime.js. - this.emitLines( - 'var ' + funcId + ' = runtime.makeMacro(', - '[' + argNames.join(', ') + '], ', - '[' + kwargNames.join(', ') + '], ', - 'function (' + realNames.join(', ') + ') {', - 'frame = frame.push();', - 'kwargs = kwargs || {};' - ); - - // Expose the arguments to the template. Don't need to use - // random names because the function - // will create a new run-time scope for us - lib.each(args, function(arg) { - this.emitLine('frame.set("' + arg.value + '", ' + - 'l_' + arg.value + ');'); - frame.set(arg.value, 'l_' + arg.value); - }, this); - - // Expose the keyword arguments - if (kwargs) { - lib.each(kwargs.children, function(pair) { - var name = pair.key.value; - this.emit('frame.set("' + name + '", ' + - 'kwargs.hasOwnProperty("' + name + '") ? ' + - 'kwargs["' + name + '"] : '); - this._compileExpression(pair.value, frame); - this.emitLine(');'); - }, this); - } - - return funcId; - }, - - _emitMacroEnd: function() { - this.emitLine('frame = frame.pop();'); - this.emitLine('return new runtime.SafeString(' + this.buffer + ');'); - this.emitLine('});'); - }, - - compileMacro: function(node, frame) { - frame = frame.push(); - var funcId = this._emitMacroBegin(node, frame); - - // Start a new output buffer, and set the old one back after - // we're done - var prevBuffer = this.buffer; - this.buffer = 'output'; - this.emitLine('var ' + this.buffer + '= "";'); - - this.compile(node.body, frame); - - this._emitMacroEnd(); - this.buffer = prevBuffer; - - // Expose the macro to the templates - var name = node.name.value; - frame = frame.pop(); - frame.set(name, funcId); - - if (frame.parent) { - this.emitLine('frame.set("' + name + '", ' + funcId + ');'); - } else { - if (node.name.value.charAt(0) != '_') { - this.emitLine('context.addExport("' + name + '");'); - } - this.emitLine('context.setVariable("' + name + '", ' + funcId + ');'); - } - }, - - compileImport: function(node, frame) { - var id = this.tmpid(); - var target = node.target.value; - - this.emit('env.getTemplate('); - this._compileExpression(node.template, frame); - this.emitLine(', ' + this.makeCallback(id)); - this.addScopeLevel(); - - this.emitLine(id + '.getExported(' + this.makeCallback(id)); - this.addScopeLevel(); - - frame.set(target, id); - - if (frame.parent) { - this.emitLine('frame.set("' + target + '", ' + id + ');'); - } else { - this.emitLine('context.setVariable("' + target + '", ' + id + ');'); - } - }, - - compileFromImport: function(node, frame) { - var importedId = this.tmpid(); - - this.emit('env.getTemplate('); - this._compileExpression(node.template, frame); - this.emitLine(', ' + this.makeCallback(importedId)); - this.addScopeLevel(); - - this.emitLine(importedId + '.getExported(' + this.makeCallback(importedId)); - this.addScopeLevel(); - - lib.each(node.names.children, function(nameNode) { - var name; - var alias; - var id = this.tmpid(); - - if (nameNode instanceof nodes.Pair) { - name = nameNode.key.value; - alias = nameNode.value.value; - } else { - name = nameNode.value; - alias = name; - } - - this.emitLine('if(' + importedId + '.hasOwnProperty("' + name + '")) {'); - this.emitLine('var ' + id + ' = ' + importedId + '.' + name + ';'); - this.emitLine('} else {'); - this.emitLine('cb(new Error("cannot import \'' + name + '\'")); return;'); - this.emitLine('}'); - - frame.set(alias, id); - - if (frame.parent) { - this.emitLine('frame.set("' + alias + '", ' + id + ');'); - } else { - this.emitLine('context.setVariable("' + alias + '", ' + id + ');'); - } - }, this); - }, - - compileBlock: function(node, frame) { - if (!this.isChild) { - var id = this.tmpid(); - - this.emitLine('context.getBlock("' + node.name.value + '")' + - '(env, context, frame, runtime, ' + this.makeCallback(id)); - this.emitLine(this.buffer + ' += ' + id + ';'); - this.addScopeLevel(); - } - }, - - compileSuper: function(node, frame) { - var name = node.blockName.value; - var id = node.symbol.value; - - this.emitLine('context.getSuper(env, ' + - '"' + name + '", ' + - 'b_' + name + ', ' + - 'frame, runtime, ' + - this.makeCallback(id)); - this.emitLine(id + ' = runtime.markSafe(' + id + ');'); - this.addScopeLevel(); - frame.set(id, id); - }, - - compileExtends: function(node, frame) { - if (this.isChild) { - this.fail('compileExtends: cannot extend multiple times', - node.template.lineno, - node.template.colno); - } - - var k = this.tmpid(); - - this.emit('env.getTemplate('); - this._compileExpression(node.template, frame); - this.emitLine(', true, ' + this.makeCallback('parentTemplate')); - - this.emitLine('for(var ' + k + ' in parentTemplate.blocks) {'); - this.emitLine('context.addBlock(' + k + - ', parentTemplate.blocks[' + k + ']);'); - this.emitLine('}'); - - this.addScopeLevel(); - this.isChild = true; - }, - - compileInclude: function(node, frame) { - var id = this.tmpid(); - var id2 = this.tmpid(); - - this.emit('env.getTemplate('); - this._compileExpression(node.template, frame); - this.emitLine(', ' + this.makeCallback(id)); - this.addScopeLevel(); - - this.emitLine(id + '.render(' + - 'context.getVariables(), frame.push(), ' + this.makeCallback(id2)); - this.emitLine(this.buffer + ' += ' + id2); - this.addScopeLevel(); - }, - - compileTemplateData: function(node, frame) { - this.compileLiteral(node, frame); - }, - - compileOutput: function(node, frame) { - var children = node.children; - for (var i = 0, l = children.length; i < l; i++) { - // TemplateData is a special case because it is never - // autoescaped, so simply output it for optimization - if (children[i] instanceof nodes.TemplateData) { - if (children[i].value) { - this.emit(this.buffer + ' += '); - this.compileLiteral(children[i], frame); - this.emitLine(';'); - } - } else { - this.emit(this.buffer + ' += runtime.suppressValue('); - this.compile(children[i], frame); - this.emit(', env.autoesc);\n'); - } - } - }, - - compileRoot: function(node, frame) { - if (frame) { - this.fail("compileRoot: root node can't have frame"); - } - - frame = new Frame(); - - this.emitFuncBegin('root'); - this._compileChildren(node, frame); - if (this.isChild) { - this.emitLine('parentTemplate.rootRenderFunc(env, context, frame, runtime, cb);'); - } - this.emitFuncEnd(this.isChild); - - // When compiling the blocks, they should all act as top-level code - this.isChild = false; - - var blocks = node.findAll(nodes.Block); - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; - var name = block.name.value; - - this.emitFuncBegin('b_' + name); - - var tmpFrame = new Frame(); - this.compile(block.body, tmpFrame); - this.emitFuncEnd(); - } - - this.emitLine('return {'); - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; - var name = 'b_' + block.name.value; - this.emitLine(name + ': ' + name + ','); - } - this.emitLine('root: root\n};'); - }, - - compile: function(node, frame) { - var _compile = this["compile" + node.typename]; - if (_compile) { - _compile.call(this, node, frame); - } else { - this.fail("compile: Cannot compile node: " + node.typename, - node.lineno, - node.colno); - } - }, - - getCode: function() { - return this.codebuf.join(''); - } - }); - - // var c = new Compiler(); - // var src = 'hello {% foo %}bar{% endfoo %} end'; - // var ast = transformer.transform(parser.parse(src)); - // nodes.printNodes(ast); - // c.compile(ast); - // var tmpl = c.getCode(); - // console.log(tmpl); - - modules['compiler'] = { - compile: function(src, asyncFilters, extensions, name) { - var c = new Compiler(); - - // Run the extension preprocessors against the source. - if (extensions && extensions.length) { - for (var i = 0; i < extensions.length; i++) { - if ('preprocess' in extensions[i]) { - src = extensions[i].preprocess(src, name); - } - } - } - - c.compile(transformer.transform(parser.parse(src, extensions), - asyncFilters, - name)); - return c.getCode(); - }, - - Compiler: Compiler - }; - })(); - (function() { - - var lib = modules["lib"]; - var r = modules["runtime"]; - - var filters = { - abs: function(n) { - return Math.abs(n); - }, - - batch: function(arr, linecount, fill_with) { - var res = []; - var tmp = []; - - for (var i = 0; i < arr.length; i++) { - if (i % linecount === 0 && tmp.length) { - res.push(tmp); - tmp = []; - } - - tmp.push(arr[i]); - } - - if (tmp.length) { - if (fill_with) { - for (var i = tmp.length; i < linecount; i++) { - tmp.push(fill_with); - } - } - - res.push(tmp); - } - - return res; - }, - - capitalize: function(str) { - var ret = str.toLowerCase(); - return r.copySafeness(str, ret.charAt(0).toUpperCase() + ret.slice(1)); - }, - - center: function(str, width) { - width = width || 80; - - if (str.length >= width) { - return str; - } - - var spaces = width - str.length; - var pre = lib.repeat(" ", spaces / 2 - spaces % 2); - var post = lib.repeat(" ", spaces / 2); - return r.copySafeness(str, pre + str + post); - }, - - 'default': function(val, def) { - return val ? val : def; - }, - - dictsort: function(val, case_sensitive, by) { - if (!lib.isObject(val)) { - throw new lib.TemplateError("dictsort filter: val must be an object"); - } - - var array = []; - for (var k in val) { - // deliberately include properties from the object's prototype - array.push([k, val[k]]); - } - - var si; - if (by === undefined || by === "key") { - si = 0; - } else if (by === "value") { - si = 1; - } else { - throw new lib.TemplateError( - "dictsort filter: You can only sort by either key or value"); - } - - array.sort(function(t1, t2) { - var a = t1[si]; - var b = t2[si]; - - if (!case_sensitive) { - if (lib.isString(a)) { - a = a.toUpperCase(); - } - if (lib.isString(b)) { - b = b.toUpperCase(); - } - } - - return a > b ? 1 : (a == b ? 0 : -1); - }); - - return array; - }, - - escape: function(str) { - if (typeof str == 'string' || - str instanceof r.SafeString) { - return lib.escape(str); - } - return str; - }, - - safe: function(str) { - return r.markSafe(str); - }, - - first: function(arr) { - return arr[0]; - }, - - groupby: function(arr, attr) { - return lib.groupBy(arr, attr); - }, - - indent: function(str, width, indentfirst) { - width = width || 4; - var res = ''; - var lines = str.split('\n'); - var sp = lib.repeat(' ', width); - - for (var i = 0; i < lines.length; i++) { - if (i == 0 && !indentfirst) { - res += lines[i] + '\n'; - } else { - res += sp + lines[i] + '\n'; - } - } - - return r.copySafeness(str, res); - }, - - join: function(arr, del, attr) { - del = del || ''; - - if (attr) { - arr = lib.map(arr, function(v) { - return v[attr]; - }); - } - - return arr.join(del); - }, - - last: function(arr) { - return arr[arr.length - 1]; - }, - - length: function(arr) { - return arr.length; - }, - - list: function(val) { - if (lib.isString(val)) { - return val.split(''); - } else if (lib.isObject(val)) { - var keys = []; - - if (Object.keys) { - keys = Object.keys(val); - } else { - for (var k in val) { - keys.push(k); - } - } - - return lib.map(keys, function(k) { - return { - key: k, - value: val[k] - }; - }); - } else { - throw new lib.TemplateError("list filter: type not iterable"); - } - }, - - lower: function(str) { - return str.toLowerCase(); - }, - - random: function(arr) { - return arr[Math.floor(Math.random() * arr.length)]; - }, - - replace: function(str, old, new_, maxCount) { - var res = str; - var last = res; - var count = 1; - res = res.replace(old, new_); - - while (last != res) { - if (count >= maxCount) { - break; - } - - last = res; - res = res.replace(old, new_); - count++; - } - - return r.copySafeness(str, res); - }, - - reverse: function(val) { - var arr; - if (lib.isString(val)) { - arr = filters.list(val); - } else { - // Copy it - arr = lib.map(val, function(v) { - return v; - }); - } - - arr.reverse(); - - if (lib.isString(val)) { - return r.copySafeness(val, arr.join('')); - } - return arr; - }, - - round: function(val, precision, method) { - precision = precision || 0; - var factor = Math.pow(10, precision); - var rounder; - - if (method == 'ceil') { - rounder = Math.ceil; - } else if (method == 'floor') { - rounder = Math.floor; - } else { - rounder = Math.round; - } - - return rounder(val * factor) / factor; - }, - - slice: function(arr, slices, fillWith) { - var sliceLength = Math.floor(arr.length / slices); - var extra = arr.length % slices; - var offset = 0; - var res = []; - - for (var i = 0; i < slices; i++) { - var start = offset + i * sliceLength; - if (i < extra) { - offset++; - } - var end = offset + (i + 1) * sliceLength; - - var slice = arr.slice(start, end); - if (fillWith && i >= extra) { - slice.push(fillWith); - } - res.push(slice); - } - - return res; - }, - - sort: function(arr, reverse, caseSens, attr) { - // Copy it - arr = lib.map(arr, function(v) { - return v; - }); - - arr.sort(function(a, b) { - var x, - y; - - if (attr) { - x = a[attr]; - y = b[attr]; - } else { - x = a; - y = b; - } - - if (!caseSens && lib.isString(x) && lib.isString(y)) { - x = x.toLowerCase(); - y = y.toLowerCase(); - } - - if (x < y) { - return reverse ? 1 : -1; - } else if (x > y) { - return reverse ? -1 : 1; - } else { - return 0; - } - }); - - return arr; - }, - - string: function(obj) { - return r.copySafeness(obj, obj); - }, - - title: function(str) { - var words = str.split(' '); - for (var i = 0; i < words.length; i++) { - words[i] = filters.capitalize(words[i]); - } - return r.copySafeness(str, words.join(' ')); - }, - - trim: function(str) { - return r.copySafeness(str, str.replace(/^\s*|\s*$/g, '')); - }, - - truncate: function(input, length, killwords, end) { - var orig = input; - length = length || 255; - - if (input.length <= length) { - return input; - } - - if (killwords) { - input = input.substring(0, length); - } else { - var idx = input.lastIndexOf(' ', length); - if (idx === -1) { - idx = length; - } - - input = input.substring(0, idx); - } - - input += (end !== undefined && end !== null) ? end : '...'; - return r.copySafeness(orig, input); - }, - - upper: function(str) { - return str.toUpperCase(); - }, - - urlencode: function(obj) { - var enc = encodeURIComponent; - if (lib.isString(obj)) { - return enc(obj); - } else { - var parts; - if (lib.isArray(obj)) { - parts = obj.map(function(item) { - return enc(item[0]) + '=' + enc(item[1]); - }) - } else { - parts = []; - for (var k in obj) { - if (obj.hasOwnProperty(k)) { - parts.push(enc(k) + '=' + enc(obj[k])); - } - } - } - return parts.join('&'); - } - }, - - wordcount: function(str) { - return str.match(/\w+/g).length; - }, - - 'float': function(val, def) { - var res = parseFloat(val); - return isNaN(res) ? def : res; - }, - - 'int': function(val, def) { - var res = parseInt(val, 10); - return isNaN(res) ? def : res; - } - }; - - // Aliases - filters.d = filters['default']; - filters.e = filters.escape; - - modules['filters'] = filters; - })(); - (function() { - - function cycler(items) { - var index = -1; - var current = null; - - return { - reset: function() { - index = -1; - current = null; - }, - - next: function() { - index++; - if (index >= items.length) { - index = 0; - } - - current = items[index]; - return current; - } - }; - - } - - function joiner(sep) { - sep = sep || ','; - var first = true; - - return function() { - var val = first ? '' : sep; - first = false; - return val; - }; - } - - var globals = { - range: function(start, stop, step) { - if (!stop) { - stop = start; - start = 0; - step = 1; - } else if (!step) { - step = 1; - } - - var arr = []; - for (var i = start; i < stop; i += step) { - arr.push(i); - } - return arr; - }, - - // lipsum: function(n, html, min, max) { - // }, - - cycler: function() { - return cycler(Array.prototype.slice.call(arguments)); - }, - - joiner: function(sep) { - return joiner(sep); - } - } - - modules['globals'] = globals; - })(); - (function() { - var Obj = modules["object"]; - var lib = modules["lib"]; - - var Loader = Obj.extend({ - on: function(name, func) { - this.listeners = this.listeners || {}; - this.listeners[name] = this.listeners[name] || []; - this.listeners[name].push(func); - }, - - emit: function(name /*, arg1, arg2, ...*/ ) { - var args = Array.prototype.slice.call(arguments, 1); - - if (this.listeners && this.listeners[name]) { - lib.each(this.listeners[name], function(listener) { - listener.apply(null, args); - }); - } - } - }); - - modules['loader'] = Loader; - })(); - (function() { - var Loader = modules["loader"]; - - var WebLoader = Loader.extend({ - init: function(baseURL, neverUpdate) { - // It's easy to use precompiled templates: just include them - // before you configure nunjucks and this will automatically - // pick it up and use it - this.precompiled = window.nunjucksPrecompiled || {}; - - this.baseURL = baseURL || ''; - this.neverUpdate = neverUpdate; - }, - - getSource: function(name) { - if (this.precompiled[name]) { - return { - src: { - type: "code", - obj: this.precompiled[name] - }, - path: name - }; - } else { - var src = this.fetch(this.baseURL + '/' + name); - if (!src) { - return null; - } - - return { - src: src, - path: name, - noCache: this.neverUpdate - }; - } - }, - - fetch: function(url, callback) { - // Only in the browser please - var ajax; - var loading = true; - var src; - - if (window.XMLHttpRequest) { // Mozilla, Safari, ... - ajax = new XMLHttpRequest(); - } else if (window.ActiveXObject) { // IE 8 and older - ajax = new ActiveXObject("Microsoft.XMLHTTP"); - } - - ajax.onreadystatechange = function() { - if (ajax.readyState == 4 && ajax.status == 200 && loading) { - loading = false; - src = ajax.responseText; - } - }; - - url += (url.indexOf('?') === -1 ? '?' : '&') + 's=' + - (new Date().getTime()); - - // Synchronous because this API shouldn't be used in - // production (pre-load compiled templates instead) - ajax.open('GET', url, false); - ajax.send(); - - return src; - } - }); - - modules['web-loaders'] = { - WebLoader: WebLoader - }; - })(); - (function() { - if (typeof window === 'undefined') { - modules['loaders'] = modules["node-loaders"]; - } else { - modules['loaders'] = modules["web-loaders"]; - } - })(); - (function() { - var lib = modules["lib"]; - var Obj = modules["object"]; - var lexer = modules["lexer"]; - var compiler = modules["compiler"]; - var builtin_filters = modules["filters"]; - var builtin_loaders = modules["loaders"]; - var runtime = modules["runtime"]; - var globals = modules["globals"]; - var Frame = runtime.Frame; - - var Environment = Obj.extend({ - init: function(loaders, opts) { - // The dev flag determines the trace that'll be shown on errors. - // If set to true, returns the full trace from the error point, - // otherwise will return trace starting from Template.render - // (the full trace from within nunjucks may confuse developers using - // the library) - // defaults to false - opts = opts || {}; - this.dev = !!opts.dev; - - // The autoescape flag sets global autoescaping. If true, - // every string variable will be escaped by default. - // If false, strings can be manually escaped using the `escape` filter. - // defaults to false - this.autoesc = !!opts.autoescape; - - if (!loaders) { - // The filesystem loader is only available client-side - if (builtin_loaders.FileSystemLoader) { - this.loaders = [new builtin_loaders.FileSystemLoader('views')]; - } else { - this.loaders = [new builtin_loaders.WebLoader('/views')]; - } - } else { - this.loaders = lib.isArray(loaders) ? loaders : [loaders]; - } - - this.initCache(); - this.filters = {}; - this.asyncFilters = []; - this.extensions = {}; - this.extensionsList = []; - - if (opts.tags) { - lexer.setTags(opts.tags); - } - - for (var name in builtin_filters) { - this.addFilter(name, builtin_filters[name]); - } - }, - - initCache: function() { - // Caching and cache busting - var cache = {}; - - lib.each(this.loaders, function(loader) { - loader.on('update', function(template) { - cache[template] = null; - }); - }); - - this.cache = cache; - }, - - addExtension: function(name, extension) { - extension._name = name; - this.extensions[name] = extension; - this.extensionsList.push(extension); - }, - - getExtension: function(name) { - return this.extensions[name]; - }, - - addFilter: function(name, func, async) { - var wrapped = func; - - if (async) { - this.asyncFilters.push(name); - } - this.filters[name] = wrapped; - }, - - getFilter: function(name) { - if (!this.filters[name]) { - throw new Error('filter not found: ' + name); - } - return this.filters[name]; - }, - - getTemplate: function(name, eagerCompile, cb) { - if (name && name.raw) { - // this fixes autoescape for templates referenced in symbols - name = name.raw; - } - - if (lib.isFunction(eagerCompile)) { - cb = eagerCompile; - eagerCompile = false; - } - - if (typeof name !== 'string') { - throw new Error('template names must be a string: ' + name); - } - - var tmpl = this.cache[name]; - - if (tmpl) { - cb(null, tmpl); - } else { - lib.asyncIter(this.loaders, function(loader, i, next, done) { - function handle(src) { - if (src) { - done(src); - } else { - next(); - } - } - - if (loader.async) { - loader.getSource(name, function(err, src) { - if (err) { - throw err; - } - handle(src); - }); - } else { - handle(loader.getSource(name)); - } - }, function(info) { - if (!info) { - cb(new Error('template not found: ' + name)); - } else { - var tmpl = new Template(info.src, this, - info.path, eagerCompile); - - if (!info.noCache) { - this.cache[name] = tmpl; - } - - cb(null, tmpl); - } - }.bind(this)); - } - }, - - express: function(app) { - var env = this; - - function NunjucksView(name, opts) { - this.name = name; - this.path = name; - } - - NunjucksView.prototype.render = function(opts, cb) { - env.render(this.name, opts, cb); - }; - - app.set('view', NunjucksView); - }, - - render: function(name, ctx, cb) { - if (lib.isFunction(ctx)) { - cb = ctx; - ctx = null; - } - - // We support a synchronous API to make it easier to migrate - // existing code to async. This works because if you don't do - // anything async work, the whole thing is actually run - // synchronously. - var syncResult = null; - - this.getTemplate(name, function(err, tmpl) { - if (err) { - cb(err); - } else { - tmpl.render(ctx, cb || function(err, res) { - if (err) { - throw err; - } - syncResult = res; - }); - } - }); - - return syncResult; - } - }); - - var Context = Obj.extend({ - init: function(ctx, blocks) { - this.ctx = ctx; - this.blocks = {}; - this.exported = []; - - for (var name in blocks) { - this.addBlock(name, blocks[name]); - } - }, - - lookup: function(name) { - // This is one of the most called functions, so optimize for - // the typical case where the name isn't in the globals - if (name in globals && !(name in this.ctx)) { - return globals[name]; - } else { - return this.ctx[name]; - } - }, - - setVariable: function(name, val) { - this.ctx[name] = val; - }, - - getVariables: function() { - return this.ctx; - }, - - addBlock: function(name, block) { - this.blocks[name] = this.blocks[name] || []; - this.blocks[name].push(block); - }, - - getBlock: function(name) { - if (!this.blocks[name]) { - throw new Error('unknown block "' + name + '"'); - } - - return this.blocks[name][0]; - }, - - getSuper: function(env, name, block, frame, runtime, cb) { - var idx = (this.blocks[name] || []).indexOf(block); - var blk = this.blocks[name][idx + 1]; - var context = this; - - if (idx == -1 || !blk) { - throw new Error('no super block available for "' + name + '"'); - } - - blk(env, context, frame, runtime, cb); - }, - - addExport: function(name) { - this.exported.push(name); - }, - - getExported: function() { - var exported = {}; - for (var i = 0; i < this.exported.length; i++) { - var name = this.exported[i]; - exported[name] = this.ctx[name]; - } - return exported; - } - }); - - var Template = Obj.extend({ - init: function(src, env, path, eagerCompile) { - this.env = env || new Environment(); - - if (lib.isObject(src)) { - switch (src.type) { - case 'code': - this.tmplProps = src.obj; - break; - case 'string': - this.tmplStr = src.obj; - break; - } - } else if (lib.isString(src)) { - this.tmplStr = src; - } else { - throw new Error("src must be a string or an object describing " + - "the source"); - } - - this.path = path; - - if (eagerCompile) { - lib.withPrettyErrors(this.path, - this.env.dev, - this._compile.bind(this)); - } else { - this.compiled = false; - } - }, - - render: function(ctx, frame, cb) { - if (typeof ctx === 'function') { - cb = ctx; - ctx = {}; - } else if (typeof frame === 'function') { - cb = frame; - frame = null; - } - - return lib.withPrettyErrors(this.path, this.env.dev, function() { - if (!this.compiled) { - this._compile(); - } - - var context = new Context(ctx || {}, this.blocks); - var syncResult = null; - - this.rootRenderFunc(this.env, - context, - frame || new Frame(), - runtime, - cb || function(err, res) { - if (err) { - throw err; - } - syncResult = res; - }); - - return syncResult; - }.bind(this)); - }, - - getExported: function(cb) { - if (!this.compiled) { - this._compile(); - } - - // Run the rootRenderFunc to populate the context with exported vars - var context = new Context({}, this.blocks); - this.rootRenderFunc(this.env, - context, - new Frame(), - runtime, - function() { - cb(null, context.getExported()); - }); - }, - - _compile: function() { - var props; - - if (this.tmplProps) { - props = this.tmplProps; - } else { - var source = compiler.compile(this.tmplStr, - this.env.asyncFilters, - this.env.extensionsList, - this.path); - var func = new Function(source); - props = func(); - } - - this.blocks = this._getBlocks(props); - this.rootRenderFunc = props.root; - this.compiled = true; - }, - - _getBlocks: function(props) { - var blocks = {}; - - for (var k in props) { - if (k.slice(0, 2) == 'b_') { - blocks[k.slice(2)] = props[k]; - } - } - - return blocks; - } - }); - - // test code - // var src = 'hello {% foo baz | bar %}hi{% endfoo %} end'; - // var env = new Environment(new builtin_loaders.FileSystemLoader('tests/templates', true), { dev: true }); - - // function FooExtension() { - // this.tags = ['foo']; - // this._name = 'FooExtension'; - - // this.parse = function(parser, nodes) { - // var tok = parser.nextToken(); - // var args = parser.parseSignature(null, true); - // parser.advanceAfterBlockEnd(tok.value); - - // var body = parser.parseUntilBlocks('endfoo'); - // parser.advanceAfterBlockEnd(); - - // return new nodes.CallExtensionAsync(this, 'run', args, [body]); - // }; - - // this.run = function(context, baz, body, cb) { - // cb(null, baz + '--' + body()); - // }; - // } - - // env.addExtension('FooExtension', new FooExtension()); - // env.addFilter('bar', function(val, cb) { - // cb(null, val + '22222'); - // }, true); - - // var ctx = {}; - // var tmpl = new Template(src, env, null, null, true); - // console.log("OUTPUT ---"); - - // tmpl.render(ctx, function(err, res) { - // if(err) { - // throw err; - // } - // console.log(res); - // }); - - modules['environment'] = { - Environment: Environment, - Template: Template - }; - })(); - var nunjucks; - - var lib = modules["lib"]; - var env = modules["environment"]; - var compiler = modules["compiler"]; - var parser = modules["parser"]; - var lexer = modules["lexer"]; - var runtime = modules["runtime"]; - var Loader = modules["loader"]; - var loaders = modules["loaders"]; - var precompile = modules["precompile"]; - - nunjucks = {}; - nunjucks.Environment = env.Environment; - nunjucks.Template = env.Template; - - nunjucks.Loader = env.Loader; - nunjucks.FileSystemLoader = loaders.FileSystemLoader; - nunjucks.WebLoader = loaders.WebLoader; - - nunjucks.compiler = compiler; - nunjucks.parser = parser; - nunjucks.lexer = lexer; - nunjucks.runtime = runtime; - - // A single instance of an environment, since this is so commonly used - - var e; - nunjucks.configure = function(templatesPath, opts) { - opts = opts || {}; - if (lib.isObject(templatesPath)) { - opts = templatesPath; - } else { - opts.templatesPath = templatesPath; - } - - var loader = loaders.FileSystemLoader || loaders.WebLoader; - e = new env.Environment(new loader(opts.templatesPath, opts.watch), opts); - - if (opts && opts.express) { - e.express(opts.express); - } - - return e; - }; - - nunjucks.render = function(name, ctx, cb) { - if (!e) { - nunjucks.configure(); - } - - return e.render(name, ctx, cb); - }; - - nunjucks.precompile = precompile; - - nunjucks.require = function(name) { - return modules[name]; - }; - - if (typeof define === 'function' && define.amd) { - define(function() { - return nunjucks; - }); - } else { - window.nunjucks = nunjucks; - } - -})(); diff --git a/tests/express-sample/js/nunjucks-min.js b/tests/express-sample/js/nunjucks-min.js deleted file mode 100644 index d9506b79..00000000 --- a/tests/express-sample/js/nunjucks-min.js +++ /dev/null @@ -1,1284 +0,0 @@ -(function() { - var modules = {}; - (function() { - function extend(cls, name, props) { - var F = function() {}; - F.prototype = cls.prototype;var prototype = new F; - var fnTest = /xyz/.test(function() { - xyz - }) ? /\bparent\b/ : /.*/; - props = props || {}; - for (var k in props) { - var src = props[k]; - var parent = prototype[k]; - if (typeof parent == "function" && typeof src == "function" && fnTest.test(src)) { - prototype[k] = function(src, parent) { - return function() { - var tmp = this.parent; - this.parent = parent; - var res = src.apply(this, arguments); - this.parent = tmp;return res - } - }(src, parent) - } else { - prototype[k] = src - } - } - prototype.typename = name;var new_cls = function() { - if (prototype.init) { - prototype.init.apply(this, arguments) - } - }; - new_cls.prototype = prototype; - new_cls.prototype.constructor = new_cls; - new_cls.extend = function(name, props) { - if (typeof name == "object") { - props = name; - name = "anonymous" - } - return extend(new_cls, name, props) - };return new_cls - } - modules["object"] = extend(Object, "Object", {}) - })();(function() { - var ArrayProto = Array.prototype; - var ObjProto = Object.prototype; - var escapeMap = { - "&": "&", - '"': """, - "'": "'", - "<": "<", - ">": ">" - }; - var lookupEscape = function(ch) { - return escapeMap[ch] - }; - var exports = modules["lib"] = {}; - exports.withPrettyErrors = function(path, withInternals, func) { - try { - return func() - } catch (e) { - if (!e.Update) { - e = new exports.TemplateError(e) - } - e.Update(path); - if (!withInternals) { - var old = e; - e = new Error(old.message); - e.name = old.name - } - throw e - } - }; - exports.TemplateError = function(message, lineno, colno) { - var err = this; - if (message instanceof Error) { - err = message; - message = message.name + ": " + message.message - } else { - if (Error.captureStackTrace) { - Error.captureStackTrace(err) - } - } - err.name = "Template render error"; - err.message = message; - err.lineno = lineno; - err.colno = colno; - err.firstUpdate = true; - err.Update = function(path) { - var message = "(" + (path || "unknown path") + ")"; - if (this.firstUpdate) { - if (this.lineno && this.colno) { - message += " [Line " + this.lineno + ", Column " + this.colno + "]" - } else if (this.lineno) { - message += " [Line " + this.lineno + "]" - } - } - message += "\n "; - if (this.firstUpdate) { - message += " " - } - this.message = message + (this.message || ""); - this.firstUpdate = false;return this - };return err - }; - exports.TemplateError.prototype = Error.prototype; - exports.escape = function(val) { - return val.replace(/[&"'<>]/g, lookupEscape) - }; - exports.isFunction = function(obj) { - return ObjProto.toString.call(obj) == "[object Function]" - }; - exports.isArray = Array.isArray || function(obj) { - return ObjProto.toString.call(obj) == "[object Array]" - }; - exports.isString = function(obj) { - return ObjProto.toString.call(obj) == "[object String]" - }; - exports.isObject = function(obj) { - return obj === Object(obj) - }; - exports.groupBy = function(obj, val) { - var result = {}; - var iterator = exports.isFunction(val) ? val : function(obj) { - return obj[val] - }; - for (var i = 0; i < obj.length; i++) { - var value = obj[i]; - var key = iterator(value, i); - (result[key] || (result[key] = [])).push(value) - } - return result - }; - exports.toArray = function(obj) { - return Array.prototype.slice.call(obj) - }; - exports.without = function(array) { - var result = []; - if (!array) { - return result - } - var index = -1, - length = array.length, - contains = exports.toArray(arguments).slice(1); - while (++index < length) { - if (contains.indexOf(array[index]) === -1) { - result.push(array[index]) - } - } - return result - }; - exports.extend = function(obj, obj2) { - for (var k in obj2) { - obj[k] = obj2[k] - } - return obj - }; - exports.repeat = function(char_, n) { - var str = ""; - for (var i = 0; i < n; i++) { - str += char_ - } - return str - }; - exports.each = function(obj, func, context) { - if (obj == null) { - return - } - if (ArrayProto.each && obj.each == ArrayProto.each) { - obj.forEach(func, context) - } else if (obj.length === +obj.length) { - for (var i = 0, l = obj.length; i < l; i++) { - func.call(context, obj[i], i, obj) - } - } - }; - exports.map = function(obj, func) { - var results = []; - if (obj == null) { - return results - } - if (ArrayProto.map && obj.map === ArrayProto.map) { - return obj.map(func) - } - for (var i = 0; i < obj.length; i++) { - results[results.length] = func(obj[i], i) - } - if (obj.length === +obj.length) { - results.length = obj.length - } - return results - }; - exports.asyncParallel = function(funcs, done) { - var count = funcs.length, - result = new Array(count), - current = 0; - var makeNext = function(i) { - return function(res) { - result[i] = res; - current += 1; - if (current === count) { - done(result) - } - } - }; - for (var i = 0; i < count; i++) { - funcs[i](makeNext(i)) - } - }; - exports.asyncIter = function(arr, iter, cb) { - var i = -1; - function next() { - i++; - if (i < arr.length) { - iter(arr[i], i, next, cb) - } else { - cb() - } - } - next() - }; - exports.asyncFor = function(obj, iter, cb) { - var keys = exports.keys(obj); - var len = keys.length; - var i = -1; - function next() { - i++;var k = keys[i]; - if (i < len) { - iter(k, obj[k], i, len, next) - } else { - cb() - } - } - next() - }; - if (!Array.prototype.indexOf) { - Array.prototype.indexOf = function(array, searchElement) { - if (array == null) { - throw new TypeError - } - var t = Object(array); - var len = t.length >>> 0; - if (len === 0) { - return -1 - } - var n = 0; - if (arguments.length > 2) { - n = Number(arguments[2]); - if (n != n) { - n = 0 - } else if (n != 0 && n != Infinity && n != -Infinity) { - n = (n > 0 || -1) * Math.floor(Math.abs(n)) - } - } - if (n >= len) { - return -1 - } - var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); - for (; k < len; k++) { - if (k in t && t[k] === searchElement) { - return k - } - } - return -1 - } - } - if (!Array.prototype.map) { - Array.prototype.map = function() { - throw new Error("map is unimplemented for this js engine") - } - } - exports.keys = function(obj) { - if (Object.prototype.keys) { - return obj.keys() - } else { - var keys = []; - for (var k in obj) { - if (obj.hasOwnProperty(k)) { - keys.push(k) - } - } - return keys - } - } - })();(function() { - var lib = modules["lib"]; - var Object = modules["object"]; - var Frame = Object.extend({ - init: function(parent) { - this.variables = {}; - this.parent = parent - }, - set: function(name, val) { - var parts = name.split("."); - var obj = this.variables; - for (var i = 0; i < parts.length - 1; i++) { - var id = parts[i]; - if (!obj[id]) { - obj[id] = {} - } - obj = obj[id] - } - obj[parts[parts.length - 1]] = val - }, - get: function(name) { - var val = this.variables[name]; - if (val !== undefined && val !== null) { - return val - } - return null - }, - lookup: function(name) { - var p = this.parent; - var val = this.variables[name]; - if (val !== undefined && val !== null) { - return val - } - return p && p.lookup(name) - }, - push: function() { - return new Frame(this) - }, - pop: function() { - return this.parent - } - }); - function makeMacro(argNames, kwargNames, func) { - return function() { - var argCount = numArgs(arguments); - var args; - var kwargs = getKeywordArgs(arguments); - if (argCount > argNames.length) { - args = Array.prototype.slice.call(arguments, 0, argNames.length); - var vals = Array.prototype.slice.call(arguments, args.length, argCount); - for (var i = 0; i < vals.length; i++) { - if (i < kwargNames.length) { - kwargs[kwargNames[i]] = vals[i] - } - } - args.push(kwargs) - } else if (argCount < argNames.length) { - args = Array.prototype.slice.call(arguments, 0, argCount); - for (var i = argCount; i < argNames.length; i++) { - var arg = argNames[i]; - args.push(kwargs[arg]); - delete kwargs[arg] - } - args.push(kwargs) - } else { - args = arguments - } - return func.apply(this, args) - } - } - function makeKeywordArgs(obj) { - obj.__keywords = true;return obj - } - function getKeywordArgs(args) { - var len = args.length; - if (len) { - var lastArg = args[len - 1]; - if (lastArg && lastArg.hasOwnProperty("__keywords")) { - return lastArg - } - } - return {} - } - function numArgs(args) { - var len = args.length; - if (len === 0) { - return 0 - } - var lastArg = args[len - 1]; - if (lastArg && lastArg.hasOwnProperty("__keywords")) { - return len - 1 - } else { - return len - } - } - function SafeString(val) { - if (typeof val != "string") { - return val - } - this.toString = function() { - return val - }; - this.length = val.length;var methods = ["charAt", "charCodeAt", "concat", "contains", "endsWith", "fromCharCode", "indexOf", "lastIndexOf", "length", "localeCompare", "match", "quote", "replace", "search", "slice", "split", "startsWith", "substr", "substring", "toLocaleLowerCase", "toLocaleUpperCase", "toLowerCase", "toUpperCase", "trim", "trimLeft", "trimRight"]; - for (var i = 0; i < methods.length; i++) { - this[methods[i]] = markSafe(val[methods[i]]) - } - } - function copySafeness(dest, target) { - if (dest instanceof SafeString) { - return new SafeString(target) - } - return target.toString() - } - function markSafe(val) { - var type = typeof val; - if (type === "string") { - return new SafeString(val) - } else if (type !== "function") { - return val - } else { - return function() { - var ret = val.apply(this, arguments); - if (typeof ret === "string") { - return new SafeString(ret) - } - return ret - } - } - } - function suppressValue(val, autoescape) { - val = val !== undefined && val !== null ? val : ""; - if (autoescape && typeof val === "string") { - val = lib.escape(val) - } - return val - } - function memberLookup(obj, val) { - obj = obj || {}; - if (typeof obj[val] === "function") { - return function() { - return obj[val].apply(obj, arguments) - } - } - return obj[val] - } - function callWrap(obj, name, args) { - if (!obj) { - throw new Error("Unable to call `" + name + "`, which is undefined or falsey") - } else if (typeof obj !== "function") { - throw new Error("Unable to call `" + name + "`, which is not a function") - } - return obj.apply(this, args) - } - function contextOrFrameLookup(context, frame, name) { - var val = frame.lookup(name); - return val !== undefined && val !== null ? val : context.lookup(name) - } - function handleError(error, lineno, colno) { - if (error.lineno) { - return error - } else { - return new lib.TemplateError(error, lineno, colno) - } - } - function asyncEach(arr, dimen, iter, cb) { - if (lib.isArray(arr)) { - var len = arr.length; - lib.asyncIter(arr, function(item, i, next) { - switch (dimen) { - case 1: - iter(item, i, len, next); - break;case 2: - iter(item[0], item[1], i, len, next); - break;case 3: - iter(item[0], item[1], item[2], i, len, next); - break;default: - item.push(i, next);iter.apply(this, item) - } - }, cb) - } else { - lib.asyncFor(arr, function(key, val, i, len, next) { - iter(key, val, i, len, next) - }, cb) - } - } - function asyncAll(arr, dimen, func, cb) { - var finished = 0; - var len; - var outputArr; - function done(i, output) { - finished++; - outputArr[i] = output; - if (finished == len) { - cb(null, outputArr.join("")) - } - } - if (lib.isArray(arr)) { - len = arr.length; - outputArr = new Array(len); - if (len == 0) { - cb(null, "") - } else { - for (var i = 0; i < arr.length; i++) { - var item = arr[i]; - switch (dimen) { - case 1: - func(item, i, len, done); - break;case 2: - func(item[0], item[1], i, len, done); - break;case 3: - func(item[0], item[1], item[2], i, len, done); - break;default: - item.push(i, done);func.apply(this, item) - } - } - } - } else { - var keys = lib.keys(arr); - len = keys.length; - outputArr = new Array(len); - if (len == 0) { - cb(null, "") - } else { - for (var i = 0; i < keys.length; i++) { - var k = keys[i]; - func(k, arr[k], i, len, done) - } - } - } - } - modules["runtime"] = { - Frame: Frame, - makeMacro: makeMacro, - makeKeywordArgs: makeKeywordArgs, - numArgs: numArgs, - suppressValue: suppressValue, - memberLookup: memberLookup, - contextOrFrameLookup: contextOrFrameLookup, - callWrap: callWrap, - handleError: handleError, - isArray: lib.isArray, - asyncEach: lib.asyncEach, - keys: lib.keys, - SafeString: SafeString, - copySafeness: copySafeness, - markSafe: markSafe, - asyncEach: asyncEach, - asyncAll: asyncAll - } - })();(function() { - var Obj = modules["object"]; - var lib = modules["lib"]; - var Loader = Obj.extend({ - on: function(name, func) { - this.listeners = this.listeners || {}; - this.listeners[name] = this.listeners[name] || [];this.listeners[name].push(func) - }, - emit: function(name) { - var args = Array.prototype.slice.call(arguments, 1); - if (this.listeners && this.listeners[name]) { - lib.each(this.listeners[name], function(listener) { - listener.apply(null, args) - }) - } - } - }); - modules["loader"] = Loader - })();(function() { - var Loader = modules["loader"]; - var WebLoader = Loader.extend({ - init: function(baseURL, neverUpdate) { - this.precompiled = window.nunjucksPrecompiled || {}; - this.baseURL = baseURL || ""; - this.neverUpdate = neverUpdate - }, - getSource: function(name) { - if (this.precompiled[name]) { - return { - src: { - type: "code", - obj: this.precompiled[name] - }, - path: name - } - } else { - var src = this.fetch(this.baseURL + "/" + name); - if (!src) { - return null - } - return { - src: src, - path: name, - noCache: this.neverUpdate - } - } - }, - fetch: function(url, callback) { - var ajax; - var loading = true; - var src; - if (window.XMLHttpRequest) { - ajax = new XMLHttpRequest - } else if (window.ActiveXObject) { - ajax = new ActiveXObject("Microsoft.XMLHTTP") - } - ajax.onreadystatechange = function() { - if (ajax.readyState == 4 && ajax.status == 200 && loading) { - loading = false; - src = ajax.responseText - } - }; - url += (url.indexOf("?") === -1 ? "?" : "&") + "s=" + (new Date).getTime();ajax.open("GET", url, false);ajax.send();return src - } - }); - modules["web-loaders"] = { - WebLoader: WebLoader - } - })();(function() { - if (typeof window === "undefined") { - modules["loaders"] = modules["node-loaders"] - } else { - modules["loaders"] = modules["web-loaders"] - } - })();(function() { - var lib = modules["lib"]; - var r = modules["runtime"]; - var filters = { - abs: function(n) { - return Math.abs(n) - }, - batch: function(arr, linecount, fill_with) { - var res = []; - var tmp = []; - for (var i = 0; i < arr.length; i++) { - if (i % linecount === 0 && tmp.length) { - res.push(tmp); - tmp = [] - } - tmp.push(arr[i]) - } - if (tmp.length) { - if (fill_with) { - for (var i = tmp.length; i < linecount; i++) { - tmp.push(fill_with) - } - } - res.push(tmp) - } - return res - }, - capitalize: function(str) { - var ret = str.toLowerCase(); - return r.copySafeness(str, ret.charAt(0).toUpperCase() + ret.slice(1)) - }, - center: function(str, width) { - width = width || 80; - if (str.length >= width) { - return str - } - var spaces = width - str.length; - var pre = lib.repeat(" ", spaces / 2 - spaces % 2); - var post = lib.repeat(" ", spaces / 2); - return r.copySafeness(str, pre + str + post) - }, - "default": function(val, def) { - return val ? val : def - }, - dictsort: function(val, case_sensitive, by) { - if (!lib.isObject(val)) { - throw new lib.TemplateError("dictsort filter: val must be an object") - } - var array = []; - for (var k in val) { - array.push([k, val[k]]) - } - var si; - if (by === undefined || by === "key") { - si = 0 - } else if (by === "value") { - si = 1 - } else { - throw new lib.TemplateError("dictsort filter: You can only sort by either key or value") - } - array.sort(function(t1, t2) { - var a = t1[si]; - var b = t2[si]; - if (!case_sensitive) { - if (lib.isString(a)) { - a = a.toUpperCase() - } - if (lib.isString(b)) { - b = b.toUpperCase() - } - } - return a > b ? 1 : a == b ? 0 : -1 - });return array - }, - escape: function(str) { - if (typeof str == "string" || str instanceof r.SafeString) { - return lib.escape(str) - } - return str - }, - safe: function(str) { - return r.markSafe(str) - }, - first: function(arr) { - return arr[0] - }, - groupby: function(arr, attr) { - return lib.groupBy(arr, attr) - }, - indent: function(str, width, indentfirst) { - width = width || 4; - var res = ""; - var lines = str.split("\n"); - var sp = lib.repeat(" ", width); - for (var i = 0; i < lines.length; i++) { - if (i == 0 && !indentfirst) { - res += lines[i] + "\n" - } else { - res += sp + lines[i] + "\n" - } - } - return r.copySafeness(str, res) - }, - join: function(arr, del, attr) { - del = del || ""; - if (attr) { - arr = lib.map(arr, function(v) { - return v[attr] - }) - } - return arr.join(del) - }, - last: function(arr) { - return arr[arr.length - 1] - }, - length: function(arr) { - return arr.length - }, - list: function(val) { - if (lib.isString(val)) { - return val.split("") - } else if (lib.isObject(val)) { - var keys = []; - if (Object.keys) { - keys = Object.keys(val) - } else { - for (var k in val) { - keys.push(k) - } - } - return lib.map(keys, function(k) { - return { - key: k, - value: val[k] - } - }) - } else { - throw new lib.TemplateError("list filter: type not iterable") - } - }, - lower: function(str) { - return str.toLowerCase() - }, - random: function(arr) { - return arr[Math.floor(Math.random() * arr.length)] - }, - replace: function(str, old, new_, maxCount) { - var res = str; - var last = res; - var count = 1; - res = res.replace(old, new_); - while (last != res) { - if (count >= maxCount) { - break - } - last = res; - res = res.replace(old, new_);count++ - } - return r.copySafeness(str, res) - }, - reverse: function(val) { - var arr; - if (lib.isString(val)) { - arr = filters.list(val) - } else { - arr = lib.map(val, function(v) { - return v - }) - } - arr.reverse(); - if (lib.isString(val)) { - return r.copySafeness(val, arr.join("")) - } - return arr - }, - round: function(val, precision, method) { - precision = precision || 0; - var factor = Math.pow(10, precision); - var rounder; - if (method == "ceil") { - rounder = Math.ceil - } else if (method == "floor") { - rounder = Math.floor - } else { - rounder = Math.round - } - return rounder(val * factor) / factor - }, - slice: function(arr, slices, fillWith) { - var sliceLength = Math.floor(arr.length / slices); - var extra = arr.length % slices; - var offset = 0; - var res = []; - for (var i = 0; i < slices; i++) { - var start = offset + i * sliceLength; - if (i < extra) { - offset++ - } - var end = offset + (i + 1) * sliceLength; - var slice = arr.slice(start, end); - if (fillWith && i >= extra) { - slice.push(fillWith) - } - res.push(slice) - } - return res - }, - sort: function(arr, reverse, caseSens, attr) { - arr = lib.map(arr, function(v) { - return v - });arr.sort(function(a, b) { - var x, - y; - if (attr) { - x = a[attr]; - y = b[attr] - } else { - x = a; - y = b - } - if (!caseSens && lib.isString(x) && lib.isString(y)) { - x = x.toLowerCase(); - y = y.toLowerCase() - } - if (x < y) { - return reverse ? 1 : -1 - } else if (x > y) { - return reverse ? -1 : 1 - } else { - return 0 - } - });return arr - }, - string: function(obj) { - return r.copySafeness(obj, obj) - }, - title: function(str) { - var words = str.split(" "); - for (var i = 0; i < words.length; i++) { - words[i] = filters.capitalize(words[i]) - } - return r.copySafeness(str, words.join(" ")) - }, - trim: function(str) { - return r.copySafeness(str, str.replace(/^\s*|\s*$/g, "")) - }, - truncate: function(input, length, killwords, end) { - var orig = input; - length = length || 255; - if (input.length <= length) { - return input; - } - if (killwords) { - input = input.substring(0, length) - } else { - var idx = input.lastIndexOf(" ", length); - if (idx === -1) { - idx = length - } - input = input.substring(0, idx) - } - input += end !== undefined && end !== null ? end : "...";return r.copySafeness(orig, input) - }, - upper: function(str) { - return str.toUpperCase() - }, - urlencode: function(obj) { - var enc = encodeURIComponent; - if (lib.isString(obj)) { - return enc(obj) - } else { - var parts; - if (lib.isArray(obj)) { - parts = obj.map(function(item) { - return enc(item[0]) + "=" + enc(item[1]) - }) - } else { - parts = []; - for (var k in obj) { - if (obj.hasOwnProperty(k)) { - parts.push(enc(k) + "=" + enc(obj[k])) - } - } - } - return parts.join("&") - } - }, - wordcount: function(str) { - return str.match(/\w+/g).length - }, - "float": function(val, def) { - var res = parseFloat(val); - return isNaN(res) ? def : res - }, - "int": function(val, def) { - var res = parseInt(val, 10); - return isNaN(res) ? def : res - } - }; - filters.d = filters["default"]; - filters.e = filters.escape; - modules["filters"] = filters - })();(function() { - function cycler(items) { - var index = -1; - var current = null; - return { - reset: function() { - index = -1; - current = null - }, - next: function() { - index++; - if (index >= items.length) { - index = 0 - } - current = items[index];return current - } - } - } - function joiner(sep) { - sep = sep || ",";var first = true; - return function() { - var val = first ? "" : sep; - first = false;return val - } - } - var globals = { - range: function(start, stop, step) { - if (!stop) { - stop = start; - start = 0; - step = 1 - } else if (!step) { - step = 1 - } - var arr = []; - for (var i = start; i < stop; i += step) { - arr.push(i) - } - return arr - }, - cycler: function() { - return cycler(Array.prototype.slice.call(arguments)) - }, - joiner: function(sep) { - return joiner(sep) - } - }; - modules["globals"] = globals - })();(function() { - var lib = modules["lib"]; - var Obj = modules["object"]; - var lexer = modules["lexer"]; - var compiler = modules["compiler"]; - var builtin_filters = modules["filters"]; - var builtin_loaders = modules["loaders"]; - var runtime = modules["runtime"]; - var globals = modules["globals"]; - var Frame = runtime.Frame; - var Environment = Obj.extend({ - init: function(loaders, opts) { - opts = opts || {}; - this.dev = !!opts.dev; - this.autoesc = !!opts.autoescape; - if (!loaders) { - if (builtin_loaders.FileSystemLoader) { - this.loaders = [new builtin_loaders.FileSystemLoader("views")] - } else { - this.loaders = [new builtin_loaders.WebLoader("/views")] - } - } else { - this.loaders = lib.isArray(loaders) ? loaders : [loaders] - } - this.initCache(); - this.filters = {}; - this.asyncFilters = []; - this.extensions = {}; - this.extensionsList = []; - if (opts.tags) { - lexer.setTags(opts.tags) - } - for (var name in builtin_filters) { - this.addFilter(name, builtin_filters[name]) - } - }, - initCache: function() { - var cache = {}; - lib.each(this.loaders, function(loader) { - loader.on("update", function(template) { - cache[template] = null - }) - }); - this.cache = cache - }, - addExtension: function(name, extension) { - extension._name = name; - this.extensions[name] = extension;this.extensionsList.push(extension) - }, - getExtension: function(name) { - return this.extensions[name] - }, - addFilter: function(name, func, async) { - var wrapped = func; - if (async) { - this.asyncFilters.push(name) - } - this.filters[name] = wrapped - }, - getFilter: function(name) { - if (!this.filters[name]) { - throw new Error("filter not found: " + name) - } - return this.filters[name] - }, - getTemplate: function(name, eagerCompile, cb) { - if (name && name.raw) { - name = name.raw - } - if (lib.isFunction(eagerCompile)) { - cb = eagerCompile; - eagerCompile = false - } - if (typeof name !== "string") { - throw new Error("template names must be a string: " + name) - } - var tmpl = this.cache[name]; - if (tmpl) { - cb(null, tmpl) - } else { - lib.asyncIter(this.loaders, function(loader, i, next, done) { - function handle(src) { - if (src) { - done(src) - } else { - next() - } - } - if (loader.async) { - loader.getSource(name, function(err, src) { - if (err) { - throw err - } - handle(src) - }) - } else { - handle(loader.getSource(name)) - } - }, function(info) { - if (!info) { - cb(new Error("template not found: " + name)) - } else { - var tmpl = new Template(info.src, this, info.path, eagerCompile); - if (!info.noCache) { - this.cache[name] = tmpl - } - cb(null, tmpl) - } - }.bind(this)) - } - }, - express: function(app) { - var env = this; - function NunjucksView(name, opts) { - this.name = name; - this.path = name - } - NunjucksView.prototype.render = function(opts, cb) { - env.render(this.name, opts, cb) - };app.set("view", NunjucksView) - }, - render: function(name, ctx, cb) { - if (lib.isFunction(ctx)) { - cb = ctx; - ctx = null - } - var syncResult = null; - this.getTemplate(name, function(err, tmpl) { - if (err) { - cb(err) - } else { - tmpl.render(ctx, cb || function(err, res) { - if (err) { - throw err - } - syncResult = res - }) - } - });return syncResult - } - }); - var Context = Obj.extend({ - init: function(ctx, blocks) { - this.ctx = ctx; - this.blocks = {}; - this.exported = []; - for (var name in blocks) { - this.addBlock(name, blocks[name]) - } - }, - lookup: function(name) { - if (name in globals && !(name in this.ctx)) { - return globals[name] - } else { - return this.ctx[name] - } - }, - setVariable: function(name, val) { - this.ctx[name] = val - }, - getVariables: function() { - return this.ctx - }, - addBlock: function(name, block) { - this.blocks[name] = this.blocks[name] || [];this.blocks[name].push(block) - }, - getBlock: function(name) { - if (!this.blocks[name]) { - throw new Error('unknown block "' + name + '"') - } - return this.blocks[name][0] - }, - getSuper: function(env, name, block, frame, runtime, cb) { - var idx = (this.blocks[name] || []).indexOf(block); - var blk = this.blocks[name][idx + 1]; - var context = this; - if (idx == -1 || !blk) { - throw new Error('no super block available for "' + name + '"') - } - blk(env, context, frame, runtime, cb) - }, - addExport: function(name) { - this.exported.push(name) - }, - getExported: function() { - var exported = {}; - for (var i = 0; i < this.exported.length; i++) { - var name = this.exported[i]; - exported[name] = this.ctx[name] - } - return exported - } - }); - var Template = Obj.extend({ - init: function(src, env, path, eagerCompile) { - this.env = env || new Environment; - if (lib.isObject(src)) { - switch (src.type) { - case "code": - this.tmplProps = src.obj; - break;case "string": - this.tmplStr = src.obj; - break - } - } else if (lib.isString(src)) { - this.tmplStr = src - } else { - throw new Error("src must be a string or an object describing " + "the source") - } - this.path = path; - if (eagerCompile) { - lib.withPrettyErrors(this.path, this.env.dev, this._compile.bind(this)) - } else { - this.compiled = false - } - }, - render: function(ctx, frame, cb) { - if (typeof ctx === "function") { - cb = ctx; - ctx = {} - } else if (typeof frame === "function") { - cb = frame; - frame = null - } - return lib.withPrettyErrors(this.path, this.env.dev, function() { - if (!this.compiled) { - this._compile() - } - var context = new Context(ctx || {}, this.blocks); - var syncResult = null; - this.rootRenderFunc(this.env, context, frame || new Frame, runtime, cb || function(err, res) { - if (err) { - throw err - } - syncResult = res - });return syncResult - }.bind(this)) - }, - getExported: function(cb) { - if (!this.compiled) { - this._compile() - } - var context = new Context({}, this.blocks); - this.rootRenderFunc(this.env, context, new Frame, runtime, function() { - cb(null, context.getExported()) - }) - }, - _compile: function() { - var props; - if (this.tmplProps) { - props = this.tmplProps - } else { - var source = compiler.compile(this.tmplStr, this.env.asyncFilters, this.env.extensionsList, this.path); - var func = new Function(source); - props = func() - } - this.blocks = this._getBlocks(props); - this.rootRenderFunc = props.root; - this.compiled = true - }, - _getBlocks: function(props) { - var blocks = {}; - for (var k in props) { - if (k.slice(0, 2) == "b_") { - blocks[k.slice(2)] = props[k] - } - } - return blocks - } - }); - modules["environment"] = { - Environment: Environment, - Template: Template - } - })(); - var nunjucks; - var lib = modules["lib"]; - var env = modules["environment"]; - var compiler = modules["compiler"]; - var parser = modules["parser"]; - var lexer = modules["lexer"]; - var runtime = modules["runtime"]; - var Loader = modules["loader"]; - var loaders = modules["loaders"]; - var precompile = modules["precompile"]; - nunjucks = {}; - nunjucks.Environment = env.Environment; - nunjucks.Template = env.Template; - nunjucks.Loader = env.Loader; - nunjucks.FileSystemLoader = loaders.FileSystemLoader; - nunjucks.WebLoader = loaders.WebLoader; - nunjucks.compiler = compiler; - nunjucks.parser = parser; - nunjucks.lexer = lexer; - nunjucks.runtime = runtime; - var e; - nunjucks.configure = function(templatesPath, opts) { - opts = opts || {}; - if (lib.isObject(templatesPath)) { - opts = templatesPath - } else { - opts.templatesPath = templatesPath - } - var loader = loaders.FileSystemLoader || loaders.WebLoader; - e = new env.Environment(new loader(opts.templatesPath, opts.watch), opts); - if (opts && opts.express) { - e.express(opts.express) - } - return e - }; - nunjucks.render = function(name, ctx, cb) { - if (!e) { - nunjucks.configure() - } - return e.render(name, ctx, cb) - }; - nunjucks.precompile = precompile; - nunjucks.require = function(name) { - return modules[name] - }; - if (typeof define === "function" && define.amd) { - define(function() { - return nunjucks - }) - } else { - window.nunjucks = nunjucks - } -})(); \ No newline at end of file diff --git a/tests/express-sample/js/nunjucks.js b/tests/express-sample/js/nunjucks.js deleted file mode 100644 index 204fcf7c..00000000 --- a/tests/express-sample/js/nunjucks.js +++ /dev/null @@ -1,1739 +0,0 @@ -(function() { - var modules = {}; - (function() { - - // A simple class system, more documentation to come - - function extend(cls, name, props) { - // This does that same thing as Object.create, but with support for IE8 - var F = function() {}; - F.prototype = cls.prototype; - var prototype = new F(); - - var fnTest = /xyz/.test(function() { - xyz; - }) ? /\bparent\b/ : /.*/; - props = props || {}; - - for (var k in props) { - var src = props[k]; - var parent = prototype[k]; - - if (typeof parent == "function" && - typeof src == "function" && - fnTest.test(src)) { - prototype[k] = (function(src, parent) { - return function() { - // Save the current parent method - var tmp = this.parent; - - // Set parent to the previous method, call, and restore - this.parent = parent; - var res = src.apply(this, arguments); - this.parent = tmp; - - return res; - }; - })(src, parent); - } else { - prototype[k] = src; - } - } - - prototype.typename = name; - - var new_cls = function() { - if (prototype.init) { - prototype.init.apply(this, arguments); - } - }; - - new_cls.prototype = prototype; - new_cls.prototype.constructor = new_cls; - - new_cls.extend = function(name, props) { - if (typeof name == "object") { - props = name; - name = "anonymous"; - } - return extend(new_cls, name, props); - }; - - return new_cls; - } - - modules['object'] = extend(Object, "Object", {}); - })(); - (function() { - var ArrayProto = Array.prototype; - var ObjProto = Object.prototype; - - var escapeMap = { - '&': '&', - '"': '"', - "'": ''', - "<": '<', - ">": '>' - }; - - var lookupEscape = function(ch) { - return escapeMap[ch]; - }; - - var exports = modules['lib'] = {}; - - exports.withPrettyErrors = function(path, withInternals, func) { - try { - return func(); - } catch (e) { - if (!e.Update) { - // not one of ours, cast it - e = new exports.TemplateError(e); - } - e.Update(path); - - // Unless they marked the dev flag, show them a trace from here - if (!withInternals) { - var old = e; - e = new Error(old.message); - e.name = old.name; - } - - throw e; - } - }; - - exports.TemplateError = function(message, lineno, colno) { - var err = this; - - if (message instanceof Error) { // for casting regular js errors - err = message; - message = message.name + ": " + message.message; - } else { - if (Error.captureStackTrace) { - Error.captureStackTrace(err); - } - } - - err.name = 'Template render error'; - err.message = message; - err.lineno = lineno; - err.colno = colno; - err.firstUpdate = true; - - err.Update = function(path) { - var message = "(" + (path || "unknown path") + ")"; - - // only show lineno + colno next to path of template - // where error occurred - if (this.firstUpdate) { - if (this.lineno && this.colno) { - message += ' [Line ' + this.lineno + ', Column ' + this.colno + ']'; - } else if (this.lineno) { - message += ' [Line ' + this.lineno + ']'; - } - } - - message += '\n '; - if (this.firstUpdate) { - message += ' '; - } - - this.message = message + (this.message || ''); - this.firstUpdate = false; - return this; - }; - - return err; - }; - - exports.TemplateError.prototype = Error.prototype; - - exports.escape = function(val) { - return val.replace(/[&"'<>]/g, lookupEscape); - }; - - exports.isFunction = function(obj) { - return ObjProto.toString.call(obj) == '[object Function]'; - }; - - exports.isArray = Array.isArray || function(obj) { - return ObjProto.toString.call(obj) == '[object Array]'; - }; - - exports.isString = function(obj) { - return ObjProto.toString.call(obj) == '[object String]'; - }; - - exports.isObject = function(obj) { - return obj === Object(obj); - }; - - exports.groupBy = function(obj, val) { - var result = {}; - var iterator = exports.isFunction(val) ? val : function(obj) { - return obj[val]; - }; - for (var i = 0; i < obj.length; i++) { - var value = obj[i]; - var key = iterator(value, i); - (result[key] || (result[key] = [])).push(value); - } - return result; - }; - - exports.toArray = function(obj) { - return Array.prototype.slice.call(obj); - }; - - exports.without = function(array) { - var result = []; - if (!array) { - return result; - } - var index = -1, - length = array.length, - contains = exports.toArray(arguments).slice(1); - - while (++index < length) { - if (contains.indexOf(array[index]) === -1) { - result.push(array[index]); - } - } - return result; - }; - - exports.extend = function(obj, obj2) { - for (var k in obj2) { - obj[k] = obj2[k]; - } - return obj; - }; - - exports.repeat = function(char_, n) { - var str = ''; - for (var i = 0; i < n; i++) { - str += char_; - } - return str; - }; - - exports.each = function(obj, func, context) { - if (obj == null) { - return; - } - - if (ArrayProto.each && obj.each == ArrayProto.each) { - obj.forEach(func, context); - } else if (obj.length === +obj.length) { - for (var i = 0, l = obj.length; i < l; i++) { - func.call(context, obj[i], i, obj); - } - } - }; - - exports.map = function(obj, func) { - var results = []; - if (obj == null) { - return results; - } - - if (ArrayProto.map && obj.map === ArrayProto.map) { - return obj.map(func); - } - - for (var i = 0; i < obj.length; i++) { - results[results.length] = func(obj[i], i); - } - - if (obj.length === +obj.length) { - results.length = obj.length; - } - - return results; - }; - - exports.asyncParallel = function(funcs, done) { - var count = funcs.length, - result = new Array(count), - current = 0; - - var makeNext = function(i) { - return function(res) { - result[i] = res; - current += 1; - - if (current === count) { - done(result); - } - }; - }; - - for (var i = 0; i < count; i++) { - funcs[i](makeNext(i)); - } - }; - - exports.asyncIter = function(arr, iter, cb) { - var i = -1; - - function next() { - i++; - - if (i < arr.length) { - iter(arr[i], i, next, cb); - } else { - cb(); - } - } - - next(); - }; - - exports.asyncFor = function(obj, iter, cb) { - var keys = exports.keys(obj); - var len = keys.length; - var i = -1; - - function next() { - i++; - var k = keys[i]; - - if (i < len) { - iter(k, obj[k], i, len, next); - } else { - cb(); - } - } - - next(); - }; - - if (!Array.prototype.indexOf) { - Array.prototype.indexOf = function(array, searchElement /*, fromIndex */ ) { - if (array == null) { - throw new TypeError(); - } - var t = Object(array); - var len = t.length >>> 0; - if (len === 0) { - return -1; - } - var n = 0; - if (arguments.length > 2) { - n = Number(arguments[2]); - if (n != n) { // shortcut for verifying if it's NaN - n = 0; - } else if (n != 0 && n != Infinity && n != -Infinity) { - n = (n > 0 || -1) * Math.floor(Math.abs(n)); - } - } - if (n >= len) { - return -1; - } - var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); - for (; k < len; k++) { - if (k in t && t[k] === searchElement) { - return k; - } - } - return -1; - }; - } - - if (!Array.prototype.map) { - Array.prototype.map = function() { - throw new Error("map is unimplemented for this js engine"); - }; - } - - exports.keys = function(obj) { - if (Object.prototype.keys) { - return obj.keys(); - } else { - var keys = []; - for (var k in obj) { - if (obj.hasOwnProperty(k)) { - keys.push(k); - } - } - return keys; - } - } - })(); - (function() { - - var lib = modules["lib"]; - var Object = modules["object"]; - - // Frames keep track of scoping both at compile-time and run-time so - // we know how to access variables. Block tags can introduce special - // variables, for example. - var Frame = Object.extend({ - init: function(parent) { - this.variables = {}; - this.parent = parent; - }, - - set: function(name, val) { - // Allow variables with dots by automatically creating the - // nested structure - var parts = name.split('.'); - var obj = this.variables; - - for (var i = 0; i < parts.length - 1; i++) { - var id = parts[i]; - - if (!obj[id]) { - obj[id] = {}; - } - obj = obj[id]; - } - - obj[parts[parts.length - 1]] = val; - }, - - get: function(name) { - var val = this.variables[name]; - if (val !== undefined && val !== null) { - return val; - } - return null; - }, - - lookup: function(name) { - var p = this.parent; - var val = this.variables[name]; - if (val !== undefined && val !== null) { - return val; - } - return p && p.lookup(name); - }, - - push: function() { - return new Frame(this); - }, - - pop: function() { - return this.parent; - } - }); - - function makeMacro(argNames, kwargNames, func) { - return function() { - var argCount = numArgs(arguments); - var args; - var kwargs = getKeywordArgs(arguments); - - if (argCount > argNames.length) { - args = Array.prototype.slice.call(arguments, 0, argNames.length); - - // Positional arguments that should be passed in as - // keyword arguments (essentially default values) - var vals = Array.prototype.slice.call(arguments, args.length, argCount); - for (var i = 0; i < vals.length; i++) { - if (i < kwargNames.length) { - kwargs[kwargNames[i]] = vals[i]; - } - } - - args.push(kwargs); - } else if (argCount < argNames.length) { - args = Array.prototype.slice.call(arguments, 0, argCount); - - for (var i = argCount; i < argNames.length; i++) { - var arg = argNames[i]; - - // Keyword arguments that should be passed as - // positional arguments, i.e. the caller explicitly - // used the name of a positional arg - args.push(kwargs[arg]); - delete kwargs[arg]; - } - - args.push(kwargs); - } else { - args = arguments; - } - - return func.apply(this, args); - }; - } - - function makeKeywordArgs(obj) { - obj.__keywords = true; - return obj; - } - - function getKeywordArgs(args) { - var len = args.length; - if (len) { - var lastArg = args[len - 1]; - if (lastArg && lastArg.hasOwnProperty('__keywords')) { - return lastArg; - } - } - return {}; - } - - function numArgs(args) { - var len = args.length; - if (len === 0) { - return 0; - } - - var lastArg = args[len - 1]; - if (lastArg && lastArg.hasOwnProperty('__keywords')) { - return len - 1; - } else { - return len; - } - } - - // A SafeString object indicates that the string should not be - // autoescaped. This happens magically because autoescaping only - // occurs on primitive string objects. - function SafeString(val) { - if (typeof val != 'string') { - return val; - } - - this.toString = function() { - return val; - }; - - this.length = val.length; - - var methods = [ - 'charAt', 'charCodeAt', 'concat', 'contains', - 'endsWith', 'fromCharCode', 'indexOf', 'lastIndexOf', - 'length', 'localeCompare', 'match', 'quote', 'replace', - 'search', 'slice', 'split', 'startsWith', 'substr', - 'substring', 'toLocaleLowerCase', 'toLocaleUpperCase', - 'toLowerCase', 'toUpperCase', 'trim', 'trimLeft', 'trimRight' - ]; - - for (var i = 0; i < methods.length; i++) { - this[methods[i]] = markSafe(val[methods[i]]); - } - } - - function copySafeness(dest, target) { - if (dest instanceof SafeString) { - return new SafeString(target); - } - return target.toString(); - } - - function markSafe(val) { - var type = typeof val; - - if (type === 'string') { - return new SafeString(val); - } else if (type !== 'function') { - return val; - } else { - return function() { - var ret = val.apply(this, arguments); - - if (typeof ret === 'string') { - return new SafeString(ret); - } - - return ret; - }; - } - } - - function suppressValue(val, autoescape) { - val = (val !== undefined && val !== null) ? val : ""; - - if (autoescape && typeof val === "string") { - val = lib.escape(val); - } - - return val; - } - - function memberLookup(obj, val) { - obj = obj || {}; - - if (typeof obj[val] === 'function') { - return function() { - return obj[val].apply(obj, arguments); - }; - } - - return obj[val]; - } - - function callWrap(obj, name, args) { - if (!obj) { - throw new Error('Unable to call `' + name + '`, which is undefined or falsey'); - } else if (typeof obj !== 'function') { - throw new Error('Unable to call `' + name + '`, which is not a function'); - } - - return obj.apply(this, args); - } - - function contextOrFrameLookup(context, frame, name) { - var val = frame.lookup(name); - return (val !== undefined && val !== null) ? - val : - context.lookup(name); - } - - function handleError(error, lineno, colno) { - if (error.lineno) { - return error; - } else { - return new lib.TemplateError(error, lineno, colno); - } - } - - function asyncEach(arr, dimen, iter, cb) { - if (lib.isArray(arr)) { - var len = arr.length; - - lib.asyncIter(arr, function(item, i, next) { - switch (dimen) { - case 1: - iter(item, i, len, next); - break; - case 2: - iter(item[0], item[1], i, len, next); - break; - case 3: - iter(item[0], item[1], item[2], i, len, next); - break; - default: - item.push(i, next); - iter.apply(this, item); - } - }, cb); - } else { - lib.asyncFor(arr, function(key, val, i, len, next) { - iter(key, val, i, len, next); - }, cb); - } - } - - function asyncAll(arr, dimen, func, cb) { - var finished = 0; - var len; - var outputArr; - - function done(i, output) { - finished++; - outputArr[i] = output; - - if (finished == len) { - cb(null, outputArr.join('')); - } - } - - if (lib.isArray(arr)) { - len = arr.length; - outputArr = new Array(len); - - if (len == 0) { - cb(null, ''); - } else { - for (var i = 0; i < arr.length; i++) { - var item = arr[i]; - - switch (dimen) { - case 1: - func(item, i, len, done); - break; - case 2: - func(item[0], item[1], i, len, done); - break; - case 3: - func(item[0], item[1], item[2], i, len, done); - break; - default: - item.push(i, done); - func.apply(this, item); - } - } - } - } else { - var keys = lib.keys(arr); - len = keys.length; - outputArr = new Array(len); - - if (len == 0) { - cb(null, ''); - } else { - for (var i = 0; i < keys.length; i++) { - var k = keys[i]; - func(k, arr[k], i, len, done); - } - } - } - } - - modules['runtime'] = { - Frame: Frame, - makeMacro: makeMacro, - makeKeywordArgs: makeKeywordArgs, - numArgs: numArgs, - suppressValue: suppressValue, - memberLookup: memberLookup, - contextOrFrameLookup: contextOrFrameLookup, - callWrap: callWrap, - handleError: handleError, - isArray: lib.isArray, - asyncEach: lib.asyncEach, - keys: lib.keys, - SafeString: SafeString, - copySafeness: copySafeness, - markSafe: markSafe, - asyncEach: asyncEach, - asyncAll: asyncAll - }; - })(); - (function() { - var Obj = modules["object"]; - var lib = modules["lib"]; - - var Loader = Obj.extend({ - on: function(name, func) { - this.listeners = this.listeners || {}; - this.listeners[name] = this.listeners[name] || []; - this.listeners[name].push(func); - }, - - emit: function(name /*, arg1, arg2, ...*/ ) { - var args = Array.prototype.slice.call(arguments, 1); - - if (this.listeners && this.listeners[name]) { - lib.each(this.listeners[name], function(listener) { - listener.apply(null, args); - }); - } - } - }); - - modules['loader'] = Loader; - })(); - (function() { - var Loader = modules["loader"]; - - var WebLoader = Loader.extend({ - init: function(baseURL, neverUpdate) { - // It's easy to use precompiled templates: just include them - // before you configure nunjucks and this will automatically - // pick it up and use it - this.precompiled = window.nunjucksPrecompiled || {}; - - this.baseURL = baseURL || ''; - this.neverUpdate = neverUpdate; - }, - - getSource: function(name) { - if (this.precompiled[name]) { - return { - src: { - type: "code", - obj: this.precompiled[name] - }, - path: name - }; - } else { - var src = this.fetch(this.baseURL + '/' + name); - if (!src) { - return null; - } - - return { - src: src, - path: name, - noCache: this.neverUpdate - }; - } - }, - - fetch: function(url, callback) { - // Only in the browser please - var ajax; - var loading = true; - var src; - - if (window.XMLHttpRequest) { // Mozilla, Safari, ... - ajax = new XMLHttpRequest(); - } else if (window.ActiveXObject) { // IE 8 and older - ajax = new ActiveXObject("Microsoft.XMLHTTP"); - } - - ajax.onreadystatechange = function() { - if (ajax.readyState == 4 && ajax.status == 200 && loading) { - loading = false; - src = ajax.responseText; - } - }; - - url += (url.indexOf('?') === -1 ? '?' : '&') + 's=' + - (new Date().getTime()); - - // Synchronous because this API shouldn't be used in - // production (pre-load compiled templates instead) - ajax.open('GET', url, false); - ajax.send(); - - return src; - } - }); - - modules['web-loaders'] = { - WebLoader: WebLoader - }; - })(); - (function() { - if (typeof window === 'undefined') { - modules['loaders'] = modules["node-loaders"]; - } else { - modules['loaders'] = modules["web-loaders"]; - } - })(); - (function() { - - var lib = modules["lib"]; - var r = modules["runtime"]; - - var filters = { - abs: function(n) { - return Math.abs(n); - }, - - batch: function(arr, linecount, fill_with) { - var res = []; - var tmp = []; - - for (var i = 0; i < arr.length; i++) { - if (i % linecount === 0 && tmp.length) { - res.push(tmp); - tmp = []; - } - - tmp.push(arr[i]); - } - - if (tmp.length) { - if (fill_with) { - for (var i = tmp.length; i < linecount; i++) { - tmp.push(fill_with); - } - } - - res.push(tmp); - } - - return res; - }, - - capitalize: function(str) { - var ret = str.toLowerCase(); - return r.copySafeness(str, ret.charAt(0).toUpperCase() + ret.slice(1)); - }, - - center: function(str, width) { - width = width || 80; - - if (str.length >= width) { - return str; - } - - var spaces = width - str.length; - var pre = lib.repeat(" ", spaces / 2 - spaces % 2); - var post = lib.repeat(" ", spaces / 2); - return r.copySafeness(str, pre + str + post); - }, - - 'default': function(val, def) { - return val ? val : def; - }, - - dictsort: function(val, case_sensitive, by) { - if (!lib.isObject(val)) { - throw new lib.TemplateError("dictsort filter: val must be an object"); - } - - var array = []; - for (var k in val) { - // deliberately include properties from the object's prototype - array.push([k, val[k]]); - } - - var si; - if (by === undefined || by === "key") { - si = 0; - } else if (by === "value") { - si = 1; - } else { - throw new lib.TemplateError( - "dictsort filter: You can only sort by either key or value"); - } - - array.sort(function(t1, t2) { - var a = t1[si]; - var b = t2[si]; - - if (!case_sensitive) { - if (lib.isString(a)) { - a = a.toUpperCase(); - } - if (lib.isString(b)) { - b = b.toUpperCase(); - } - } - - return a > b ? 1 : (a == b ? 0 : -1); - }); - - return array; - }, - - escape: function(str) { - if (typeof str == 'string' || - str instanceof r.SafeString) { - return lib.escape(str); - } - return str; - }, - - safe: function(str) { - return r.markSafe(str); - }, - - first: function(arr) { - return arr[0]; - }, - - groupby: function(arr, attr) { - return lib.groupBy(arr, attr); - }, - - indent: function(str, width, indentfirst) { - width = width || 4; - var res = ''; - var lines = str.split('\n'); - var sp = lib.repeat(' ', width); - - for (var i = 0; i < lines.length; i++) { - if (i == 0 && !indentfirst) { - res += lines[i] + '\n'; - } else { - res += sp + lines[i] + '\n'; - } - } - - return r.copySafeness(str, res); - }, - - join: function(arr, del, attr) { - del = del || ''; - - if (attr) { - arr = lib.map(arr, function(v) { - return v[attr]; - }); - } - - return arr.join(del); - }, - - last: function(arr) { - return arr[arr.length - 1]; - }, - - length: function(arr) { - return arr.length; - }, - - list: function(val) { - if (lib.isString(val)) { - return val.split(''); - } else if (lib.isObject(val)) { - var keys = []; - - if (Object.keys) { - keys = Object.keys(val); - } else { - for (var k in val) { - keys.push(k); - } - } - - return lib.map(keys, function(k) { - return { - key: k, - value: val[k] - }; - }); - } else { - throw new lib.TemplateError("list filter: type not iterable"); - } - }, - - lower: function(str) { - return str.toLowerCase(); - }, - - random: function(arr) { - return arr[Math.floor(Math.random() * arr.length)]; - }, - - replace: function(str, old, new_, maxCount) { - var res = str; - var last = res; - var count = 1; - res = res.replace(old, new_); - - while (last != res) { - if (count >= maxCount) { - break; - } - - last = res; - res = res.replace(old, new_); - count++; - } - - return r.copySafeness(str, res); - }, - - reverse: function(val) { - var arr; - if (lib.isString(val)) { - arr = filters.list(val); - } else { - // Copy it - arr = lib.map(val, function(v) { - return v; - }); - } - - arr.reverse(); - - if (lib.isString(val)) { - return r.copySafeness(val, arr.join('')); - } - return arr; - }, - - round: function(val, precision, method) { - precision = precision || 0; - var factor = Math.pow(10, precision); - var rounder; - - if (method == 'ceil') { - rounder = Math.ceil; - } else if (method == 'floor') { - rounder = Math.floor; - } else { - rounder = Math.round; - } - - return rounder(val * factor) / factor; - }, - - slice: function(arr, slices, fillWith) { - var sliceLength = Math.floor(arr.length / slices); - var extra = arr.length % slices; - var offset = 0; - var res = []; - - for (var i = 0; i < slices; i++) { - var start = offset + i * sliceLength; - if (i < extra) { - offset++; - } - var end = offset + (i + 1) * sliceLength; - - var slice = arr.slice(start, end); - if (fillWith && i >= extra) { - slice.push(fillWith); - } - res.push(slice); - } - - return res; - }, - - sort: function(arr, reverse, caseSens, attr) { - // Copy it - arr = lib.map(arr, function(v) { - return v; - }); - - arr.sort(function(a, b) { - var x, - y; - - if (attr) { - x = a[attr]; - y = b[attr]; - } else { - x = a; - y = b; - } - - if (!caseSens && lib.isString(x) && lib.isString(y)) { - x = x.toLowerCase(); - y = y.toLowerCase(); - } - - if (x < y) { - return reverse ? 1 : -1; - } else if (x > y) { - return reverse ? -1 : 1; - } else { - return 0; - } - }); - - return arr; - }, - - string: function(obj) { - return r.copySafeness(obj, obj); - }, - - title: function(str) { - var words = str.split(' '); - for (var i = 0; i < words.length; i++) { - words[i] = filters.capitalize(words[i]); - } - return r.copySafeness(str, words.join(' ')); - }, - - trim: function(str) { - return r.copySafeness(str, str.replace(/^\s*|\s*$/g, '')); - }, - - truncate: function(input, length, killwords, end) { - var orig = input; - length = length || 255; - - if (input.length <= length) { - return input; - } - - if (killwords) { - input = input.substring(0, length); - } else { - var idx = input.lastIndexOf(' ', length); - if (idx === -1) { - idx = length; - } - - input = input.substring(0, idx); - } - - input += (end !== undefined && end !== null) ? end : '...'; - return r.copySafeness(orig, input); - }, - - upper: function(str) { - return str.toUpperCase(); - }, - - urlencode: function(obj) { - var enc = encodeURIComponent; - if (lib.isString(obj)) { - return enc(obj); - } else { - var parts; - if (lib.isArray(obj)) { - parts = obj.map(function(item) { - return enc(item[0]) + '=' + enc(item[1]); - }) - } else { - parts = []; - for (var k in obj) { - if (obj.hasOwnProperty(k)) { - parts.push(enc(k) + '=' + enc(obj[k])); - } - } - } - return parts.join('&'); - } - }, - - wordcount: function(str) { - return str.match(/\w+/g).length; - }, - - 'float': function(val, def) { - var res = parseFloat(val); - return isNaN(res) ? def : res; - }, - - 'int': function(val, def) { - var res = parseInt(val, 10); - return isNaN(res) ? def : res; - } - }; - - // Aliases - filters.d = filters['default']; - filters.e = filters.escape; - - modules['filters'] = filters; - })(); - (function() { - - function cycler(items) { - var index = -1; - var current = null; - - return { - reset: function() { - index = -1; - current = null; - }, - - next: function() { - index++; - if (index >= items.length) { - index = 0; - } - - current = items[index]; - return current; - } - }; - - } - - function joiner(sep) { - sep = sep || ','; - var first = true; - - return function() { - var val = first ? '' : sep; - first = false; - return val; - }; - } - - var globals = { - range: function(start, stop, step) { - if (!stop) { - stop = start; - start = 0; - step = 1; - } else if (!step) { - step = 1; - } - - var arr = []; - for (var i = start; i < stop; i += step) { - arr.push(i); - } - return arr; - }, - - // lipsum: function(n, html, min, max) { - // }, - - cycler: function() { - return cycler(Array.prototype.slice.call(arguments)); - }, - - joiner: function(sep) { - return joiner(sep); - } - } - - modules['globals'] = globals; - })(); - (function() { - var lib = modules["lib"]; - var Obj = modules["object"]; - var lexer = modules["lexer"]; - var compiler = modules["compiler"]; - var builtin_filters = modules["filters"]; - var builtin_loaders = modules["loaders"]; - var runtime = modules["runtime"]; - var globals = modules["globals"]; - var Frame = runtime.Frame; - - var Environment = Obj.extend({ - init: function(loaders, opts) { - // The dev flag determines the trace that'll be shown on errors. - // If set to true, returns the full trace from the error point, - // otherwise will return trace starting from Template.render - // (the full trace from within nunjucks may confuse developers using - // the library) - // defaults to false - opts = opts || {}; - this.dev = !!opts.dev; - - // The autoescape flag sets global autoescaping. If true, - // every string variable will be escaped by default. - // If false, strings can be manually escaped using the `escape` filter. - // defaults to false - this.autoesc = !!opts.autoescape; - - if (!loaders) { - // The filesystem loader is only available client-side - if (builtin_loaders.FileSystemLoader) { - this.loaders = [new builtin_loaders.FileSystemLoader('views')]; - } else { - this.loaders = [new builtin_loaders.WebLoader('/views')]; - } - } else { - this.loaders = lib.isArray(loaders) ? loaders : [loaders]; - } - - this.initCache(); - this.filters = {}; - this.asyncFilters = []; - this.extensions = {}; - this.extensionsList = []; - - if (opts.tags) { - lexer.setTags(opts.tags); - } - - for (var name in builtin_filters) { - this.addFilter(name, builtin_filters[name]); - } - }, - - initCache: function() { - // Caching and cache busting - var cache = {}; - - lib.each(this.loaders, function(loader) { - loader.on('update', function(template) { - cache[template] = null; - }); - }); - - this.cache = cache; - }, - - addExtension: function(name, extension) { - extension._name = name; - this.extensions[name] = extension; - this.extensionsList.push(extension); - }, - - getExtension: function(name) { - return this.extensions[name]; - }, - - addFilter: function(name, func, async) { - var wrapped = func; - - if (async) { - this.asyncFilters.push(name); - } - this.filters[name] = wrapped; - }, - - getFilter: function(name) { - if (!this.filters[name]) { - throw new Error('filter not found: ' + name); - } - return this.filters[name]; - }, - - getTemplate: function(name, eagerCompile, cb) { - if (name && name.raw) { - // this fixes autoescape for templates referenced in symbols - name = name.raw; - } - - if (lib.isFunction(eagerCompile)) { - cb = eagerCompile; - eagerCompile = false; - } - - if (typeof name !== 'string') { - throw new Error('template names must be a string: ' + name); - } - - var tmpl = this.cache[name]; - - if (tmpl) { - cb(null, tmpl); - } else { - lib.asyncIter(this.loaders, function(loader, i, next, done) { - function handle(src) { - if (src) { - done(src); - } else { - next(); - } - } - - if (loader.async) { - loader.getSource(name, function(err, src) { - if (err) { - throw err; - } - handle(src); - }); - } else { - handle(loader.getSource(name)); - } - }, function(info) { - if (!info) { - cb(new Error('template not found: ' + name)); - } else { - var tmpl = new Template(info.src, this, - info.path, eagerCompile); - - if (!info.noCache) { - this.cache[name] = tmpl; - } - - cb(null, tmpl); - } - }.bind(this)); - } - }, - - express: function(app) { - var env = this; - - function NunjucksView(name, opts) { - this.name = name; - this.path = name; - } - - NunjucksView.prototype.render = function(opts, cb) { - env.render(this.name, opts, cb); - }; - - app.set('view', NunjucksView); - }, - - render: function(name, ctx, cb) { - if (lib.isFunction(ctx)) { - cb = ctx; - ctx = null; - } - - // We support a synchronous API to make it easier to migrate - // existing code to async. This works because if you don't do - // anything async work, the whole thing is actually run - // synchronously. - var syncResult = null; - - this.getTemplate(name, function(err, tmpl) { - if (err) { - cb(err); - } else { - tmpl.render(ctx, cb || function(err, res) { - if (err) { - throw err; - } - syncResult = res; - }); - } - }); - - return syncResult; - } - }); - - var Context = Obj.extend({ - init: function(ctx, blocks) { - this.ctx = ctx; - this.blocks = {}; - this.exported = []; - - for (var name in blocks) { - this.addBlock(name, blocks[name]); - } - }, - - lookup: function(name) { - // This is one of the most called functions, so optimize for - // the typical case where the name isn't in the globals - if (name in globals && !(name in this.ctx)) { - return globals[name]; - } else { - return this.ctx[name]; - } - }, - - setVariable: function(name, val) { - this.ctx[name] = val; - }, - - getVariables: function() { - return this.ctx; - }, - - addBlock: function(name, block) { - this.blocks[name] = this.blocks[name] || []; - this.blocks[name].push(block); - }, - - getBlock: function(name) { - if (!this.blocks[name]) { - throw new Error('unknown block "' + name + '"'); - } - - return this.blocks[name][0]; - }, - - getSuper: function(env, name, block, frame, runtime, cb) { - var idx = (this.blocks[name] || []).indexOf(block); - var blk = this.blocks[name][idx + 1]; - var context = this; - - if (idx == -1 || !blk) { - throw new Error('no super block available for "' + name + '"'); - } - - blk(env, context, frame, runtime, cb); - }, - - addExport: function(name) { - this.exported.push(name); - }, - - getExported: function() { - var exported = {}; - for (var i = 0; i < this.exported.length; i++) { - var name = this.exported[i]; - exported[name] = this.ctx[name]; - } - return exported; - } - }); - - var Template = Obj.extend({ - init: function(src, env, path, eagerCompile) { - this.env = env || new Environment(); - - if (lib.isObject(src)) { - switch (src.type) { - case 'code': - this.tmplProps = src.obj; - break; - case 'string': - this.tmplStr = src.obj; - break; - } - } else if (lib.isString(src)) { - this.tmplStr = src; - } else { - throw new Error("src must be a string or an object describing " + - "the source"); - } - - this.path = path; - - if (eagerCompile) { - lib.withPrettyErrors(this.path, - this.env.dev, - this._compile.bind(this)); - } else { - this.compiled = false; - } - }, - - render: function(ctx, frame, cb) { - if (typeof ctx === 'function') { - cb = ctx; - ctx = {}; - } else if (typeof frame === 'function') { - cb = frame; - frame = null; - } - - return lib.withPrettyErrors(this.path, this.env.dev, function() { - if (!this.compiled) { - this._compile(); - } - - var context = new Context(ctx || {}, this.blocks); - var syncResult = null; - - this.rootRenderFunc(this.env, - context, - frame || new Frame(), - runtime, - cb || function(err, res) { - if (err) { - throw err; - } - syncResult = res; - }); - - return syncResult; - }.bind(this)); - }, - - getExported: function(cb) { - if (!this.compiled) { - this._compile(); - } - - // Run the rootRenderFunc to populate the context with exported vars - var context = new Context({}, this.blocks); - this.rootRenderFunc(this.env, - context, - new Frame(), - runtime, - function() { - cb(null, context.getExported()); - }); - }, - - _compile: function() { - var props; - - if (this.tmplProps) { - props = this.tmplProps; - } else { - var source = compiler.compile(this.tmplStr, - this.env.asyncFilters, - this.env.extensionsList, - this.path); - var func = new Function(source); - props = func(); - } - - this.blocks = this._getBlocks(props); - this.rootRenderFunc = props.root; - this.compiled = true; - }, - - _getBlocks: function(props) { - var blocks = {}; - - for (var k in props) { - if (k.slice(0, 2) == 'b_') { - blocks[k.slice(2)] = props[k]; - } - } - - return blocks; - } - }); - - // test code - // var src = 'hello {% foo baz | bar %}hi{% endfoo %} end'; - // var env = new Environment(new builtin_loaders.FileSystemLoader('tests/templates', true), { dev: true }); - - // function FooExtension() { - // this.tags = ['foo']; - // this._name = 'FooExtension'; - - // this.parse = function(parser, nodes) { - // var tok = parser.nextToken(); - // var args = parser.parseSignature(null, true); - // parser.advanceAfterBlockEnd(tok.value); - - // var body = parser.parseUntilBlocks('endfoo'); - // parser.advanceAfterBlockEnd(); - - // return new nodes.CallExtensionAsync(this, 'run', args, [body]); - // }; - - // this.run = function(context, baz, body, cb) { - // cb(null, baz + '--' + body()); - // }; - // } - - // env.addExtension('FooExtension', new FooExtension()); - // env.addFilter('bar', function(val, cb) { - // cb(null, val + '22222'); - // }, true); - - // var ctx = {}; - // var tmpl = new Template(src, env, null, null, true); - // console.log("OUTPUT ---"); - - // tmpl.render(ctx, function(err, res) { - // if(err) { - // throw err; - // } - // console.log(res); - // }); - - modules['environment'] = { - Environment: Environment, - Template: Template - }; - })(); - var nunjucks; - - var lib = modules["lib"]; - var env = modules["environment"]; - var compiler = modules["compiler"]; - var parser = modules["parser"]; - var lexer = modules["lexer"]; - var runtime = modules["runtime"]; - var Loader = modules["loader"]; - var loaders = modules["loaders"]; - var precompile = modules["precompile"]; - - nunjucks = {}; - nunjucks.Environment = env.Environment; - nunjucks.Template = env.Template; - - nunjucks.Loader = env.Loader; - nunjucks.FileSystemLoader = loaders.FileSystemLoader; - nunjucks.WebLoader = loaders.WebLoader; - - nunjucks.compiler = compiler; - nunjucks.parser = parser; - nunjucks.lexer = lexer; - nunjucks.runtime = runtime; - - // A single instance of an environment, since this is so commonly used - - var e; - nunjucks.configure = function(templatesPath, opts) { - opts = opts || {}; - if (lib.isObject(templatesPath)) { - opts = templatesPath; - } else { - opts.templatesPath = templatesPath; - } - - var loader = loaders.FileSystemLoader || loaders.WebLoader; - e = new env.Environment(new loader(opts.templatesPath, opts.watch), opts); - - if (opts && opts.express) { - e.express(opts.express); - } - - return e; - }; - - nunjucks.render = function(name, ctx, cb) { - if (!e) { - nunjucks.configure(); - } - - return e.render(name, ctx, cb); - }; - - nunjucks.precompile = precompile; - - nunjucks.require = function(name) { - return modules[name]; - }; - - if (typeof define === 'function' && define.amd) { - define(function() { - return nunjucks; - }); - } else { - window.nunjucks = nunjucks; - } - -})(); diff --git a/tests/express-sample/js/require.js b/tests/express-sample/js/require.js deleted file mode 100644 index ba4997bb..00000000 --- a/tests/express-sample/js/require.js +++ /dev/null @@ -1,817 +0,0 @@ -/* - RequireJS 2.1.6 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. - Available via the MIT or new BSD license. - see: http://github.com/jrburke/requirejs for details -*/ -var requirejs, - require, - define; -(function(ba) { - function J(b) { - return "[object Function]" === N.call(b) - } - function K(b) { - return "[object Array]" === N.call(b) - } - function z(b, c) { - if (b) { - var d; - for (d = 0; d < b.length && (!b[d] || !c(b[d], d, b)); d += 1) { - ; - } - } - } - function O(b, c) { - if (b) { - var d; - for (d = b.length - 1; -1 < d && (!b[d] || !c(b[d], d, b)); d -= 1) { - ; - } - } - } - function t(b, c) { - return ha.call(b, c) - } - function m(b, c) { - return t(b, c) && b[c] - } - function H(b, c) { - for (var d in b) { - if (t(b, d) && c(b[d], d)) { - break - } - } - } - function S(b, c, d, m) { - c && H(c, function(c, l) { - if (d || !t(b, l)) { - m && "string" !== typeof c ? (b[l] || (b[l] = {}), S(b[l], - c, d, m)) : b[l] = c - } - });return b - } - function v(b, c) { - return function() { - return c.apply(b, arguments) - } - } - function ca(b) { - throw b; - } - function da(b) { - if (!b) { - return b; - } - var c = ba; - z(b.split("."), function(b) { - c = c[b] - });return c - } - function B(b, c, d, m) { - c = Error(c + "\nhttp://requirejs.org/docs/errors.html#" + b); - c.requireType = b; - c.requireModules = m;d && (c.originalError = d);return c - } - function ia(b) { - function c(a, f, C) { - var e, - n, - b, - c, - d, - T, - k, - g = f && f.split("/"); - e = g;var l = j.map, - h = l && l["*"]; - if (a && "." === a.charAt(0)) { - if (f) { - e = m(j.pkgs, f) ? g = [f] : g.slice(0, g.length - - 1); - f = a = e.concat(a.split("/")); - for (e = 0; f[e]; e += 1) { - if (n = f[e], "." === n) { - f.splice(e, 1), e -= 1; - } else if (".." === n) { - if (1 === e && (".." === f[2] || ".." === f[0])) { - break; - } else { - 0 < e && (f.splice(e - 1, 2), e -= 2); - } - } - } - e = m(j.pkgs, f = a[0]); - a = a.join("/");e && a === f + "/" + e.main && (a = f) - } else { - 0 === a.indexOf("./") && (a = a.substring(2)); - } - } - if (C && l && (g || h)) { - f = a.split("/"); - for (e = f.length; 0 < e; e -= 1) { - b = f.slice(0, e).join("/"); - if (g) { - for (n = g.length; 0 < n; n -= 1) { - if (C = m(l, g.slice(0, n).join("/"))) { - if (C = m(C, b)) { - c = C; - d = e;break - } - } - } - } - if (c) { - break; - } - !T && (h && m(h, b)) && (T = m(h, b), k = e) - } - !c && - T && (c = T, d = k);c && (f.splice(0, d, c), a = f.join("/")) - } - return a - } - function d(a) { - A && z(document.getElementsByTagName("script"), function(f) { - if (f.getAttribute("data-requiremodule") === a && f.getAttribute("data-requirecontext") === k.contextName) { - return f.parentNode.removeChild(f), !0 - } - }) - } - function p(a) { - var f = m(j.paths, a); - if (f && K(f) && 1 < f.length) { - return d(a), f.shift(), k.require.undef(a), k.require([a]), !0 - } - } - function g(a) { - var f, - b = a ? a.indexOf("!") : -1; - -1 < b && (f = a.substring(0, b), a = a.substring(b + 1, a.length));return [f, a] - } - function l(a, - f, b, e) { - var n, - D, - i = null, - d = f ? f.name : null, - l = a, - h = !0, - j = ""; - a || (h = !1, a = "_@r" + (N += 1)); - a = g(a); - i = a[0]; - a = a[1];i && (i = c(i, d, e), D = m(r, i));a && (i ? j = D && D.normalize ? D.normalize(a, function(a) { - return c(a, d, e) - }) : c(a, d, e) : (j = c(a, d, e), a = g(j), i = a[0], j = a[1], b = !0, n = k.nameToUrl(j))); - b = i && !D && !b ? "_unnormalized" + (O += 1) : "";return { - prefix: i, - name: j, - parentMap: f, - unnormalized: !!b, - url: n, - originalName: l, - isDefine: h, - id: (i ? i + "!" + j : j) + b - } - } - function s(a) { - var f = a.id, - b = m(q, f); - b || (b = q[f] = new k.Module(a));return b - } - function u(a, f, b) { - var e = a.id, - n = m(q, - e); - if (t(r, e) && (!n || n.defineEmitComplete)) { - "defined" === f && b(r[e]); - } else if (n = s(a), n.error && "error" === f) { - b(n.error); - } else { - n.on(f, b) - } - } - function w(a, f) { - var b = a.requireModules, - e = !1; - if (f) { - f(a); - } else if (z(b, function(f) { - if (f = m(q, f)) { - f.error = a, f.events.error && (e = !0, f.emit("error", a)) - } - }), !e) { - h.onError(a) - } - } - function x() { - U.length && (ja.apply(I, [I.length - 1, 0].concat(U)), U = []) - } - function y(a) { - delete q[a]; - delete W[a] - } - function G(a, f, b) { - var e = a.map.id; - a.error ? a.emit("error", a.error) : (f[e] = !0, z(a.depMaps, function(e, c) { - var d = e.id, - g = m(q, d); - g && (!a.depMatched[c] && !b[d]) && (m(f, d) ? (a.defineDep(c, r[d]), a.check()) : G(g, f, b)) - }), b[e] = !0) - } - function E() { - var a, - f, - b, - e, - n = (b = 1E3 * j.waitSeconds) && k.startTime + b < (new Date).getTime(), - c = [], - i = [], - g = !1, - l = !0; - if (!X) { - X = !0;H(W, function(b) { - a = b.map; - f = a.id; - if (b.enabled && (a.isDefine || i.push(b), !b.error)) { - if (!b.inited && n) { - p(f) ? g = e = !0 : (c.push(f), d(f)); - } else if (!b.inited && (b.fetched && a.isDefine) && (g = !0, !a.prefix)) { - return l = !1 - } - } - }); - if (n && c.length) { - return b = B("timeout", "Load timeout for modules: " + c, null, c), b.contextName = k.contextName, w(b); - } - l && z(i, function(a) { - G(a, {}, {}) - }); - if ((!n || e) && g) { - if ((A || ea) && !Y) { - Y = setTimeout(function() { - Y = 0;E() - }, 50); - } - } - X = !1 - } - } - function F(a) { - t(r, a[0]) || s(l(a[0], null, !0)).init(a[1], a[2]) - } - function L(a) { - var a = a.currentTarget || a.srcElement, - b = k.onScriptLoad; - a.detachEvent && !Z ? a.detachEvent("onreadystatechange", b) : a.removeEventListener("load", b, !1); - b = k.onScriptError;(!a.detachEvent || Z) && a.removeEventListener("error", b, !1);return { - node: a, - id: a && a.getAttribute("data-requiremodule") - } - } - function M() { - var a; - for (x(); I.length;) { - a = I.shift(); - if (null === a[0]) { - return w(B("mismatch", "Mismatched anonymous define() module: " + a[a.length - 1])); - } - F(a) - } - } - var X, - $, - k, - P, - Y, - j = { - waitSeconds: 7, - baseUrl: "./", - paths: {}, - pkgs: {}, - shim: {}, - config: {} - }, - q = {}, - W = {}, - aa = {}, - I = [], - r = {}, - V = {}, - N = 1, - O = 1; - P = { - require: function(a) { - return a.require ? a.require : a.require = k.makeRequire(a.map) - }, - exports: function(a) { - a.usingExports = !0; - if (a.map.isDefine) { - return a.exports ? a.exports : a.exports = r[a.map.id] = {} - } - }, - module: function(a) { - return a.module ? a.module : a.module = { - id: a.map.id, - uri: a.map.url, - config: function() { - var b = m(j.pkgs, a.map.id); - return (b ? m(j.config, a.map.id + "/" + b.main) : m(j.config, a.map.id)) || {} - }, - exports: r[a.map.id] - } - } - }; - $ = function(a) { - this.events = m(aa, a.id) || {}; - this.map = a; - this.shim = m(j.shim, a.id); - this.depExports = []; - this.depMaps = []; - this.depMatched = []; - this.pluginMaps = {}; - this.depCount = 0 - }; - $.prototype = { - init: function(a, b, c, e) { - e = e || {}; - if (!this.inited) { - this.factory = b; - if (c) { - this.on("error", c); - } else { - this.events.error && (c = v(this, function(a) { - this.emit("error", a) - })); - } - this.depMaps = a && a.slice(0); - this.errback = c; - this.inited = !0; - this.ignore = e.ignore; - e.enabled || this.enabled ? this.enable() : this.check() - } - }, - defineDep: function(a, b) { - this.depMatched[a] || (this.depMatched[a] = !0, this.depCount -= 1, this.depExports[a] = b) - }, - fetch: function() { - if (!this.fetched) { - this.fetched = !0; - k.startTime = (new Date).getTime(); - var a = this.map; - if (this.shim) { - k.makeRequire(this.map, { - enableBuildCallback: !0 - })(this.shim.deps || [], v(this, function() { - return a.prefix ? this.callPlugin() : this.load() - })); - } else { - return a.prefix ? this.callPlugin() : this.load() - } - } - }, - load: function() { - var a = this.map.url; - V[a] || (V[a] = !0, k.load(this.map.id, a)) - }, - check: function() { - if (this.enabled && !this.enabling) { - var a, - b, - c = this.map.id; - b = this.depExports; - var e = this.exports, - n = this.factory; - if (this.inited) { - if (this.error) { - this.emit("error", this.error); - } else { - if (!this.defining) { - this.defining = !0; - if (1 > this.depCount && !this.defined) { - if (J(n)) { - if (this.events.error && this.map.isDefine || h.onError !== ca) { - try { - e = k.execCb(c, n, b, e) - } catch (d) { - a = d - } - } else { - e = k.execCb(c, n, b, e); - } - this.map.isDefine && ((b = this.module) && void 0 !== b.exports && b.exports !== - this.exports ? e = b.exports : void 0 === e && this.usingExports && (e = this.exports)); - if (a) { - return a.requireMap = this.map, a.requireModules = this.map.isDefine ? [this.map.id] : null, a.requireType = this.map.isDefine ? "define" : "require", w(this.error = a) - } - } else { - e = n; - } - this.exports = e; - if (this.map.isDefine && !this.ignore && (r[c] = e, h.onResourceLoad)) { - h.onResourceLoad(k, this.map, this.depMaps); - } - y(c); - this.defined = !0 - } - this.defining = !1;this.defined && !this.defineEmitted && (this.defineEmitted = !0, this.emit("defined", this.exports), this.defineEmitComplete = !0) - } - } - } else { - this.fetch() - } - } - }, - callPlugin: function() { - var a = this.map, - b = a.id, - d = l(a.prefix); - this.depMaps.push(d);u(d, "defined", v(this, function(e) { - var n, - d; - d = this.map.name; - var g = this.map.parentMap ? this.map.parentMap.name : null, - C = k.makeRequire(a.parentMap, { - enableBuildCallback: !0 - }); - if (this.map.unnormalized) { - if (e.normalize && (d = e.normalize(d, function(a) { - return c(a, g, !0) - }) || ""), e = l(a.prefix + "!" + d, this.map.parentMap), u(e, "defined", v(this, function(a) { - this.init([], function() { - return a - }, null, { - enabled: !0, - ignore: !0 - }) - })), - d = m(q, e.id)) { - this.depMaps.push(e); - if (this.events.error) { - d.on("error", v(this, function(a) { - this.emit("error", a) - })); - } - d.enable() - } - } else { - n = v(this, function(a) { - this.init([], function() { - return a - }, null, { - enabled: !0 - }) - }), n.error = v(this, function(a) { - this.inited = !0; - this.error = a; - a.requireModules = [b];H(q, function(a) { - 0 === a.map.id.indexOf(b + "_unnormalized") && y(a.map.id) - });w(a) - }), n.fromText = v(this, function(e, c) { - var d = a.name, - g = l(d), - i = Q; - c && (e = c);i && (Q = !1);s(g);t(j.config, b) && (j.config[d] = j.config[b]);try { - h.exec(e) - } catch (D) { - return w(B("fromtexteval", - "fromText eval for " + b + " failed: " + D, D, [b])) - } i && (Q = !0);this.depMaps.push(g);k.completeLoad(d);C([d], n) - }), e.load(a.name, C, n, j) - } - }));k.enable(d, this); - this.pluginMaps[d.id] = d - }, - enable: function() { - W[this.map.id] = this; - this.enabling = this.enabled = !0;z(this.depMaps, v(this, function(a, b) { - var c, - e; - if ("string" === typeof a) { - a = l(a, this.map.isDefine ? this.map : this.map.parentMap, !1, !this.skipMap); - this.depMaps[b] = a; - if (c = m(P, a.id)) { - this.depExports[b] = c(this);return - } - this.depCount += 1;u(a, "defined", v(this, function(a) { - this.defineDep(b, - a);this.check() - }));this.errback && u(a, "error", v(this, this.errback)) - } - c = a.id; - e = q[c];!t(P, c) && (e && !e.enabled) && k.enable(a, this) - }));H(this.pluginMaps, v(this, function(a) { - var b = m(q, a.id); - b && !b.enabled && k.enable(a, this) - })); - this.enabling = !1;this.check() - }, - on: function(a, b) { - var c = this.events[a]; - c || (c = this.events[a] = []);c.push(b) - }, - emit: function(a, b) { - z(this.events[a], function(a) { - a(b) - });"error" === a && - delete this.events[a] - } - }; - k = { - config: j, - contextName: b, - registry: q, - defined: r, - urlFetched: V, - defQueue: I, - Module: $, - makeModuleMap: l, - nextTick: h.nextTick, - onError: w, - configure: function(a) { - a.baseUrl && "/" !== a.baseUrl.charAt(a.baseUrl.length - 1) && (a.baseUrl += "/"); - var b = j.pkgs, - c = j.shim, - e = { - paths: !0, - config: !0, - map: !0 - }; - H(a, function(a, b) { - e[b] ? "map" === b ? (j.map || (j.map = {}), S(j[b], a, !0, !0)) : S(j[b], a, !0) : j[b] = a - });a.shim && (H(a.shim, function(a, b) { - K(a) && (a = { - deps: a - }); - if ((a.exports || a.init) && !a.exportsFn) { - a.exportsFn = k.makeShimExports(a); - } - c[b] = a - }), j.shim = c);a.packages && (z(a.packages, function(a) { - a = "string" === typeof a ? { - name: a - } : a; - b[a.name] = { - name: a.name, - location: a.location || a.name, - main: (a.main || "main").replace(ka, "").replace(fa, "") - } - }), j.pkgs = b);H(q, function(a, b) { - !a.inited && !a.map.unnormalized && (a.map = l(b)) - }); - if (a.deps || a.callback) { - k.require(a.deps || [], a.callback) - } - }, - makeShimExports: function(a) { - return function() { - var b; - a.init && (b = a.init.apply(ba, arguments));return b || a.exports && da(a.exports) - } - }, - makeRequire: function(a, f) { - function d(e, c, g) { - var i, - j; - f.enableBuildCallback && (c && J(c)) && (c.__requireJsBuild = !0); - if ("string" === typeof e) { - if (J(c)) { - return w(B("requireargs", - "Invalid require call"), g); - } - if (a && t(P, e)) { - return P[e](q[a.id]); - } - if (h.get) { - return h.get(k, e, a, d); - } - i = l(e, a, !1, !0); - i = i.id;return !t(r, i) ? w(B("notloaded", 'Module name "' + i + '" has not been loaded yet for context: ' + b + (a ? "" : ". Use require([])"))) : r[i] - } - M();k.nextTick(function() { - M(); - j = s(l(null, a)); - j.skipMap = f.skipMap;j.init(e, c, g, { - enabled: !0 - });E() - });return d - } - f = f || {};S(d, { - isBrowser: A, - toUrl: function(b) { - var d, - f = b.lastIndexOf("."), - g = b.split("/")[0]; - if (-1 !== f && (!("." === g || ".." === g) || 1 < f)) { - d = b.substring(f, b.length), b = b.substring(0, f); - } - return k.nameToUrl(c(b, a && a.id, !0), d, !0) - }, - defined: function(b) { - return t(r, l(b, a, !1, !0).id) - }, - specified: function(b) { - b = l(b, a, !1, !0).id;return t(r, b) || t(q, b) - } - });a || (d.undef = function(b) { - x(); - var c = l(b, a, !0), - d = m(q, b); - delete r[b]; - delete V[c.url]; - delete aa[b]; - d && (d.events.defined && (aa[b] = d.events), y(b)) - });return d - }, - enable: function(a) { - m(q, a.id) && s(a).enable() - }, - completeLoad: function(a) { - var b, - c, - e = m(j.shim, a) || {}, - d = e.exports; - for (x(); I.length;) { - c = I.shift(); - if (null === c[0]) { - c[0] = a; - if (b) { - break; - } - b = !0 - } else { - c[0] === - a && (b = !0); - } - F(c) - } - c = m(q, a); - if (!b && !t(r, a) && c && !c.inited) { - if (j.enforceDefine && (!d || !da(d))) { - return p(a) ? void 0 : w(B("nodefine", "No define call for " + a, null, [a])); - } - F([a, e.deps || [], e.exportsFn]) - } - E() - }, - nameToUrl: function(a, b, c) { - var d, - g, - l, - i, - k, - p; - if (h.jsExtRegExp.test(a)) { - i = a + (b || ""); - } else { - d = j.paths; - g = j.pkgs; - i = a.split("/"); - for (k = i.length; 0 < k; k -= 1) { - if (p = i.slice(0, k).join("/"), l = m(g, p), p = m(d, p)) { - K(p) && (p = p[0]);i.splice(0, k, p);break - } else if (l) { - a = a === l.name ? l.location + "/" + l.main : l.location;i.splice(0, k, a);break - } - } - i = i.join("/"); - i += b || (/\?/.test(i) || c ? "" : ".js"); - i = ("/" === i.charAt(0) || i.match(/^[\w\+\.\-]+:/) ? "" : j.baseUrl) + i - } - return j.urlArgs ? i + ((-1 === i.indexOf("?") ? "?" : "&") + j.urlArgs) : i - }, - load: function(a, b) { - h.load(k, a, b) - }, - execCb: function(a, b, c, d) { - return b.apply(d, c) - }, - onScriptLoad: function(a) { - if ("load" === a.type || la.test((a.currentTarget || a.srcElement).readyState)) { - R = null, a = L(a), k.completeLoad(a.id) - } - }, - onScriptError: function(a) { - var b = L(a); - if (!p(b.id)) { - return w(B("scripterror", "Script error for: " + b.id, a, [b.id])) - } - } - }; - k.require = k.makeRequire(); - return k - } - var h, - x, - y, - E, - L, - F, - R, - M, - s, - ga, - ma = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, - na = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, - fa = /\.js$/, - ka = /^\.\//; - x = Object.prototype; - var N = x.toString, - ha = x.hasOwnProperty, - ja = Array.prototype.splice, - A = !!("undefined" !== typeof window && navigator && window.document), - ea = !A && "undefined" !== typeof importScripts, - la = A && "PLAYSTATION 3" === navigator.platform ? /^complete$/ : /^(complete|loaded)$/, - Z = "undefined" !== typeof opera && "[object Opera]" === opera.toString(), - G = {}, - u = {}, - U = [], - Q = !1; - if ("undefined" === typeof define) { - if ("undefined" !== typeof requirejs) { - if (J(requirejs)) { - return; - } - u = requirejs; - requirejs = void 0 - } - "undefined" !== typeof require && !J(require) && (u = require, require = void 0); - h = requirejs = function(b, c, d, p) { - var g, - l = "_"; - !K(b) && "string" !== typeof b && (g = b, K(c) ? (b = c, c = d, d = p) : b = []);g && g.context && (l = g.context);(p = m(G, l)) || (p = G[l] = h.s.newContext(l));g && p.configure(g);return p.require(b, c, d) - }; - h.config = function(b) { - return h(b) - }; - h.nextTick = "undefined" !== typeof setTimeout ? function(b) { - setTimeout(b, - 4) - } : function(b) { - b() - };require || (require = h); - h.version = "2.1.6"; - h.jsExtRegExp = /^\/|:|\?|\.js$/; - h.isBrowser = A; - x = h.s = { - contexts: G, - newContext: ia - };h({});z(["toUrl", "undef", "defined", "specified"], function(b) { - h[b] = function() { - var c = G._; - return c.require[b].apply(c, arguments) - } - }); - if (A && (y = x.head = document.getElementsByTagName("head")[0], E = document.getElementsByTagName("base")[0])) { - y = x.head = E.parentNode; - } - h.onError = ca; - h.load = function(b, c, d) { - var h = b && b.config || {}, - g; - if (A) { - return g = h.xhtml ? document.createElementNS("http://www.w3.org/1999/xhtml", - "html:script") : document.createElement("script"), g.type = h.scriptType || "text/javascript", g.charset = "utf-8", g.async = !0, g.setAttribute("data-requirecontext", b.contextName), g.setAttribute("data-requiremodule", c), g.attachEvent && !(g.attachEvent.toString && 0 > g.attachEvent.toString().indexOf("[native code")) && !Z ? (Q = !0, g.attachEvent("onreadystatechange", b.onScriptLoad)) : (g.addEventListener("load", b.onScriptLoad, !1), g.addEventListener("error", b.onScriptError, !1)), g.src = d, M = g, E ? y.insertBefore(g, E) : y.appendChild(g), - M = null, g; - } - if (ea) { - try { - importScripts(d), b.completeLoad(c) - } catch (l) { - b.onError(B("importscripts", "importScripts failed for " + c + " at " + d, l, [c])) - } - } - };A && O(document.getElementsByTagName("script"), function(b) { - y || (y = b.parentNode); - if (L = b.getAttribute("data-main")) { - return s = L, u.baseUrl || (F = s.split("/"), s = F.pop(), ga = F.length ? F.join("/") + "/" : "./", u.baseUrl = ga), s = s.replace(fa, ""), h.jsExtRegExp.test(s) && (s = L), u.deps = u.deps ? u.deps.concat(s) : [s], !0 - } - }); - define = function(b, c, d) { - var h, - g; - "string" !== typeof b && (d = c, c = b, b = null); - K(c) || (d = c, c = null);!c && J(d) && (c = [], d.length && (d.toString().replace(ma, "").replace(na, function(b, d) { - c.push(d) - }), c = (1 === d.length ? ["require"] : ["require", "exports", "module"]).concat(c))); - if (Q) { - if (!(h = M)) { - R && "interactive" === R.readyState || O(document.getElementsByTagName("script"), function(b) { - if ("interactive" === b.readyState) { - return R = b - } - }), h = R; - } - h && (b || (b = h.getAttribute("data-requiremodule")), g = G[h.getAttribute("data-requirecontext")]) - } - (g ? g.defQueue : U).push([b, c, d]) - }; - define.amd = { - jQuery: !0 - }; - h.exec = function(b) { - return eval(b) - }; - h(u) - } -})(this); diff --git a/tests/express-sample/js/templates.js b/tests/express-sample/js/templates.js deleted file mode 100644 index e526b2d8..00000000 --- a/tests/express-sample/js/templates.js +++ /dev/null @@ -1,126 +0,0 @@ -window.baseTmpl = (function() { - (window.nunjucksPrecompiled = window.nunjucksPrecompiled || {})["base.njk"] = (function() { - function root(env, context, frame, runtime, cb) { - var lineno = null; - var colno = null; - var output = ""; - try { - output += "\n\n \n A quick app\n\n \n\n \n \n \n \n \n "; - context.getBlock("content")(env, context, frame, runtime, function(t_2, t_1) { - if (t_2) { - cb(t_2); return; - } - output += t_1; - output += "\n\n
    \n "; - context.getBlock("footer")(env, context, frame, runtime, function(t_4, t_3) { - if (t_4) { - cb(t_4); return; - } - output += t_3; - output += "\n
    \n \n\n"; - cb(null, output); - }) - }); - } catch (e) { - cb(runtime.handleError(e, lineno, colno)); - } - } - function b_content(env, context, frame, runtime, cb) { - var lineno = null; - var colno = null; - var output = ""; - try { - cb(null, output); - ; - } catch (e) { - cb(runtime.handleError(e, lineno, colno)); - } - } - function b_footer(env, context, frame, runtime, cb) { - var lineno = null; - var colno = null; - var output = ""; - try { - output += "(c) James Long 2012"; - cb(null, output); - ; - } catch (e) { - cb(runtime.handleError(e, lineno, colno)); - } - } - return { - b_content: b_content, - b_footer: b_footer, - root: root - }; - })(); - return function(ctx, cb) { - return nunjucks.render("base.njk", ctx, cb); - } -})(); -window.aboutTmpl = (function() { - (window.nunjucksPrecompiled = window.nunjucksPrecompiled || {})["about.njk"] = (function() { - function root(env, context, frame, runtime, cb) { - var lineno = null; - var colno = null; - var output = ""; - try { - env.getTemplate("base.njk", true, function(t_2, parentTemplate) { - if (t_2) { - cb(t_2); return; - } - for (var t_1 in parentTemplate.blocks) { - context.addBlock(t_1, parentTemplate.blocks[t_1]); - } - output += "\n\n"; - output += "\n\n"; - output += "\n"; - parentTemplate.rootRenderFunc(env, context, frame, runtime, cb); - }); - } catch (e) { - cb(runtime.handleError(e, lineno, colno)); - } - } - function b_content(env, context, frame, runtime, cb) { - var lineno = null; - var colno = null; - var output = ""; - try { - output += "\nThis is just the about page\n"; - cb(null, output); - ; - } catch (e) { - cb(runtime.handleError(e, lineno, colno)); - } - } - function b_footer(env, context, frame, runtime, cb) { - var lineno = null; - var colno = null; - var output = ""; - try { - context.getSuper(env, "footer", b_footer, frame, runtime, function(t_3, hole_3) { - if (t_3) { - cb(t_3); return; - } - hole_3 = runtime.markSafe(hole_3); - output += "\n"; - output += runtime.suppressValue(hole_3, env.autoesc); - output += "\nYou really should read this!\n\n"; - output += runtime.suppressValue(runtime.contextOrFrameLookup(context, frame, "poop"), env.autoesc); - output += "\n"; - cb(null, output); - }); - } catch (e) { - cb(runtime.handleError(e, lineno, colno)); - } - } - return { - b_content: b_content, - b_footer: b_footer, - root: root - }; - })(); - return function(ctx, cb) { - return nunjucks.render("about.njk", ctx, cb); - } -})(); diff --git a/tests/express-sample/pre.js b/tests/express-sample/pre.js deleted file mode 100644 index 64e211a7..00000000 --- a/tests/express-sample/pre.js +++ /dev/null @@ -1,16 +0,0 @@ -var precompileString = require('../../index').precompileString; -var fs = require('fs'); - -var out = 'window.baseTmpl = ' + -precompileString(fs.readFileSync('views/base.njk', 'utf-8'), { - name: 'base.njk', - asFunction: true -}); - -out += 'window.aboutTmpl = ' + -precompileString(fs.readFileSync('views/about.njk', 'utf-8'), { - name: 'about.njk', - asFunction: true -}); - -fs.writeFileSync('js/templates.js', out, 'utf-8'); diff --git a/tests/express-sample/views/index.html b/tests/express-sample/views/index.html deleted file mode 100644 index 74d8ca2d..00000000 --- a/tests/express-sample/views/index.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends "base.njk" %} - -{% block content %} -Hello, {{ username | default('poop') }}! This is just some content. - -
    -{% endblock %} diff --git a/tests/express/express.js b/tests/express.js similarity index 87% rename from tests/express/express.js rename to tests/express.js index 06bce63b..79890f55 100644 --- a/tests/express/express.js +++ b/tests/express.js @@ -4,12 +4,11 @@ var path = require('path'); var express = require('express'); var expect = require('expect.js'); var request = require('supertest'); -var nunjucks = require('../../'); +var nunjucks = require('../nunjucks/index'); -var VIEWS = path.join(__dirname, '..', 'express-sample', 'views'); +var VIEWS = path.join(__dirname, '../samples/express/views'); describe('express', function() { - var app; var env; @@ -25,7 +24,7 @@ describe('express', function() { it('should render a view with extension', function(done) { app.get('/', function(req, res) { - res.render('about.njk'); + res.render('about.html'); }); request(app) .get('/') diff --git a/tests/filters.js b/tests/filters.js index 3c1c8073..6e6e8483 100644 --- a/tests/filters.js +++ b/tests/filters.js @@ -1,16 +1,19 @@ (function() { 'use strict'; - var expect, - util, - lib, - r; + var expect; + var util; + var lib; + var r; + var render; + var equal; + var finish; if (typeof require !== 'undefined') { expect = require('expect.js'); util = require('./util'); - lib = require('../src/lib'); - r = require('../src/runtime'); + lib = require('../nunjucks/src/lib'); + r = require('../nunjucks/src/runtime'); } else { expect = window.expect; util = window.util; @@ -18,12 +21,11 @@ r = nunjucks.runtime; } - var render = util.render; - var equal = util.equal; - var finish = util.finish; + render = util.render; + equal = util.equal; + finish = util.finish; describe('filter', function() { - it('abs', function(done) { equal('{{ -3|abs }}', '3'); equal('{{ -3.456|abs }}', '3.456'); @@ -93,7 +95,7 @@ finish(done); }); - it('dump', function(done) { + it('dump', function() { equal('{{ [\'a\', 1, {b: true}] | dump }}', '["a",1,{"b":true}]'); equal('{{ [\'a\', 1, {b: true}] | dump(2) }}', @@ -102,89 +104,69 @@ '[\n "a",\n 1,\n {\n "b": true\n }\n]'); equal('{{ [\'a\', 1, {b: true}] | dump(\'\t\') }}', '[\n\t"a",\n\t1,\n\t{\n\t\t"b": true\n\t}\n]'); - finish(done); }); - it('escape', function(done) { - var res = render('{{ "" | escape }}', {}, { - autoescape: false - }); - expect(res).to.be('<html>'); - finish(done); + it('escape', function() { + equal( + '{{ "" | escape }}', {}, + { autoescape: false }, + '<html>'); }); - it('escape skip safe', function(done) { - var res = render('{{ "" | safe | escape }}', {}, { - autoescape: false - }); - expect(res).to.be(''); - finish(done); + it('escape skip safe', function() { + equal('{{ "" | safe | escape }}', {}, + { autoescape: false }, + ''); }); - it('should not double escape strings', function(done) { - var res = render('{{ "" | escape | escape }}', {}, { - autoescape: false - }); - expect(res).to.be('<html>'); - finish(done); + it('should not double escape strings', function() { + equal('{{ "" | escape | escape }}', {}, + { autoescape: false }, + '<html>'); }); - it('should not double escape with autoescape on', function(done) { - var res = render('{% set val = "" | escape %}{{ val }}', {}, { - autoescape: true - }); - expect(res).to.be('<html>'); - finish(done); + it('should not double escape with autoescape on', function() { + equal('{% set val = "" | escape %}{{ val }}', {}, + { autoescape: true }, + '<html>'); }); - it('should work with non-string values', function(done) { - var res1 = render('{{ foo | escape }}', { - foo: [''] - }, { - autoescape: false - }); - expect(res1).to.be('<html>'); - - var res2 = render('{{ foo | escape }}', { - foo: { - toString: function() { - return ''; - } - } - }, { - autoescape: false - }); - expect(res2).to.be('<html>'); + it('should work with non-string values', function() { + equal( + '{{ foo | escape }}', + { foo: [''] }, + { autoescape: false }, + '<html>'); - var res3 = render('{{ foo | escape }}', { - foo: null - }, { - autoescape: false - }); - expect(res3).to.be(''); + equal( + '{{ foo | escape }}', + { foo: { toString: function() { return ''; } } }, + { autoescape: false }, + '<html>'); - finish(done); + equal('{{ foo | escape }}', + { foo: null }, + { autoescape: false }, + ''); }); - it('should not escape safe strings with autoescape on', function(done) { - var res1 = render('{{ "" | safe | escape }}', {}, { - autoescape: true - }); - expect(res1).to.be(''); + it('should not escape safe strings with autoescape on', function() { + equal( + '{{ "" | safe | escape }}', {}, + { autoescape: true }, + ''); - var res2 = render('{% set val = "" | safe | e %}{{ val }}', {}, { - autoescape: true - }); - expect(res2).to.be(''); - finish(done); + equal( + '{% set val = "" | safe | e %}{{ val }}', {}, + { autoescape: true }, + ''); }); - it('should keep strings escaped after they have been escaped', function(done) { - var res = render('{% set val = "" | e | safe %}{{ val }}', {}, { - autoescape: false - }); - expect(res).to.be('<html>'); - finish(done); + it('should keep strings escaped after they have been escaped', function() { + equal( + '{% set val = "" | e | safe %}{{ val }}', {}, + { autoescape: false }, + '<html>'); }); it('dictsort', function(done) { @@ -199,12 +181,12 @@ '{{ item[0] }}{% endfor %}', { items: { - 'e': 1, - 'd': 2, - 'c': 3, - 'a': 4, - 'f': 5, - 'b': 6 + e: 1, + d: 2, + c: 3, + a: 4, + f: 5, + b: 6 } }, 'abcdef'); @@ -213,10 +195,10 @@ equal( '{% for item in items | dictsort(true) %}{{ item[0] }},{% endfor %}', { items: { - 'ABC': 6, - 'ABc': 5, - 'Abc': 1, - 'abc': 2 + ABC: 6, + ABc: 5, + Abc: 1, + abc: 2 } }, 'ABC,ABc,Abc,abc,'); @@ -225,10 +207,10 @@ equal( '{% for item in items | dictsort(false, "value") %}{{ item[0] }}{% endfor %}', { items: { - 'a': 6, - 'b': 5, - 'c': 1, - 'd': 2 + a: 6, + b: 5, + c: 1, + d: 2 } }, 'cdba'); @@ -241,15 +223,22 @@ finish(done); }); - it('float/int', function(done) { + it('float', function() { equal('{{ "3.5" | float }}', '3.5'); + equal('{{ "0" | float }}', '0'); + }); + + it('int', function() { equal('{{ "3.5" | int }}', '3'); equal('{{ "0" | int }}', '0'); - equal('{{ "0" | float }}', '0'); + }); + + it('int (default value)', function() { equal('{{ "bob" | int("cat") }}', 'cat'); - equal('{{ "bob" | float("cat") }}', 'cat'); + }); - finish(done); + it('float (default value)', function() { + equal('{{ "bob" | float("cat") }}', 'cat'); }); it('groupby', function(done) { @@ -344,70 +333,100 @@ finish(done); }); - it('length', function(done) { - equal('{{ [1,2,3] | length }}', '3'); - equal('{{ blah|length }}', '0'); - equal('{{ str | length }}', { - str: r.markSafe('blah') - }, '4'); - equal('{{ str | length }}', { - str: 'blah' - }, '4'); - equal('{{ str | length }}', { - str: new String('blah') - }, '4'); - equal('{{ undefined | length }}', '0'); - equal('{{ null | length }}', '0'); - equal('{{ nothing | length }}', '0'); - equal('{{ obj | length }}', { - obj: {} - }, '0'); - equal('{{ obj | length }}', { - obj: { - key: 'value' - } - }, '1'); - equal('{{ obj | length }}', { - obj: { - key: 'value', - length: 5 - } - }, '2'); - equal('{{ obj.length }}', { - obj: { - key: 'value', - length: 5 - } - }, '5'); - equal('{{ arr | length }}', { - arr: [0, 1] - }, '2'); - equal('{{ arr | length }}', { - arr: [0,, 2] // eslint-disable-line - }, '3'); - equal('{{ arr | length }}', { - arr: new Array(0, 1) - }, '2'); - var arr = new Array(0, 1); - arr.key = 'value'; - equal('{{ arr | length }}', { - arr: arr - }, '2'); - if (typeof Map === 'function') { - var map = new Map([['key1', 'value1'], ['key2', 'value2']]); - map.set('key3', 'value3'); - equal('{{ map | length }}', { - map: map + describe('the length filter', function suite() { + it('should return length of a list literal', function test() { + equal('{{ [1,2,3] | length }}', '3'); + }); + it('should output 0 for a missing context variable', function test() { + equal('{{ blah|length }}', '0'); + }); + it('should output string length for string variables', function test() { + equal('{{ str | length }}', { + str: 'blah' + }, '4'); + }); + it('should output string length for a SafeString variable', function test() { + equal('{{ str | length }}', { + str: r.markSafe('') + }, '6'); + }); + it('should output the correct length of a string created with new String()', function test() { + equal('{{ str | length }}', { + str: new String('blah') // eslint-disable-line no-new-wrappers + }, '4'); + }); + it('should output 0 for a literal "undefined"', function test() { + equal('{{ undefined | length }}', '0'); + }); + it('should output 0 for a literal "null"', function test() { + equal('{{ null | length }}', '0'); + }); + it('should output 0 for an Object with no properties', function test() { + equal('{{ obj | length }}', { + obj: {} + }, '0'); + }); + it('should output 1 for an Object with 1 property', function test() { + equal('{{ obj | length }}', { + obj: { + key: 'value' + } + }, '1'); + }); + it('should output the number of properties for a plain Object, not the value of its length property', function test() { + equal('{{ obj | length }}', { + obj: { + key: 'value', + length: 5 + } + }, '2'); + }); + it('should output the length of an array', function test() { + equal('{{ arr | length }}', { + arr: [0, 1] + }, '2'); + }); + it('should output the full length of a sparse array', function test() { + equal('{{ arr | length }}', { + arr: [0,, 2] // eslint-disable-line }, '3'); - } - if (typeof Set === 'function') { - var set = new Set(['value1']); - set.add('value2'); - equal('{{ set | length }}', { - set: set + }); + it('should output the length of an array created with "new Array"', function test() { + equal('{{ arr | length }}', { + arr: new Array(0, 1) // eslint-disable-line no-array-constructor }, '2'); - } - finish(done); + }); + it('should output the length of an array created with "new Array" with user-defined properties', function test() { + var arr = new Array(0, 1); // eslint-disable-line no-array-constructor + arr.key = 'value'; + equal('{{ arr | length }}', { + arr: arr + }, '2'); + }); + it('should output the length of a Map', function test() { + /* global Map */ + var map; + if (typeof Map === 'undefined') { + this.skip(); + } else { + map = new Map([['key1', 'value1'], ['key2', 'value2']]); + map.set('key3', 'value3'); + equal('{{ map | length }}', { + map: map + }, '3'); + } + }); + it('should output the length of a Set', function test() { + /* global Set */ + var set; + if (typeof Set === 'undefined') { + this.skip(); + } else { + set = new Set(['value1']); + set.add('value2'); + equal('{{ set | length }}', { set: set }, '2'); + } + }); }); it('list', function(done) { @@ -454,9 +473,10 @@ }); it('random', function(done) { - for (var i = 0; i < 100; i++) { + var i; + for (i = 0; i < 100; i++) { render('{{ [1,2,3,4,5,6,7,8,9] | random }}', function(err, res) { - var val = parseInt(res); + var val = parseInt(res, 10); expect(val).to.be.within(1, 9); }); } @@ -741,7 +761,7 @@ }, '1=2&%261=%262'); equal('{{ obj | urlencode | safe }}', { obj: { - '1': 2, + 1: 2, '&1': '&2' } }, '1=2&%261=%262'); @@ -828,14 +848,14 @@ equal('{{ "testuser@testuser.com" | urlize | safe }}', 'testuser@testuser.com'); - //periods in the text + // periods in the text equal('{{ "foo." | urlize }}', 'foo.'); equal('{{ "foo.foo" | urlize }}', 'foo.foo'); - //markup in the text + // markup in the text equal('{{ "what up" | urlize | safe }}', 'what up'); - //breaklines and tabs in the text + // breaklines and tabs in the text equal('{{ "what\nup" | urlize | safe }}', 'what\nup'); equal('{{ "what\tup" | urlize | safe }}', 'what\tup'); @@ -844,13 +864,14 @@ it('wordcount', function(done) { equal('{{ "foo bar baz" | wordcount }}', '3'); - equal('{{ str | wordcount }}', { - str: r.markSafe('foo bar baz') - }, '3'); + equal( + '{{ str | wordcount }}', + { str: r.markSafe('foo bar baz') }, + '3'); equal('{{ null | wordcount }}', ''); equal('{{ undefined | wordcount }}', ''); equal('{{ nothing | wordcount }}', ''); finish(done); }); }); -})(); +}()); diff --git a/tests/globals.js b/tests/globals.js index 13d21079..775c285c 100644 --- a/tests/globals.js +++ b/tests/globals.js @@ -1,29 +1,26 @@ (function() { 'use strict'; - var expect, - util, - Environment, - Loader, - templatesPath; + var expect; + var util; + var Environment; + var equal; + var render; + var finish; if (typeof require !== 'undefined') { expect = require('expect.js'); util = require('./util'); - Environment = require('../src/environment').Environment; - Loader = require('../src/node-loaders').FileSystemLoader; - templatesPath = 'tests/templates'; + Environment = require('../nunjucks/src/environment').Environment; } else { expect = window.expect; util = window.util; Environment = nunjucks.Environment; - Loader = nunjucks.WebLoader; - templatesPath = '../templates'; } - var equal = util.equal; - var render = util.render; - var finish = util.finish; + equal = util.equal; + render = util.render; + finish = util.finish; describe('global', function() { it('should have range', function(done) { @@ -81,7 +78,7 @@ }); it('should allow addition of globals', function(done) { - var env = new Environment(new Loader(templatesPath)); + var env = new Environment(); env.addGlobal('hello', function(arg1) { return 'Hello ' + arg1; @@ -93,7 +90,7 @@ }); it('should allow chaining of globals', function(done) { - var env = new Environment(new Loader(templatesPath)); + var env = new Environment(); env.addGlobal('hello', function(arg1) { return 'Hello ' + arg1; @@ -108,7 +105,7 @@ }); it('should allow getting of globals', function(done) { - var env = new Environment(new Loader(templatesPath)); + var env = new Environment(); var hello = function(arg1) { return 'Hello ' + arg1; }; @@ -121,7 +118,7 @@ }); it('should allow getting boolean globals', function(done) { - var env = new Environment(new Loader(templatesPath)); + var env = new Environment(); var hello = false; env.addGlobal('hello', hello); @@ -132,7 +129,7 @@ }); it('should fail on getting non-existent global', function(done) { - var env = new Environment(new Loader(templatesPath)); + var env = new Environment(); // Using this format instead of .withArgs since env.getGlobal uses 'this' expect(function() { @@ -143,7 +140,7 @@ }); it('should pass context as this to global functions', function(done) { - var env = new Environment(new Loader(templatesPath)); + var env = new Environment(); env.addGlobal('hello', function() { return 'Hello ' + this.lookup('user'); @@ -156,11 +153,11 @@ }); it('should be exclusive to each environment', function(done) { - var env = new Environment(new Loader(templatesPath)); + var env = new Environment(); var env2; env.addGlobal('hello', 'konichiwa'); - env2 = new Environment(new Loader(templatesPath)); + env2 = new Environment(); // Using this format instead of .withArgs since env2.getGlobal uses 'this' expect(function() { @@ -171,7 +168,7 @@ }); it('should return errors from globals', function(done) { - var env = new Environment(new Loader(templatesPath)); + var env = new Environment(); env.addGlobal('err', function() { throw new Error('Global error'); @@ -186,4 +183,4 @@ finish(done); }); }); -})(); +}()); diff --git a/tests/jinja-compat.js b/tests/jinja-compat.js index 2110984d..f0e3b86b 100644 --- a/tests/jinja-compat.js +++ b/tests/jinja-compat.js @@ -2,6 +2,8 @@ 'use strict'; var util; + var equal; + var finish; if (typeof require !== 'undefined') { util = require('./util'); @@ -9,8 +11,8 @@ util = window.util; } - var equal = util.jinjaEqual; - var finish = util.finish; + equal = util.jinjaEqual; + finish = util.finish; describe('jinja-compat', function() { var arr = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']; @@ -121,4 +123,4 @@ finish(done); }); }); -})(); +}()); diff --git a/tests/lexer.js b/tests/lexer.js index 4cdb7648..0c406e54 100644 --- a/tests/lexer.js +++ b/tests/lexer.js @@ -1,14 +1,14 @@ (function() { 'use strict'; - var expect, - lib, - lexer; + var expect; + var lib; + var lexer; if (typeof require !== 'undefined') { expect = require('expect.js'); - lib = require('../src/lib'); - lexer = require('../src/lexer'); + lib = require('../nunjucks/src/lib'); + lexer = require('../nunjucks/src/lexer'); } else { expect = window.expect; lib = nunjucks.lib; @@ -16,9 +16,12 @@ } function _hasTokens(ws, tokens, types) { - for (var i = 0; i < types.length; i++) { - var type = types[i]; - var tok = tokens.nextToken(); + var i; + var type; + var tok; + for (i = 0; i < types.length; i++) { + type = types[i]; + tok = tokens.nextToken(); if (!ws) { while (tok && tok.type === lexer.TOKEN_WHITESPACE) { @@ -35,18 +38,18 @@ } } - function hasTokens(tokens /*, types */ ) { + function hasTokens(tokens /* , types */) { return _hasTokens(false, tokens, lib.toArray(arguments).slice(1)); } - function hasTokensWithWS(tokens /*, types */ ) { + function hasTokensWithWS(tokens /* , types */) { return _hasTokens(true, tokens, lib.toArray(arguments).slice(1)); } describe('lexer', function() { - var tok, - tmpl, - tokens; + var tok; + var tmpl; + var tokens; it('should parse template data', function() { tok = lexer.lex('3').nextToken(); @@ -200,7 +203,7 @@ lexer.TOKEN_STRING, lexer.TOKEN_REGEX, lexer.TOKEN_VARIABLE_END); - }), + }); it('should parse function calls', function() { tokens = lexer.lex('{{ foo(bar) }}'); @@ -277,7 +280,7 @@ lexer.TOKEN_PIPE, [lexer.TOKEN_SYMBOL, 'bar'], lexer.TOKEN_VARIABLE_END); - }), + }); it('should parse operators', function() { hasTokens(lexer.lex('{{ 3+3-3*3/3 }}'), @@ -318,7 +321,7 @@ lexer.TOKEN_OPERATOR, lexer.TOKEN_INT, lexer.TOKEN_VARIABLE_END); - }), + }); it('should parse comments', function() { tokens = lexer.lex('data data {# comment #} data'); @@ -326,7 +329,7 @@ lexer.TOKEN_DATA, lexer.TOKEN_COMMENT, lexer.TOKEN_DATA); - }), + }); it('should allow changing the variable start and end', function() { tokens = lexer.lex('data {= var =}', { @@ -340,7 +343,7 @@ lexer.TOKEN_VARIABLE_START, lexer.TOKEN_SYMBOL, lexer.TOKEN_VARIABLE_END); - }), + }); it('should allow changing the block start and end', function() { tokens = lexer.lex('{= =}', { @@ -352,7 +355,7 @@ hasTokens(tokens, lexer.TOKEN_BLOCK_START, lexer.TOKEN_BLOCK_END); - }), + }); it('should allow changing the variable start and end', function() { tokens = lexer.lex('data {= var =}', { @@ -366,7 +369,7 @@ lexer.TOKEN_VARIABLE_START, lexer.TOKEN_SYMBOL, lexer.TOKEN_VARIABLE_END); - }), + }); it('should allow changing the comment start and end', function() { tokens = lexer.lex('', { @@ -377,7 +380,7 @@ }); hasTokens(tokens, lexer.TOKEN_COMMENT); - }), + }); /** * Test that this bug is fixed: https://github.com/mozilla/nunjucks/issues/235 @@ -434,4 +437,4 @@ lexer.TOKEN_VARIABLE_END); }); }); -})(); +}()); diff --git a/tests/loader.js b/tests/loader.js index aee148e4..4c31428d 100644 --- a/tests/loader.js +++ b/tests/loader.js @@ -9,9 +9,9 @@ if (typeof require !== 'undefined') { expect = require('expect.js'); - Environment = require('../src/environment').Environment; - WebLoader = require('../src/web-loaders').WebLoader; - FileSystemLoader = require('../src/node-loaders').FileSystemLoader; + Environment = require('../nunjucks/src/environment').Environment; + WebLoader = require('../nunjucks/src/web-loaders').WebLoader; + FileSystemLoader = require('../nunjucks/src/node-loaders').FileSystemLoader; templatesPath = 'tests/templates'; } else { expect = window.expect; @@ -40,6 +40,8 @@ it('should allow a simple loader to be created', function() { // From Docs: http://mozilla.github.io/nunjucks/api.html#writing-a-loader // We should be able to create a loader that only exposes getSource + var env, parent; + function MyLoader() { // configuration } @@ -51,14 +53,16 @@ }; }; - var env = new Environment(new MyLoader(templatesPath)); - var parent = env.getTemplate('fake.njk'); + env = new Environment(new MyLoader(templatesPath)); + parent = env.getTemplate('fake.njk'); expect(parent.render()).to.be('Hello World'); }); it('should catch loader error', function(done) { // From Docs: http://mozilla.github.io/nunjucks/api.html#writing-a-loader // We should be able to create a loader that only exposes getSource + var env; + function MyLoader() { // configuration this.async = true; @@ -70,14 +74,13 @@ }, 1); }; - var env = new Environment(new MyLoader(templatesPath)); + env = new Environment(new MyLoader(templatesPath)); env.getTemplate('fake.njk', function(err, parent) { expect(err).to.be.a(Error); expect(parent).to.be(undefined); done(); }); - }); }); -})(); +}()); diff --git a/tests/parser.js b/tests/parser.js index 6a3c27e5..6ab3c579 100644 --- a/tests/parser.js +++ b/tests/parser.js @@ -8,9 +8,9 @@ if (typeof require !== 'undefined') { expect = require('expect.js'); - lib = require('../src/lib'); - nodes = require('../src/nodes'); - parser = require('../src/parser'); + lib = require('../nunjucks/src/lib'); + nodes = require('../nunjucks/src/nodes'); + parser = require('../nunjucks/src/parser'); } else { expect = window.expect; lib = nunjucks.lib; @@ -21,6 +21,7 @@ function _isAST(node1, node2) { // Compare ASTs // TODO: Clean this up (seriously, really) + /* eslint-disable vars-on-top */ expect(node1.typename).to.be(node2.typename); @@ -33,8 +34,8 @@ expect(sig1).to.be(sig2); - for (var i = 0, l = node2.children.length; i < l; i++) { - _isAST(node1.children[i], node2.children[i]); + for (var n = 0, l = node2.children.length; n < l; n++) { + _isAST(node1.children[n], node2.children[n]); } } else { node2.iterFields(function(value, field) { @@ -93,23 +94,23 @@ return ast; } - var type = ast[0]; + var Type = ast[0]; // some nodes have fields (e.g. Compare.ops) which are plain arrays - if (type instanceof Array) { + if (Type instanceof Array) { return lib.map(ast, toNodes); } var F = function() {}; - F.prototype = type.prototype; + F.prototype = Type.prototype; var dummy = new F(); if (dummy instanceof nodes.NodeList) { - return new type(0, 0, lib.map(ast.slice(1), toNodes)); + return new Type(0, 0, lib.map(ast.slice(1), toNodes)); } else if (dummy instanceof nodes.CallExtension) { - return new type(ast[1], ast[2], ast[3] ? toNodes(ast[3]) : ast[3], + return new Type(ast[1], ast[2], ast[3] ? toNodes(ast[3]) : ast[3], lib.isArray(ast[4]) ? lib.map(ast[4], toNodes) : ast[4]); } else { - return new type(0, 0, + return new Type(0, 0, toNodes(ast[1]), toNodes(ast[2]), toNodes(ast[3]), @@ -331,7 +332,6 @@ }); it('should parse include tags', function() { - var n = parser.parse('{% include "test.njk" %}'); expect(n.children[0].typename).to.be('Include'); @@ -353,7 +353,6 @@ [nodes.NodeList, [nodes.Output, [nodes.Symbol, 'x']]]]]); - }); it('should parse for loops with else', function() { @@ -368,7 +367,6 @@ [nodes.NodeList, [nodes.Output, [nodes.TemplateData, 'empty']]]]]); - }); it('should parse filters', function() { @@ -805,7 +803,6 @@ [nodes.TemplateData, ' ']], [nodes.Output, [nodes.Symbol, 'z']]]]]); - }); it('should throw errors', function() { @@ -863,9 +860,8 @@ }); it('should parse custom tags', function() { - - function testtagExtension() { - // jshint validthis: true + function TestTagExtension() { + /* eslint-disable no-shadow */ this.tags = ['testtag']; /* normally this is automatically done by Environment */ @@ -878,8 +874,8 @@ }; } - function testblocktagExtension() { - // jshint validthis: true + function TestBlockTagExtension() { + /* eslint-disable no-shadow */ this.tags = ['testblocktag']; this._name = 'testblocktagExtension'; @@ -895,8 +891,8 @@ }; } - function testargsExtension() { - // jshint validthis: true + function TestArgsExtension() { + /* eslint-disable no-shadow */ this.tags = ['testargs']; this._name = 'testargsExtension'; @@ -914,9 +910,9 @@ }; } - var extensions = [new testtagExtension(), - new testblocktagExtension(), - new testargsExtension()]; + var extensions = [new TestTagExtension(), + new TestBlockTagExtension(), + new TestArgsExtension()]; isAST(parser.parse('{% testtag %}', extensions), [nodes.Root, @@ -955,4 +951,4 @@ [nodes.CallExtension, extensions[2], 'biz', null]]); }); }); -})(); +}()); diff --git a/tests/precompile.js b/tests/precompile.js index 0a3eac76..2330a3f6 100644 --- a/tests/precompile.js +++ b/tests/precompile.js @@ -7,8 +7,8 @@ if (typeof require !== 'undefined') { expect = require('expect.js'); - precompile = require('../src/precompile').precompile; - precompileString = require('../src/precompile').precompileString; + precompile = require('../nunjucks/src/precompile').precompile; + precompileString = require('../nunjucks/src/precompile').precompileString; } else { expect = window.expect; precompile = nunjucks.precompile; @@ -50,4 +50,4 @@ }); }); }); -})(); +}()); diff --git a/tests/runtime.js b/tests/runtime.js index 58a2861b..4b104f6b 100644 --- a/tests/runtime.js +++ b/tests/runtime.js @@ -1,8 +1,7 @@ (function() { 'use strict'; - var expect, - util; + var expect, util, finish, render; if (typeof require !== 'undefined') { expect = require('expect.js'); @@ -12,8 +11,8 @@ util = window.util; } - var finish = util.finish; - var render = util.render; + finish = util.finish; + render = util.render; describe('runtime', function() { it('should report the failed function calls to symbols', function(done) { @@ -112,4 +111,4 @@ finish(done); }); }); -})(); +}()); diff --git a/tests/setup.js b/tests/setup.js new file mode 100644 index 00000000..0f9538e0 --- /dev/null +++ b/tests/setup.js @@ -0,0 +1,2 @@ +process.env.NODE_ENV = 'test'; + diff --git a/tests/tests.js b/tests/tests.js index 1299f4b6..ccbb1067 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -1,7 +1,7 @@ (function() { 'use strict'; - var expect, util; + var expect, util, render, equal; if (typeof require !== 'undefined') { expect = require('expect.js'); @@ -11,7 +11,8 @@ util = window.util; } - var render = util.render; + render = util.render; + equal = util.equal; describe('tests', function() { it('callable should detect callability', function() { @@ -93,16 +94,22 @@ }); it('mapping should detect Maps or hashes', function() { - var map1 = new Map(); - var map2 = {}; - var mapOneIsMapping = render('{{ map is mapping }}', { - map: map1 - }); - var mapTwoIsMapping = render('{{ map is mapping }}', { - map: map2 - }); - expect(mapOneIsMapping).to.be('true'); - expect(mapTwoIsMapping).to.be('true'); + /* global Map */ + var map1, map2, mapOneIsMapping, mapTwoIsMapping; + if (typeof Map === 'undefined') { + this.skip(); + } else { + map1 = new Map(); + map2 = {}; + mapOneIsMapping = render('{{ map is mapping }}', { + map: map1 + }); + mapTwoIsMapping = render('{{ map is mapping }}', { + map: map2 + }); + expect(mapOneIsMapping).to.be('true'); + expect(mapTwoIsMapping).to.be('true'); + } }); it('falsy should detect whether or not a value is falsy', function() { @@ -154,26 +161,38 @@ expect(four).to.be('false'); }); - it('iterable should detect whether or not a value is iterable', function() { - var iterable = (function* iterable() { - yield true; - }()); - var generatorIsIterable = render('{{ fn is iterable }}', { - fn: iterable - }); - var arrayIsNotIterable = render('{{ arr is not iterable }}', { - arr: [] - }); - var mapIsIterable = render('{{ map is iterable }}', { - map: new Map() - }); - var setIsNotIterable = render('{{ set is not iterable }}', { - set: new Set() - }); - expect(generatorIsIterable).to.be('true'); - expect(arrayIsNotIterable).to.be('false'); - expect(mapIsIterable).to.be('true'); - expect(setIsNotIterable).to.be('false'); + it('iterable should detect that a generator is iterable', function(done) { + /* eslint-disable no-eval */ + var iterable; + try { + iterable = eval('(function* iterable() { yield true; })()'); + } catch (e) { + return this.skip(); // Browser does not support generators + } + equal('{{ fn is iterable }}', { fn: iterable }, 'true'); + return done(); + }); + + it('iterable should detect that an Array is not non-iterable', function() { + equal('{{ arr is not iterable }}', { arr: [] }, 'false'); + }); + + it('iterable should detect that a Map is iterable', function() { + /* global Map */ + if (typeof Map === 'undefined') { + this.skip(); + } else { + equal('{{ map is iterable }}', { map: new Map() }, 'true'); + } + }); + + it('iterable should detect that a Set is not non-iterable', function() { + /* global Set */ + if (typeof Set === 'undefined') { + this.skip(); + } else { + equal('{{ set is not iterable }}', { set: new Set() }, 'false'); + } }); it('number should detect whether a value is numeric', function() { @@ -216,4 +235,4 @@ expect(render('{{ "Foobar" is upper }}')).to.be('false'); }); }); -})(); +}()); diff --git a/tests/util.js b/tests/util.js index 0abcd4a3..52afb39b 100644 --- a/tests/util.js +++ b/tests/util.js @@ -1,24 +1,38 @@ (function() { + /* eslint-disable vars-on-top */ + 'use strict'; var nunjucks, + nunjucksFull, + isSlim = false, Environment, Template, Loader, + precompileString, templatesPath, expect; - if (typeof require !== 'undefined') { - nunjucks = require('../index.js'); + if (typeof window === 'undefined') { + nunjucks = nunjucksFull = require('../nunjucks/index.js'); Loader = nunjucks.FileSystemLoader; templatesPath = 'tests/templates'; expect = require('expect.js'); } else { nunjucks = window.nunjucks; - Loader = nunjucks.WebLoader; + if (window.nunjucksFull) { + isSlim = true; + nunjucksFull = window.nunjucksFull; + // These must be the same for instanceof checks to succeed + nunjucksFull.runtime.SafeString.prototype = nunjucks.runtime.SafeString.prototype; + } else { + nunjucksFull = window.nunjucksFull = nunjucks; + } + Loader = nunjucksFull.WebLoader; templatesPath = '../templates'; expect = window.expect; } + precompileString = nunjucksFull.precompileString; Environment = nunjucks.Environment; Template = nunjucks.Template; @@ -30,23 +44,34 @@ doneHandler = null; }); - function equal(str, ctx, str2, env) { + function equal(str, ctx, opts, str2, env) { if (typeof ctx === 'string') { - env = str2; + env = opts; str2 = ctx; ctx = null; + opts = {}; } - - var res = render(str, ctx, {}, env); + if (typeof opts === 'string') { + env = str2; + str2 = opts; + opts = {}; + } + opts = opts || {}; + var res = render(str, ctx, opts, env); expect(res).to.be(str2); } function jinjaEqual(str, ctx, str2, env) { - var jinjaUninstall = nunjucks.installJinjaCompat(); + var jinjaUninstalls = [nunjucks.installJinjaCompat()]; + if (nunjucksFull !== nunjucks) { + jinjaUninstalls.push(nunjucksFull.installJinjaCompat()); + } try { return equal(str, ctx, str2, env); } finally { - jinjaUninstall(); + for (var i = 0; i < jinjaUninstalls.length; i++) { + jinjaUninstalls[i](); + } } } @@ -65,6 +90,12 @@ return str.replace(/\r\n|\r/g, '\n'); } + function randomTemplateName() { + var rand = Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5); + return rand + '.njk'; + } + + // eslint-disable-next-line consistent-return function render(str, ctx, opts, env, cb) { if (typeof ctx === 'function') { cb = ctx; @@ -82,29 +113,64 @@ opts = opts || {}; opts.dev = true; - var e = env || new Environment(new Loader(templatesPath), opts); + + var loader; + var e; + + if (isSlim) { + e = env || new Environment([], opts); + loader = e.loaders[0]; + } else { + loader = new Loader(templatesPath); + e = env || new Environment(loader, opts); + } var name; if (opts.filters) { for (name in opts.filters) { - e.addFilter(name, opts.filters[name]); + if (Object.prototype.hasOwnProperty.call(opts.filters, name)) { + e.addFilter(name, opts.filters[name]); + } } } if (opts.asyncFilters) { for (name in opts.asyncFilters) { - e.addFilter(name, opts.asyncFilters[name], true); + if (Object.prototype.hasOwnProperty.call(opts.asyncFilters, name)) { + e.addFilter(name, opts.asyncFilters[name], true); + } } } if (opts.extensions) { for (name in opts.extensions) { - e.addExtension(name, opts.extensions[name]); + if (Object.prototype.hasOwnProperty.call(opts.extensions, name)) { + e.addExtension(name, opts.extensions[name]); + } } } + var tmplName; + if (isSlim) { + tmplName = randomTemplateName(); + var precompileJs = precompileString(str, { + name: tmplName, + asFunction: true, + env: e + }); + eval(precompileJs); // eslint-disable-line no-eval + } + ctx = ctx || {}; - var t = new Template(str, e); + + var t; + + if (isSlim) { + var tmplSource = loader.getSource(tmplName); + t = new Template(tmplSource.src, e, tmplSource.path); + } else { + t = new Template(str, e); + } if (!cb) { return t.render(ctx); @@ -115,7 +181,17 @@ throw err; } - cb(err, normEOL(res)); + try { + cb(err, normEOL(res)); + } catch (exc) { + if (doneHandler) { + doneHandler(exc); + numAsyncs = 0; + doneHandler = null; + } else { + throw exc; + } + } numAsyncs--; @@ -126,19 +202,21 @@ } } - if (typeof module !== 'undefined') { + if (typeof window === 'undefined') { module.exports.render = render; module.exports.equal = equal; module.exports.jinjaEqual = jinjaEqual; module.exports.finish = finish; module.exports.normEOL = normEOL; + module.exports.isSlim = isSlim; } else { window.util = { render: render, equal: equal, jinjaEqual: jinjaEqual, finish: finish, - normEOL: normEOL + normEOL: normEOL, + isSlim: isSlim }; } -})(); +}());