mirror of
https://github.com/atlanticbiomedical/biomedjs.git
synced 2025-07-02 00:47:26 -04:00
6709 lines
178 KiB
JavaScript
6709 lines
178 KiB
JavaScript
(function(e){if("function"==typeof bootstrap)bootstrap("jade",e);else if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeJade=e}else"undefined"!=typeof window?window.jade=e():global.jade=e()})(function(){var define,ses,bootstrap,module,exports;
|
|
return (function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require=="function"&&require;for(var s=0;s<n.length;s++)i(n[s]);return i})({1:[function(require,module,exports){
|
|
// nothing to see here... no file methods for the browser
|
|
|
|
},{}],2:[function(require,module,exports){
|
|
|
|
/*!
|
|
* Jade - runtime
|
|
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
/**
|
|
* Lame Array.isArray() polyfill for now.
|
|
*/
|
|
|
|
if (!Array.isArray) {
|
|
Array.isArray = function(arr){
|
|
return '[object Array]' == Object.prototype.toString.call(arr);
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Lame Object.keys() polyfill for now.
|
|
*/
|
|
|
|
if (!Object.keys) {
|
|
Object.keys = function(obj){
|
|
var arr = [];
|
|
for (var key in obj) {
|
|
if (obj.hasOwnProperty(key)) {
|
|
arr.push(key);
|
|
}
|
|
}
|
|
return arr;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Merge two attribute objects giving precedence
|
|
* to values in object `b`. Classes are special-cased
|
|
* allowing for arrays and merging/joining appropriately
|
|
* resulting in a string.
|
|
*
|
|
* @param {Object} a
|
|
* @param {Object} b
|
|
* @return {Object} a
|
|
* @api private
|
|
*/
|
|
|
|
exports.merge = function merge(a, b) {
|
|
var ac = a['class'];
|
|
var bc = b['class'];
|
|
|
|
if (ac || bc) {
|
|
ac = ac || [];
|
|
bc = bc || [];
|
|
if (!Array.isArray(ac)) ac = [ac];
|
|
if (!Array.isArray(bc)) bc = [bc];
|
|
a['class'] = ac.concat(bc).filter(nulls);
|
|
}
|
|
|
|
for (var key in b) {
|
|
if (key != 'class') {
|
|
a[key] = b[key];
|
|
}
|
|
}
|
|
|
|
return a;
|
|
};
|
|
|
|
/**
|
|
* Filter null `val`s.
|
|
*
|
|
* @param {*} val
|
|
* @return {Boolean}
|
|
* @api private
|
|
*/
|
|
|
|
function nulls(val) {
|
|
return val != null && val !== '';
|
|
}
|
|
|
|
/**
|
|
* join array as classes.
|
|
*
|
|
* @param {*} val
|
|
* @return {String}
|
|
* @api private
|
|
*/
|
|
|
|
function joinClasses(val) {
|
|
return Array.isArray(val) ? val.map(joinClasses).filter(nulls).join(' ') : val;
|
|
}
|
|
|
|
/**
|
|
* Render the given attributes object.
|
|
*
|
|
* @param {Object} obj
|
|
* @param {Object} escaped
|
|
* @return {String}
|
|
* @api private
|
|
*/
|
|
|
|
exports.attrs = function attrs(obj, escaped){
|
|
var buf = []
|
|
, terse = obj.terse;
|
|
|
|
delete obj.terse;
|
|
var keys = Object.keys(obj)
|
|
, len = keys.length;
|
|
|
|
if (len) {
|
|
buf.push('');
|
|
for (var i = 0; i < len; ++i) {
|
|
var key = keys[i]
|
|
, val = obj[key];
|
|
|
|
if ('boolean' == typeof val || null == val) {
|
|
if (val) {
|
|
terse
|
|
? buf.push(key)
|
|
: buf.push(key + '="' + key + '"');
|
|
}
|
|
} else if (0 == key.indexOf('data') && 'string' != typeof val) {
|
|
buf.push(key + "='" + JSON.stringify(val) + "'");
|
|
} else if ('class' == key) {
|
|
if (escaped && escaped[key]){
|
|
if (val = exports.escape(joinClasses(val))) {
|
|
buf.push(key + '="' + val + '"');
|
|
}
|
|
} else {
|
|
if (val = joinClasses(val)) {
|
|
buf.push(key + '="' + val + '"');
|
|
}
|
|
}
|
|
} else if (escaped && escaped[key]) {
|
|
buf.push(key + '="' + exports.escape(val) + '"');
|
|
} else {
|
|
buf.push(key + '="' + val + '"');
|
|
}
|
|
}
|
|
}
|
|
|
|
return buf.join(' ');
|
|
};
|
|
|
|
/**
|
|
* Escape the given string of `html`.
|
|
*
|
|
* @param {String} html
|
|
* @return {String}
|
|
* @api private
|
|
*/
|
|
|
|
exports.escape = function escape(html){
|
|
return String(html)
|
|
.replace(/&/g, '&')
|
|
.replace(/</g, '<')
|
|
.replace(/>/g, '>')
|
|
.replace(/"/g, '"');
|
|
};
|
|
|
|
/**
|
|
* Re-throw the given `err` in context to the
|
|
* the jade in `filename` at the given `lineno`.
|
|
*
|
|
* @param {Error} err
|
|
* @param {String} filename
|
|
* @param {String} lineno
|
|
* @api private
|
|
*/
|
|
|
|
exports.rethrow = function rethrow(err, filename, lineno, str){
|
|
if (!(err instanceof Error)) throw err;
|
|
if ((typeof window != 'undefined' || !filename) && !str) {
|
|
err.message += ' on line ' + lineno;
|
|
throw err;
|
|
}
|
|
try {
|
|
str = str || require('fs').readFileSync(filename, 'utf8')
|
|
} catch (ex) {
|
|
rethrow(err, null, lineno)
|
|
}
|
|
var context = 3
|
|
, lines = str.split('\n')
|
|
, start = Math.max(lineno - context, 0)
|
|
, end = Math.min(lines.length, lineno + context);
|
|
|
|
// Error context
|
|
var context = lines.slice(start, end).map(function(line, i){
|
|
var curr = i + start + 1;
|
|
return (curr == lineno ? ' > ' : ' ')
|
|
+ curr
|
|
+ '| '
|
|
+ line;
|
|
}).join('\n');
|
|
|
|
// Alter exception message
|
|
err.path = filename;
|
|
err.message = (filename || 'Jade') + ':' + lineno
|
|
+ '\n' + context + '\n\n' + err.message;
|
|
throw err;
|
|
};
|
|
|
|
},{"fs":1}],3:[function(require,module,exports){
|
|
|
|
/*!
|
|
* Jade - doctypes
|
|
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
module.exports = {
|
|
'5': '<!DOCTYPE html>'
|
|
, 'default': '<!DOCTYPE html>'
|
|
, 'xml': '<?xml version="1.0" encoding="utf-8" ?>'
|
|
, 'transitional': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
|
|
, 'strict': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
|
|
, 'frameset': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">'
|
|
, '1.1': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
|
|
, 'basic': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">'
|
|
, 'mobile': '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">'
|
|
};
|
|
},{}],4:[function(require,module,exports){
|
|
|
|
/*!
|
|
* Jade - self closing tags
|
|
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
module.exports = [
|
|
'meta'
|
|
, 'img'
|
|
, 'link'
|
|
, 'input'
|
|
, 'source'
|
|
, 'area'
|
|
, 'base'
|
|
, 'col'
|
|
, 'br'
|
|
, 'hr'
|
|
];
|
|
},{}],5:[function(require,module,exports){
|
|
|
|
/*!
|
|
* Jade - utils
|
|
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
/**
|
|
* Merge `b` into `a`.
|
|
*
|
|
* @param {Object} a
|
|
* @param {Object} b
|
|
* @return {Object}
|
|
* @api public
|
|
*/
|
|
|
|
exports.merge = function(a, b) {
|
|
for (var key in b) a[key] = b[key];
|
|
return a;
|
|
};
|
|
|
|
|
|
},{}],6:[function(require,module,exports){
|
|
/*!
|
|
* Jade - filters
|
|
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
module.exports = filter;
|
|
function filter(name, str, options) {
|
|
if (typeof filter[name] === 'function') {
|
|
var res = filter[name](str, options);
|
|
} else {
|
|
throw new Error('unknown filter ":' + name + '"');
|
|
}
|
|
return res;
|
|
}
|
|
filter.exists = function (name, str, options) {
|
|
return typeof filter[name] === 'function';
|
|
};
|
|
|
|
},{}],7:[function(require,module,exports){
|
|
// shim for using process in browser
|
|
|
|
var process = module.exports = {};
|
|
|
|
process.nextTick = (function () {
|
|
var canSetImmediate = typeof window !== 'undefined'
|
|
&& window.setImmediate;
|
|
var canPost = typeof window !== 'undefined'
|
|
&& window.postMessage && window.addEventListener
|
|
;
|
|
|
|
if (canSetImmediate) {
|
|
return function (f) { return window.setImmediate(f) };
|
|
}
|
|
|
|
if (canPost) {
|
|
var queue = [];
|
|
window.addEventListener('message', function (ev) {
|
|
if (ev.source === window && ev.data === 'process-tick') {
|
|
ev.stopPropagation();
|
|
if (queue.length > 0) {
|
|
var fn = queue.shift();
|
|
fn();
|
|
}
|
|
}
|
|
}, true);
|
|
|
|
return function nextTick(fn) {
|
|
queue.push(fn);
|
|
window.postMessage('process-tick', '*');
|
|
};
|
|
}
|
|
|
|
return function nextTick(fn) {
|
|
setTimeout(fn, 0);
|
|
};
|
|
})();
|
|
|
|
process.title = 'browser';
|
|
process.browser = true;
|
|
process.env = {};
|
|
process.argv = [];
|
|
|
|
process.binding = function (name) {
|
|
throw new Error('process.binding is not supported');
|
|
}
|
|
|
|
// TODO(shtylman)
|
|
process.cwd = function () { return '/' };
|
|
process.chdir = function (dir) {
|
|
throw new Error('process.chdir is not supported');
|
|
};
|
|
|
|
},{}],8:[function(require,module,exports){
|
|
(function(process){function filter (xs, fn) {
|
|
var res = [];
|
|
for (var i = 0; i < xs.length; i++) {
|
|
if (fn(xs[i], i, xs)) res.push(xs[i]);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
// resolves . and .. elements in a path array with directory names there
|
|
// must be no slashes, empty elements, or device names (c:\) in the array
|
|
// (so also no leading and trailing slashes - it does not distinguish
|
|
// relative and absolute paths)
|
|
function normalizeArray(parts, allowAboveRoot) {
|
|
// if the path tries to go above the root, `up` ends up > 0
|
|
var up = 0;
|
|
for (var i = parts.length; i >= 0; i--) {
|
|
var last = parts[i];
|
|
if (last == '.') {
|
|
parts.splice(i, 1);
|
|
} else if (last === '..') {
|
|
parts.splice(i, 1);
|
|
up++;
|
|
} else if (up) {
|
|
parts.splice(i, 1);
|
|
up--;
|
|
}
|
|
}
|
|
|
|
// if the path is allowed to go above the root, restore leading ..s
|
|
if (allowAboveRoot) {
|
|
for (; up--; up) {
|
|
parts.unshift('..');
|
|
}
|
|
}
|
|
|
|
return parts;
|
|
}
|
|
|
|
// Regex to split a filename into [*, dir, basename, ext]
|
|
// posix version
|
|
var splitPathRe = /^(.+\/(?!$)|\/)?((?:.+?)?(\.[^.]*)?)$/;
|
|
|
|
// path.resolve([from ...], to)
|
|
// posix version
|
|
exports.resolve = function() {
|
|
var resolvedPath = '',
|
|
resolvedAbsolute = false;
|
|
|
|
for (var i = arguments.length; i >= -1 && !resolvedAbsolute; i--) {
|
|
var path = (i >= 0)
|
|
? arguments[i]
|
|
: process.cwd();
|
|
|
|
// Skip empty and invalid entries
|
|
if (typeof path !== 'string' || !path) {
|
|
continue;
|
|
}
|
|
|
|
resolvedPath = path + '/' + resolvedPath;
|
|
resolvedAbsolute = path.charAt(0) === '/';
|
|
}
|
|
|
|
// At this point the path should be resolved to a full absolute path, but
|
|
// handle relative paths to be safe (might happen when process.cwd() fails)
|
|
|
|
// Normalize the path
|
|
resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) {
|
|
return !!p;
|
|
}), !resolvedAbsolute).join('/');
|
|
|
|
return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
|
|
};
|
|
|
|
// path.normalize(path)
|
|
// posix version
|
|
exports.normalize = function(path) {
|
|
var isAbsolute = path.charAt(0) === '/',
|
|
trailingSlash = path.slice(-1) === '/';
|
|
|
|
// Normalize the path
|
|
path = normalizeArray(filter(path.split('/'), function(p) {
|
|
return !!p;
|
|
}), !isAbsolute).join('/');
|
|
|
|
if (!path && !isAbsolute) {
|
|
path = '.';
|
|
}
|
|
if (path && trailingSlash) {
|
|
path += '/';
|
|
}
|
|
|
|
return (isAbsolute ? '/' : '') + path;
|
|
};
|
|
|
|
|
|
// posix version
|
|
exports.join = function() {
|
|
var paths = Array.prototype.slice.call(arguments, 0);
|
|
return exports.normalize(filter(paths, function(p, index) {
|
|
return p && typeof p === 'string';
|
|
}).join('/'));
|
|
};
|
|
|
|
|
|
exports.dirname = function(path) {
|
|
var dir = splitPathRe.exec(path)[1] || '';
|
|
var isWindows = false;
|
|
if (!dir) {
|
|
// No dirname
|
|
return '.';
|
|
} else if (dir.length === 1 ||
|
|
(isWindows && dir.length <= 3 && dir.charAt(1) === ':')) {
|
|
// It is just a slash or a drive letter with a slash
|
|
return dir;
|
|
} else {
|
|
// It is a full dirname, strip trailing slash
|
|
return dir.substring(0, dir.length - 1);
|
|
}
|
|
};
|
|
|
|
|
|
exports.basename = function(path, ext) {
|
|
var f = splitPathRe.exec(path)[2] || '';
|
|
// TODO: make this comparison case-insensitive on windows?
|
|
if (ext && f.substr(-1 * ext.length) === ext) {
|
|
f = f.substr(0, f.length - ext.length);
|
|
}
|
|
return f;
|
|
};
|
|
|
|
|
|
exports.extname = function(path) {
|
|
return splitPathRe.exec(path)[3] || '';
|
|
};
|
|
|
|
exports.relative = function(from, to) {
|
|
from = exports.resolve(from).substr(1);
|
|
to = exports.resolve(to).substr(1);
|
|
|
|
function trim(arr) {
|
|
var start = 0;
|
|
for (; start < arr.length; start++) {
|
|
if (arr[start] !== '') break;
|
|
}
|
|
|
|
var end = arr.length - 1;
|
|
for (; end >= 0; end--) {
|
|
if (arr[end] !== '') break;
|
|
}
|
|
|
|
if (start > end) return [];
|
|
return arr.slice(start, end - start + 1);
|
|
}
|
|
|
|
var fromParts = trim(from.split('/'));
|
|
var toParts = trim(to.split('/'));
|
|
|
|
var length = Math.min(fromParts.length, toParts.length);
|
|
var samePartsLength = length;
|
|
for (var i = 0; i < length; i++) {
|
|
if (fromParts[i] !== toParts[i]) {
|
|
samePartsLength = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
var outputParts = [];
|
|
for (var i = samePartsLength; i < fromParts.length; i++) {
|
|
outputParts.push('..');
|
|
}
|
|
|
|
outputParts = outputParts.concat(toParts.slice(samePartsLength));
|
|
|
|
return outputParts.join('/');
|
|
};
|
|
|
|
})(require("__browserify_process"))
|
|
},{"__browserify_process":7}],9:[function(require,module,exports){
|
|
/*!
|
|
* Jade
|
|
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
/**
|
|
* Module dependencies.
|
|
*/
|
|
|
|
var Parser = require('./parser')
|
|
, Lexer = require('./lexer')
|
|
, Compiler = require('./compiler')
|
|
, runtime = require('./runtime')
|
|
, addWith = require('with')
|
|
, fs = require('fs');
|
|
|
|
/**
|
|
* Expose self closing tags.
|
|
*/
|
|
|
|
exports.selfClosing = require('./self-closing');
|
|
|
|
/**
|
|
* Default supported doctypes.
|
|
*/
|
|
|
|
exports.doctypes = require('./doctypes');
|
|
|
|
/**
|
|
* Text filters.
|
|
*/
|
|
|
|
exports.filters = require('./filters');
|
|
|
|
/**
|
|
* Utilities.
|
|
*/
|
|
|
|
exports.utils = require('./utils');
|
|
|
|
/**
|
|
* Expose `Compiler`.
|
|
*/
|
|
|
|
exports.Compiler = Compiler;
|
|
|
|
/**
|
|
* Expose `Parser`.
|
|
*/
|
|
|
|
exports.Parser = Parser;
|
|
|
|
/**
|
|
* Expose `Lexer`.
|
|
*/
|
|
|
|
exports.Lexer = Lexer;
|
|
|
|
/**
|
|
* Nodes.
|
|
*/
|
|
|
|
exports.nodes = require('./nodes');
|
|
|
|
/**
|
|
* Jade runtime helpers.
|
|
*/
|
|
|
|
exports.runtime = runtime;
|
|
|
|
/**
|
|
* Template function cache.
|
|
*/
|
|
|
|
exports.cache = {};
|
|
|
|
/**
|
|
* Parse the given `str` of jade and return a function body.
|
|
*
|
|
* @param {String} str
|
|
* @param {Object} options
|
|
* @return {String}
|
|
* @api private
|
|
*/
|
|
|
|
function parse(str, options){
|
|
try {
|
|
// Parse
|
|
var parser = new (options.parser || Parser)(str, options.filename, options);
|
|
|
|
// Compile
|
|
var compiler = new (options.compiler || Compiler)(parser.parse(), options)
|
|
, js = compiler.compile();
|
|
|
|
// Debug compiler
|
|
if (options.debug) {
|
|
console.error('\nCompiled Function:\n\n\033[90m%s\033[0m', js.replace(/^/gm, ' '));
|
|
}
|
|
|
|
return ''
|
|
+ 'var buf = [];\n'
|
|
+ (options.self
|
|
? 'var self = locals || {};\n' + js
|
|
: addWith('locals || {}', js, ['jade', 'buf'])) + ';'
|
|
+ 'return buf.join("");';
|
|
} catch (err) {
|
|
parser = parser.context();
|
|
runtime.rethrow(err, parser.filename, parser.lexer.lineno, str);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Strip any UTF-8 BOM off of the start of `str`, if it exists.
|
|
*
|
|
* @param {String} str
|
|
* @return {String}
|
|
* @api private
|
|
*/
|
|
|
|
function stripBOM(str){
|
|
return 0xFEFF == str.charCodeAt(0)
|
|
? str.substring(1)
|
|
: str;
|
|
}
|
|
|
|
/**
|
|
* Compile a `Function` representation of the given jade `str`.
|
|
*
|
|
* Options:
|
|
*
|
|
* - `compileDebug` when `false` debugging code is stripped from the compiled
|
|
template, when it is explicitly `true`, the source code is included in
|
|
the compiled template for better accuracy.
|
|
* - `filename` used to improve errors when `compileDebug` is not `false`
|
|
*
|
|
* @param {String} str
|
|
* @param {Options} options
|
|
* @return {Function}
|
|
* @api public
|
|
*/
|
|
|
|
exports.compile = function(str, options){
|
|
var options = options || {}
|
|
, filename = options.filename
|
|
? JSON.stringify(options.filename)
|
|
: 'undefined'
|
|
, fn;
|
|
|
|
str = stripBOM(String(str));
|
|
|
|
if (options.compileDebug !== false) {
|
|
fn = [
|
|
'jade.debug = [{ lineno: 1, filename: ' + filename + ' }];'
|
|
, 'try {'
|
|
, parse(str, options)
|
|
, '} catch (err) {'
|
|
, ' jade.rethrow(err, jade.debug[0].filename, jade.debug[0].lineno' + (options.compileDebug === true ? ',' + JSON.stringify(str) : '') + ');'
|
|
, '}'
|
|
].join('\n');
|
|
} else {
|
|
fn = parse(str, options);
|
|
}
|
|
|
|
if (options.client) return new Function('locals', fn)
|
|
fn = new Function('locals, jade', fn)
|
|
return function(locals){ return fn(locals, Object.create(runtime)) }
|
|
};
|
|
|
|
/**
|
|
* Render the given `str` of jade and invoke
|
|
* the callback `fn(err, str)`.
|
|
*
|
|
* Options:
|
|
*
|
|
* - `cache` enable template caching
|
|
* - `filename` filename required for `include` / `extends` and caching
|
|
*
|
|
* @param {String} str
|
|
* @param {Object|Function} options or fn
|
|
* @param {Function} fn
|
|
* @api public
|
|
*/
|
|
|
|
exports.render = function(str, options, fn){
|
|
// swap args
|
|
if ('function' == typeof options) {
|
|
fn = options, options = {};
|
|
}
|
|
|
|
// cache requires .filename
|
|
if (options.cache && !options.filename) {
|
|
return fn(new Error('the "filename" option is required for caching'));
|
|
}
|
|
|
|
try {
|
|
var path = options.filename;
|
|
var tmpl = options.cache
|
|
? exports.cache[path] || (exports.cache[path] = exports.compile(str, options))
|
|
: exports.compile(str, options);
|
|
fn(null, tmpl(options));
|
|
} catch (err) {
|
|
fn(err);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Render a Jade file at the given `path` and callback `fn(err, str)`.
|
|
*
|
|
* @param {String} path
|
|
* @param {Object|Function} options or callback
|
|
* @param {Function} fn
|
|
* @api public
|
|
*/
|
|
|
|
exports.renderFile = function(path, options, fn){
|
|
var key = path + ':string';
|
|
|
|
if ('function' == typeof options) {
|
|
fn = options, options = {};
|
|
}
|
|
|
|
try {
|
|
options.filename = path;
|
|
var str = options.cache
|
|
? exports.cache[key] || (exports.cache[key] = fs.readFileSync(path, 'utf8'))
|
|
: fs.readFileSync(path, 'utf8');
|
|
exports.render(str, options, fn);
|
|
} catch (err) {
|
|
fn(err);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Express support.
|
|
*/
|
|
|
|
exports.__express = exports.renderFile;
|
|
|
|
},{"fs":1,"./parser":10,"./compiler":11,"./lexer":12,"./runtime":2,"./self-closing":4,"./doctypes":3,"./filters":6,"./utils":5,"./nodes":13,"with":14}],10:[function(require,module,exports){
|
|
/*!
|
|
* Jade - Parser
|
|
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
/**
|
|
* Module dependencies.
|
|
*/
|
|
|
|
var Lexer = require('./lexer')
|
|
, nodes = require('./nodes')
|
|
, utils = require('./utils')
|
|
, filters = require('./filters')
|
|
, path = require('path')
|
|
, extname = path.extname;
|
|
|
|
/**
|
|
* Initialize `Parser` with the given input `str` and `filename`.
|
|
*
|
|
* @param {String} str
|
|
* @param {String} filename
|
|
* @param {Object} options
|
|
* @api public
|
|
*/
|
|
|
|
var Parser = exports = module.exports = function Parser(str, filename, options){
|
|
this.input = str;
|
|
this.lexer = new Lexer(str, options);
|
|
this.filename = filename;
|
|
this.blocks = {};
|
|
this.mixins = {};
|
|
this.options = options;
|
|
this.contexts = [this];
|
|
};
|
|
|
|
/**
|
|
* Tags that may not contain tags.
|
|
*/
|
|
|
|
var textOnly = exports.textOnly = ['script', 'style'];
|
|
|
|
/**
|
|
* Parser prototype.
|
|
*/
|
|
|
|
Parser.prototype = {
|
|
|
|
/**
|
|
* Push `parser` onto the context stack,
|
|
* or pop and return a `Parser`.
|
|
*/
|
|
|
|
context: function(parser){
|
|
if (parser) {
|
|
this.contexts.push(parser);
|
|
} else {
|
|
return this.contexts.pop();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Return the next token object.
|
|
*
|
|
* @return {Object}
|
|
* @api private
|
|
*/
|
|
|
|
advance: function(){
|
|
return this.lexer.advance();
|
|
},
|
|
|
|
/**
|
|
* Skip `n` tokens.
|
|
*
|
|
* @param {Number} n
|
|
* @api private
|
|
*/
|
|
|
|
skip: function(n){
|
|
while (n--) this.advance();
|
|
},
|
|
|
|
/**
|
|
* Single token lookahead.
|
|
*
|
|
* @return {Object}
|
|
* @api private
|
|
*/
|
|
|
|
peek: function() {
|
|
return this.lookahead(1);
|
|
},
|
|
|
|
/**
|
|
* Return lexer lineno.
|
|
*
|
|
* @return {Number}
|
|
* @api private
|
|
*/
|
|
|
|
line: function() {
|
|
return this.lexer.lineno;
|
|
},
|
|
|
|
/**
|
|
* `n` token lookahead.
|
|
*
|
|
* @param {Number} n
|
|
* @return {Object}
|
|
* @api private
|
|
*/
|
|
|
|
lookahead: function(n){
|
|
return this.lexer.lookahead(n);
|
|
},
|
|
|
|
/**
|
|
* Parse input returning a string of js for evaluation.
|
|
*
|
|
* @return {String}
|
|
* @api public
|
|
*/
|
|
|
|
parse: function(){
|
|
var block = new nodes.Block, parser;
|
|
block.line = this.line();
|
|
|
|
while ('eos' != this.peek().type) {
|
|
if ('newline' == this.peek().type) {
|
|
this.advance();
|
|
} else {
|
|
block.push(this.parseExpr());
|
|
}
|
|
}
|
|
|
|
if (parser = this.extending) {
|
|
this.context(parser);
|
|
var ast = parser.parse();
|
|
this.context();
|
|
|
|
// hoist mixins
|
|
for (var name in this.mixins)
|
|
ast.unshift(this.mixins[name]);
|
|
return ast;
|
|
}
|
|
|
|
return block;
|
|
},
|
|
|
|
/**
|
|
* Expect the given type, or throw an exception.
|
|
*
|
|
* @param {String} type
|
|
* @api private
|
|
*/
|
|
|
|
expect: function(type){
|
|
if (this.peek().type === type) {
|
|
return this.advance();
|
|
} else {
|
|
throw new Error('expected "' + type + '", but got "' + this.peek().type + '"');
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Accept the given `type`.
|
|
*
|
|
* @param {String} type
|
|
* @api private
|
|
*/
|
|
|
|
accept: function(type){
|
|
if (this.peek().type === type) {
|
|
return this.advance();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* tag
|
|
* | doctype
|
|
* | mixin
|
|
* | include
|
|
* | filter
|
|
* | comment
|
|
* | text
|
|
* | each
|
|
* | code
|
|
* | yield
|
|
* | id
|
|
* | class
|
|
* | interpolation
|
|
*/
|
|
|
|
parseExpr: function(){
|
|
switch (this.peek().type) {
|
|
case 'tag':
|
|
return this.parseTag();
|
|
case 'mixin':
|
|
return this.parseMixin();
|
|
case 'block':
|
|
return this.parseBlock();
|
|
case 'case':
|
|
return this.parseCase();
|
|
case 'when':
|
|
return this.parseWhen();
|
|
case 'default':
|
|
return this.parseDefault();
|
|
case 'extends':
|
|
return this.parseExtends();
|
|
case 'include':
|
|
return this.parseInclude();
|
|
case 'doctype':
|
|
return this.parseDoctype();
|
|
case 'filter':
|
|
return this.parseFilter();
|
|
case 'comment':
|
|
return this.parseComment();
|
|
case 'text':
|
|
return this.parseText();
|
|
case 'each':
|
|
return this.parseEach();
|
|
case 'code':
|
|
return this.parseCode();
|
|
case 'call':
|
|
return this.parseCall();
|
|
case 'interpolation':
|
|
return this.parseInterpolation();
|
|
case 'yield':
|
|
this.advance();
|
|
var block = new nodes.Block;
|
|
block.yield = true;
|
|
return block;
|
|
case 'id':
|
|
case 'class':
|
|
var tok = this.advance();
|
|
this.lexer.defer(this.lexer.tok('tag', 'div'));
|
|
this.lexer.defer(tok);
|
|
return this.parseExpr();
|
|
default:
|
|
throw new Error('unexpected token "' + this.peek().type + '"');
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Text
|
|
*/
|
|
|
|
parseText: function(){
|
|
var tok = this.expect('text');
|
|
var node = new nodes.Text(tok.val);
|
|
node.line = this.line();
|
|
return node;
|
|
},
|
|
|
|
/**
|
|
* ':' expr
|
|
* | block
|
|
*/
|
|
|
|
parseBlockExpansion: function(){
|
|
if (':' == this.peek().type) {
|
|
this.advance();
|
|
return new nodes.Block(this.parseExpr());
|
|
} else {
|
|
return this.block();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* case
|
|
*/
|
|
|
|
parseCase: function(){
|
|
var val = this.expect('case').val;
|
|
var node = new nodes.Case(val);
|
|
node.line = this.line();
|
|
node.block = this.block();
|
|
return node;
|
|
},
|
|
|
|
/**
|
|
* when
|
|
*/
|
|
|
|
parseWhen: function(){
|
|
var val = this.expect('when').val
|
|
return new nodes.Case.When(val, this.parseBlockExpansion());
|
|
},
|
|
|
|
/**
|
|
* default
|
|
*/
|
|
|
|
parseDefault: function(){
|
|
this.expect('default');
|
|
return new nodes.Case.When('default', this.parseBlockExpansion());
|
|
},
|
|
|
|
/**
|
|
* code
|
|
*/
|
|
|
|
parseCode: function(){
|
|
var tok = this.expect('code');
|
|
var node = new nodes.Code(tok.val, tok.buffer, tok.escape);
|
|
var block;
|
|
var i = 1;
|
|
node.line = this.line();
|
|
while (this.lookahead(i) && 'newline' == this.lookahead(i).type) ++i;
|
|
block = 'indent' == this.lookahead(i).type;
|
|
if (block) {
|
|
this.skip(i-1);
|
|
node.block = this.block();
|
|
}
|
|
return node;
|
|
},
|
|
|
|
/**
|
|
* comment
|
|
*/
|
|
|
|
parseComment: function(){
|
|
var tok = this.expect('comment');
|
|
var node;
|
|
|
|
if ('indent' == this.peek().type) {
|
|
node = new nodes.BlockComment(tok.val, this.block(), tok.buffer);
|
|
} else {
|
|
node = new nodes.Comment(tok.val, tok.buffer);
|
|
}
|
|
|
|
node.line = this.line();
|
|
return node;
|
|
},
|
|
|
|
/**
|
|
* doctype
|
|
*/
|
|
|
|
parseDoctype: function(){
|
|
var tok = this.expect('doctype');
|
|
var node = new nodes.Doctype(tok.val);
|
|
node.line = this.line();
|
|
return node;
|
|
},
|
|
|
|
/**
|
|
* filter attrs? text-block
|
|
*/
|
|
|
|
parseFilter: function(){
|
|
var tok = this.expect('filter');
|
|
var attrs = this.accept('attrs');
|
|
var block;
|
|
|
|
this.lexer.pipeless = true;
|
|
block = this.parseTextBlock();
|
|
this.lexer.pipeless = false;
|
|
|
|
var node = new nodes.Filter(tok.val, block, attrs && attrs.attrs);
|
|
node.line = this.line();
|
|
return node;
|
|
},
|
|
|
|
/**
|
|
* each block
|
|
*/
|
|
|
|
parseEach: function(){
|
|
var tok = this.expect('each');
|
|
var node = new nodes.Each(tok.code, tok.val, tok.key);
|
|
node.line = this.line();
|
|
node.block = this.block();
|
|
if (this.peek().type == 'code' && this.peek().val == 'else') {
|
|
this.advance();
|
|
node.alternative = this.block();
|
|
}
|
|
return node;
|
|
},
|
|
|
|
/**
|
|
* Resolves a path relative to the template for use in
|
|
* includes and extends
|
|
*
|
|
* @param {String} path
|
|
* @param {String} purpose Used in error messages.
|
|
* @return {String}
|
|
* @api private
|
|
*/
|
|
|
|
resolvePath: function (path, purpose) {
|
|
var p = require('path');
|
|
var dirname = p.dirname;
|
|
var basename = p.basename;
|
|
var join = p.join;
|
|
|
|
if (path[0] !== '/' && !this.filename)
|
|
throw new Error('the "filename" option is required to use "' + purpose + '" with "relative" paths');
|
|
|
|
if (path[0] === '/' && !this.options.basedir)
|
|
throw new Error('the "basedir" option is required to use "' + purpose + '" with "absolute" paths');
|
|
|
|
path = join(path[0] === '/' ? this.options.basedir : dirname(this.filename), path);
|
|
|
|
if (basename(path).indexOf('.') === -1) path += '.jade';
|
|
|
|
return path;
|
|
},
|
|
|
|
/**
|
|
* 'extends' name
|
|
*/
|
|
|
|
parseExtends: function(){
|
|
var fs = require('fs');
|
|
|
|
var path = this.resolvePath(this.expect('extends').val.trim(), 'extends');
|
|
if ('.jade' != path.substr(-5)) path += '.jade';
|
|
|
|
var str = fs.readFileSync(path, 'utf8');
|
|
var parser = new Parser(str, path, this.options);
|
|
|
|
parser.blocks = this.blocks;
|
|
parser.contexts = this.contexts;
|
|
this.extending = parser;
|
|
|
|
// TODO: null node
|
|
return new nodes.Literal('');
|
|
},
|
|
|
|
/**
|
|
* 'block' name block
|
|
*/
|
|
|
|
parseBlock: function(){
|
|
var block = this.expect('block');
|
|
var mode = block.mode;
|
|
var name = block.val.trim();
|
|
|
|
block = 'indent' == this.peek().type
|
|
? this.block()
|
|
: new nodes.Block(new nodes.Literal(''));
|
|
|
|
var prev = this.blocks[name] || {prepended: [], appended: []}
|
|
if (prev.mode === 'replace') return this.blocks[name] = prev;
|
|
|
|
var allNodes = prev.prepended.concat(block.nodes).concat(prev.appended);
|
|
|
|
switch (mode) {
|
|
case 'append':
|
|
prev.appended = prev.parser === this ?
|
|
prev.appended.concat(block.nodes) :
|
|
block.nodes.concat(prev.appended);
|
|
break;
|
|
case 'prepend':
|
|
prev.prepended = prev.parser === this ?
|
|
block.nodes.concat(prev.prepended) :
|
|
prev.prepended.concat(block.nodes);
|
|
break;
|
|
}
|
|
block.nodes = allNodes;
|
|
block.appended = prev.appended;
|
|
block.prepended = prev.prepended;
|
|
block.mode = mode;
|
|
block.parser = this;
|
|
|
|
return this.blocks[name] = block;
|
|
},
|
|
|
|
/**
|
|
* include block?
|
|
*/
|
|
|
|
parseInclude: function(){
|
|
var fs = require('fs');
|
|
|
|
var path = this.resolvePath(this.expect('include').val.trim(), 'include');
|
|
|
|
// non-jade
|
|
if ('.jade' != path.substr(-5)) {
|
|
var str = fs.readFileSync(path, 'utf8').replace(/\r/g, '');
|
|
var ext = extname(path).slice(1);
|
|
if (filters.exists(ext)) str = filters(ext, str, { filename: path });
|
|
return new nodes.Literal(str);
|
|
}
|
|
|
|
var str = fs.readFileSync(path, 'utf8');
|
|
var parser = new Parser(str, path, this.options);
|
|
parser.blocks = utils.merge({}, this.blocks);
|
|
|
|
parser.mixins = this.mixins;
|
|
|
|
this.context(parser);
|
|
var ast = parser.parse();
|
|
this.context();
|
|
ast.filename = path;
|
|
|
|
if ('indent' == this.peek().type) {
|
|
ast.includeBlock().push(this.block());
|
|
}
|
|
|
|
return ast;
|
|
},
|
|
|
|
/**
|
|
* call ident block
|
|
*/
|
|
|
|
parseCall: function(){
|
|
var tok = this.expect('call');
|
|
var name = tok.val;
|
|
var args = tok.args;
|
|
var mixin = new nodes.Mixin(name, args, new nodes.Block, true);
|
|
|
|
this.tag(mixin);
|
|
if (mixin.code) {
|
|
mixin.block.push(mixin.code);
|
|
mixin.code = null;
|
|
}
|
|
if (mixin.block.isEmpty()) mixin.block = null;
|
|
return mixin;
|
|
},
|
|
|
|
/**
|
|
* mixin block
|
|
*/
|
|
|
|
parseMixin: function(){
|
|
var tok = this.expect('mixin');
|
|
var name = tok.val;
|
|
var args = tok.args;
|
|
var mixin;
|
|
|
|
// definition
|
|
if ('indent' == this.peek().type) {
|
|
mixin = new nodes.Mixin(name, args, this.block(), false);
|
|
this.mixins[name] = mixin;
|
|
return mixin;
|
|
// call
|
|
} else {
|
|
return new nodes.Mixin(name, args, null, true);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* indent (text | newline)* outdent
|
|
*/
|
|
|
|
parseTextBlock: function(){
|
|
var block = new nodes.Block;
|
|
block.line = this.line();
|
|
var spaces = this.expect('indent').val;
|
|
if (null == this._spaces) this._spaces = spaces;
|
|
var indent = Array(spaces - this._spaces + 1).join(' ');
|
|
while ('outdent' != this.peek().type) {
|
|
switch (this.peek().type) {
|
|
case 'newline':
|
|
this.advance();
|
|
break;
|
|
case 'indent':
|
|
this.parseTextBlock().nodes.forEach(function(node){
|
|
block.push(node);
|
|
});
|
|
break;
|
|
default:
|
|
var text = new nodes.Text(indent + this.advance().val);
|
|
text.line = this.line();
|
|
block.push(text);
|
|
}
|
|
}
|
|
|
|
if (spaces == this._spaces) this._spaces = null;
|
|
this.expect('outdent');
|
|
return block;
|
|
},
|
|
|
|
/**
|
|
* indent expr* outdent
|
|
*/
|
|
|
|
block: function(){
|
|
var block = new nodes.Block;
|
|
block.line = this.line();
|
|
this.expect('indent');
|
|
while ('outdent' != this.peek().type) {
|
|
if ('newline' == this.peek().type) {
|
|
this.advance();
|
|
} else {
|
|
block.push(this.parseExpr());
|
|
}
|
|
}
|
|
this.expect('outdent');
|
|
return block;
|
|
},
|
|
|
|
/**
|
|
* interpolation (attrs | class | id)* (text | code | ':')? newline* block?
|
|
*/
|
|
|
|
parseInterpolation: function(){
|
|
var tok = this.advance();
|
|
var tag = new nodes.Tag(tok.val);
|
|
tag.buffer = true;
|
|
return this.tag(tag);
|
|
},
|
|
|
|
/**
|
|
* tag (attrs | class | id)* (text | code | ':')? newline* block?
|
|
*/
|
|
|
|
parseTag: function(){
|
|
// ast-filter look-ahead
|
|
var i = 2;
|
|
if ('attrs' == this.lookahead(i).type) ++i;
|
|
|
|
var tok = this.advance();
|
|
var tag = new nodes.Tag(tok.val);
|
|
|
|
tag.selfClosing = tok.selfClosing;
|
|
|
|
return this.tag(tag);
|
|
},
|
|
|
|
/**
|
|
* Parse tag.
|
|
*/
|
|
|
|
tag: function(tag){
|
|
var dot;
|
|
|
|
tag.line = this.line();
|
|
|
|
var seenAttrs = false;
|
|
// (attrs | class | id)*
|
|
out:
|
|
while (true) {
|
|
switch (this.peek().type) {
|
|
case 'id':
|
|
case 'class':
|
|
var tok = this.advance();
|
|
tag.setAttribute(tok.type, "'" + tok.val + "'");
|
|
continue;
|
|
case 'attrs':
|
|
if (seenAttrs) {
|
|
console.warn('You should not have jade tags with multiple attributes.');
|
|
}
|
|
seenAttrs = true;
|
|
var tok = this.advance()
|
|
, obj = tok.attrs
|
|
, escaped = tok.escaped
|
|
, names = Object.keys(obj);
|
|
|
|
if (tok.selfClosing) tag.selfClosing = true;
|
|
|
|
for (var i = 0, len = names.length; i < len; ++i) {
|
|
var name = names[i]
|
|
, val = obj[name];
|
|
tag.setAttribute(name, val, escaped[name]);
|
|
}
|
|
continue;
|
|
default:
|
|
break out;
|
|
}
|
|
}
|
|
|
|
// check immediate '.'
|
|
if ('.' == this.peek().val) {
|
|
dot = tag.textOnly = true;
|
|
this.advance();
|
|
}
|
|
|
|
// (text | code | ':')?
|
|
switch (this.peek().type) {
|
|
case 'text':
|
|
tag.block.push(this.parseText());
|
|
break;
|
|
case 'code':
|
|
tag.code = this.parseCode();
|
|
break;
|
|
case ':':
|
|
this.advance();
|
|
tag.block = new nodes.Block;
|
|
tag.block.push(this.parseExpr());
|
|
break;
|
|
case 'newline':
|
|
case 'indent':
|
|
case 'outdent':
|
|
case 'eos':
|
|
break;
|
|
default:
|
|
throw new Error('Unexpected token `' + this.peek().type + '` expected `text`, `code`, `:`, `newline` or `eos`')
|
|
}
|
|
|
|
// newline*
|
|
while ('newline' == this.peek().type) this.advance();
|
|
|
|
tag.textOnly = tag.textOnly || ~textOnly.indexOf(tag.name);
|
|
|
|
// script special-case
|
|
if ('script' == tag.name) {
|
|
var type = tag.getAttribute('type');
|
|
if (!dot && type && 'text/javascript' != type.replace(/^['"]|['"]$/g, '')) {
|
|
tag.textOnly = false;
|
|
}
|
|
}
|
|
|
|
// block?
|
|
if ('indent' == this.peek().type) {
|
|
if (tag.textOnly) {
|
|
if (!dot) {
|
|
console.warn(this.filename + ', line ' + this.peek().line + ':')
|
|
console.warn('Implicit textOnly for `script` and `style` is deprecated. Use `script.` or `style.` instead.');
|
|
}
|
|
this.lexer.pipeless = true;
|
|
tag.block = this.parseTextBlock();
|
|
this.lexer.pipeless = false;
|
|
} else {
|
|
var block = this.block();
|
|
if (tag.block) {
|
|
for (var i = 0, len = block.nodes.length; i < len; ++i) {
|
|
tag.block.push(block.nodes[i]);
|
|
}
|
|
} else {
|
|
tag.block = block;
|
|
}
|
|
}
|
|
}
|
|
|
|
return tag;
|
|
}
|
|
};
|
|
|
|
},{"path":8,"fs":1,"./lexer":12,"./filters":6,"./utils":5,"./nodes":13}],13:[function(require,module,exports){
|
|
|
|
/*!
|
|
* Jade - nodes
|
|
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
exports.Node = require('./node');
|
|
exports.Tag = require('./tag');
|
|
exports.Code = require('./code');
|
|
exports.Each = require('./each');
|
|
exports.Case = require('./case');
|
|
exports.Text = require('./text');
|
|
exports.Block = require('./block');
|
|
exports.Mixin = require('./mixin');
|
|
exports.Filter = require('./filter');
|
|
exports.Comment = require('./comment');
|
|
exports.Literal = require('./literal');
|
|
exports.BlockComment = require('./block-comment');
|
|
exports.Doctype = require('./doctype');
|
|
|
|
},{"./node":15,"./each":16,"./tag":17,"./text":18,"./code":19,"./case":20,"./block":21,"./filter":22,"./comment":23,"./mixin":24,"./literal":25,"./doctype":26,"./block-comment":27}],15:[function(require,module,exports){
|
|
|
|
/*!
|
|
* Jade - nodes - Node
|
|
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
/**
|
|
* Initialize a `Node`.
|
|
*
|
|
* @api public
|
|
*/
|
|
|
|
var Node = module.exports = function Node(){};
|
|
|
|
/**
|
|
* Clone this node (return itself)
|
|
*
|
|
* @return {Node}
|
|
* @api private
|
|
*/
|
|
|
|
Node.prototype.clone = function(){
|
|
return this;
|
|
};
|
|
|
|
},{}],12:[function(require,module,exports){
|
|
/*!
|
|
* Jade - Lexer
|
|
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
var utils = require('./utils');
|
|
var parseJSExpression = require('character-parser').parseMax;
|
|
|
|
/**
|
|
* Initialize `Lexer` with the given `str`.
|
|
*
|
|
* Options:
|
|
*
|
|
* - `colons` allow colons for attr delimiters
|
|
*
|
|
* @param {String} str
|
|
* @param {Object} options
|
|
* @api private
|
|
*/
|
|
|
|
var Lexer = module.exports = function Lexer(str, options) {
|
|
options = options || {};
|
|
this.input = str.replace(/\r\n|\r/g, '\n');
|
|
this.colons = options.colons;
|
|
this.deferredTokens = [];
|
|
this.lastIndents = 0;
|
|
this.lineno = 1;
|
|
this.stash = [];
|
|
this.indentStack = [];
|
|
this.indentRe = null;
|
|
this.pipeless = false;
|
|
};
|
|
|
|
/**
|
|
* Lexer prototype.
|
|
*/
|
|
|
|
Lexer.prototype = {
|
|
|
|
/**
|
|
* Construct a token with the given `type` and `val`.
|
|
*
|
|
* @param {String} type
|
|
* @param {String} val
|
|
* @return {Object}
|
|
* @api private
|
|
*/
|
|
|
|
tok: function(type, val){
|
|
return {
|
|
type: type
|
|
, line: this.lineno
|
|
, val: val
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Consume the given `len` of input.
|
|
*
|
|
* @param {Number} len
|
|
* @api private
|
|
*/
|
|
|
|
consume: function(len){
|
|
this.input = this.input.substr(len);
|
|
},
|
|
|
|
/**
|
|
* Scan for `type` with the given `regexp`.
|
|
*
|
|
* @param {String} type
|
|
* @param {RegExp} regexp
|
|
* @return {Object}
|
|
* @api private
|
|
*/
|
|
|
|
scan: function(regexp, type){
|
|
var captures;
|
|
if (captures = regexp.exec(this.input)) {
|
|
this.consume(captures[0].length);
|
|
return this.tok(type, captures[1]);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Defer the given `tok`.
|
|
*
|
|
* @param {Object} tok
|
|
* @api private
|
|
*/
|
|
|
|
defer: function(tok){
|
|
this.deferredTokens.push(tok);
|
|
},
|
|
|
|
/**
|
|
* Lookahead `n` tokens.
|
|
*
|
|
* @param {Number} n
|
|
* @return {Object}
|
|
* @api private
|
|
*/
|
|
|
|
lookahead: function(n){
|
|
var fetch = n - this.stash.length;
|
|
while (fetch-- > 0) this.stash.push(this.next());
|
|
return this.stash[--n];
|
|
},
|
|
|
|
/**
|
|
* Return the indexOf `(` or `{` or `[` / `)` or `}` or `]` delimiters.
|
|
*
|
|
* @return {Number}
|
|
* @api private
|
|
*/
|
|
|
|
bracketExpression: function(skip){
|
|
skip = skip || 0;
|
|
var start = this.input[skip];
|
|
if (start != '(' && start != '{' && start != '[') throw new Error('unrecognized start character');
|
|
var end = ({'(': ')', '{': '}', '[': ']'})[start];
|
|
var range = parseJSExpression(this.input, {start: skip + 1});
|
|
if (this.input[range.end] !== end) throw new Error('start character ' + start + ' does not match end character ' + this.input[range.end]);
|
|
return range;
|
|
},
|
|
|
|
/**
|
|
* Stashed token.
|
|
*/
|
|
|
|
stashed: function() {
|
|
return this.stash.length
|
|
&& this.stash.shift();
|
|
},
|
|
|
|
/**
|
|
* Deferred token.
|
|
*/
|
|
|
|
deferred: function() {
|
|
return this.deferredTokens.length
|
|
&& this.deferredTokens.shift();
|
|
},
|
|
|
|
/**
|
|
* end-of-source.
|
|
*/
|
|
|
|
eos: function() {
|
|
if (this.input.length) return;
|
|
if (this.indentStack.length) {
|
|
this.indentStack.shift();
|
|
return this.tok('outdent');
|
|
} else {
|
|
return this.tok('eos');
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Blank line.
|
|
*/
|
|
|
|
blank: function() {
|
|
var captures;
|
|
if (captures = /^\n *\n/.exec(this.input)) {
|
|
this.consume(captures[0].length - 1);
|
|
++this.lineno;
|
|
if (this.pipeless) return this.tok('text', '');
|
|
return this.next();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Comment.
|
|
*/
|
|
|
|
comment: function() {
|
|
var captures;
|
|
if (captures = /^ *\/\/(-)?([^\n]*)/.exec(this.input)) {
|
|
this.consume(captures[0].length);
|
|
var tok = this.tok('comment', captures[2]);
|
|
tok.buffer = '-' != captures[1];
|
|
return tok;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Interpolated tag.
|
|
*/
|
|
|
|
interpolation: function() {
|
|
if (/^#\{/.test(this.input)) {
|
|
var match;
|
|
try {
|
|
match = this.bracketExpression(1);
|
|
} catch (ex) {
|
|
return;//not an interpolation expression, just an unmatched open interpolation
|
|
}
|
|
|
|
this.consume(match.end + 1);
|
|
return this.tok('interpolation', match.src);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Tag.
|
|
*/
|
|
|
|
tag: function() {
|
|
var captures;
|
|
if (captures = /^(\w[-:\w]*)(\/?)/.exec(this.input)) {
|
|
this.consume(captures[0].length);
|
|
var tok, name = captures[1];
|
|
if (':' == name[name.length - 1]) {
|
|
name = name.slice(0, -1);
|
|
tok = this.tok('tag', name);
|
|
this.defer(this.tok(':'));
|
|
while (' ' == this.input[0]) this.input = this.input.substr(1);
|
|
} else {
|
|
tok = this.tok('tag', name);
|
|
}
|
|
tok.selfClosing = !! captures[2];
|
|
return tok;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Filter.
|
|
*/
|
|
|
|
filter: function() {
|
|
return this.scan(/^:(\w+)/, 'filter');
|
|
},
|
|
|
|
/**
|
|
* Doctype.
|
|
*/
|
|
|
|
doctype: function() {
|
|
return this.scan(/^(?:!!!|doctype) *([^\n]+)?/, 'doctype');
|
|
},
|
|
|
|
/**
|
|
* Id.
|
|
*/
|
|
|
|
id: function() {
|
|
return this.scan(/^#([\w-]+)/, 'id');
|
|
},
|
|
|
|
/**
|
|
* Class.
|
|
*/
|
|
|
|
className: function() {
|
|
return this.scan(/^\.([\w-]+)/, 'class');
|
|
},
|
|
|
|
/**
|
|
* Text.
|
|
*/
|
|
|
|
text: function() {
|
|
return this.scan(/^(?:\| ?| ?)?([^\n]+)/, 'text');
|
|
},
|
|
|
|
/**
|
|
* Extends.
|
|
*/
|
|
|
|
"extends": function() {
|
|
return this.scan(/^extends? +([^\n]+)/, 'extends');
|
|
},
|
|
|
|
/**
|
|
* Block prepend.
|
|
*/
|
|
|
|
prepend: function() {
|
|
var captures;
|
|
if (captures = /^prepend +([^\n]+)/.exec(this.input)) {
|
|
this.consume(captures[0].length);
|
|
var mode = 'prepend'
|
|
, name = captures[1]
|
|
, tok = this.tok('block', name);
|
|
tok.mode = mode;
|
|
return tok;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Block append.
|
|
*/
|
|
|
|
append: function() {
|
|
var captures;
|
|
if (captures = /^append +([^\n]+)/.exec(this.input)) {
|
|
this.consume(captures[0].length);
|
|
var mode = 'append'
|
|
, name = captures[1]
|
|
, tok = this.tok('block', name);
|
|
tok.mode = mode;
|
|
return tok;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Block.
|
|
*/
|
|
|
|
block: function() {
|
|
var captures;
|
|
if (captures = /^block\b *(?:(prepend|append) +)?([^\n]*)/.exec(this.input)) {
|
|
this.consume(captures[0].length);
|
|
var mode = captures[1] || 'replace'
|
|
, name = captures[2]
|
|
, tok = this.tok('block', name);
|
|
|
|
tok.mode = mode;
|
|
return tok;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Yield.
|
|
*/
|
|
|
|
yield: function() {
|
|
return this.scan(/^yield */, 'yield');
|
|
},
|
|
|
|
/**
|
|
* Include.
|
|
*/
|
|
|
|
include: function() {
|
|
return this.scan(/^include +([^\n]+)/, 'include');
|
|
},
|
|
|
|
/**
|
|
* Case.
|
|
*/
|
|
|
|
"case": function() {
|
|
return this.scan(/^case +([^\n]+)/, 'case');
|
|
},
|
|
|
|
/**
|
|
* When.
|
|
*/
|
|
|
|
when: function() {
|
|
return this.scan(/^when +([^:\n]+)/, 'when');
|
|
},
|
|
|
|
/**
|
|
* Default.
|
|
*/
|
|
|
|
"default": function() {
|
|
return this.scan(/^default */, 'default');
|
|
},
|
|
|
|
/**
|
|
* Assignment.
|
|
*/
|
|
|
|
assignment: function() {
|
|
var captures;
|
|
if (captures = /^(\w+) += *([^;\n]+)( *;? *)/.exec(this.input)) {
|
|
this.consume(captures[0].length);
|
|
var name = captures[1]
|
|
, val = captures[2];
|
|
return this.tok('code', 'var ' + name + ' = (' + val + ');');
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Call mixin.
|
|
*/
|
|
|
|
call: function(){
|
|
var captures;
|
|
if (captures = /^\+([-\w]+)/.exec(this.input)) {
|
|
this.consume(captures[0].length);
|
|
var tok = this.tok('call', captures[1]);
|
|
|
|
// Check for args (not attributes)
|
|
if (captures = /^ *\(/.exec(this.input)) {
|
|
try {
|
|
var range = this.bracketExpression(captures[0].length - 1);
|
|
if (!/^ *[-\w]+ *=/.test(range.src)) { // not attributes
|
|
this.consume(range.end + 1);
|
|
tok.args = range.src;
|
|
}
|
|
} catch (ex) {
|
|
//not a bracket expcetion, just unmatched open parens
|
|
}
|
|
}
|
|
|
|
return tok;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Mixin.
|
|
*/
|
|
|
|
mixin: function(){
|
|
var captures;
|
|
if (captures = /^mixin +([-\w]+)(?: *\((.*)\))?/.exec(this.input)) {
|
|
this.consume(captures[0].length);
|
|
var tok = this.tok('mixin', captures[1]);
|
|
tok.args = captures[2];
|
|
return tok;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Conditional.
|
|
*/
|
|
|
|
conditional: function() {
|
|
var captures;
|
|
if (captures = /^(if|unless|else if|else)\b([^\n]*)/.exec(this.input)) {
|
|
this.consume(captures[0].length);
|
|
var type = captures[1]
|
|
, js = captures[2];
|
|
|
|
switch (type) {
|
|
case 'if': js = 'if (' + js + ')'; break;
|
|
case 'unless': js = 'if (!(' + js + '))'; break;
|
|
case 'else if': js = 'else if (' + js + ')'; break;
|
|
case 'else': js = 'else'; break;
|
|
}
|
|
|
|
return this.tok('code', js);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* While.
|
|
*/
|
|
|
|
"while": function() {
|
|
var captures;
|
|
if (captures = /^while +([^\n]+)/.exec(this.input)) {
|
|
this.consume(captures[0].length);
|
|
return this.tok('code', 'while (' + captures[1] + ')');
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Each.
|
|
*/
|
|
|
|
each: function() {
|
|
var captures;
|
|
if (captures = /^(?:- *)?(?:each|for) +([a-zA-Z_$][\w$]*)(?: *, *([a-zA-Z_$][\w$]*))? * in *([^\n]+)/.exec(this.input)) {
|
|
this.consume(captures[0].length);
|
|
var tok = this.tok('each', captures[1]);
|
|
tok.key = captures[2] || '$index';
|
|
tok.code = captures[3];
|
|
return tok;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Code.
|
|
*/
|
|
|
|
code: function() {
|
|
var captures;
|
|
if (captures = /^(!?=|-)[ \t]*([^\n]+)/.exec(this.input)) {
|
|
this.consume(captures[0].length);
|
|
var flags = captures[1];
|
|
captures[1] = captures[2];
|
|
var tok = this.tok('code', captures[1]);
|
|
tok.escape = flags.charAt(0) === '=';
|
|
tok.buffer = flags.charAt(0) === '=' || flags.charAt(1) === '=';
|
|
return tok;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Attributes.
|
|
*/
|
|
|
|
attrs: function() {
|
|
if ('(' == this.input.charAt(0)) {
|
|
var index = this.bracketExpression().end
|
|
, str = this.input.substr(1, index-1)
|
|
, tok = this.tok('attrs')
|
|
, len = str.length
|
|
, colons = this.colons
|
|
, states = ['key']
|
|
, escapedAttr
|
|
, key = ''
|
|
, val = ''
|
|
, quote
|
|
, c
|
|
, p;
|
|
|
|
function state(){
|
|
return states[states.length - 1];
|
|
}
|
|
|
|
function interpolate(attr) {
|
|
return attr.replace(/(\\)?#\{(.+)/g, function(_, escape, expr){
|
|
if (escape) return _;
|
|
try {
|
|
var range = parseJSExpression(expr);
|
|
if (expr[range.end] !== '}') return _.substr(0, 2) + interpolate(_.substr(2));
|
|
return quote + " + (" + range.src + ") + " + quote + interpolate(expr.substr(range.end + 1));
|
|
} catch (ex) {
|
|
return _.substr(0, 2) + interpolate(_.substr(2));
|
|
}
|
|
});
|
|
}
|
|
|
|
this.consume(index + 1);
|
|
tok.attrs = {};
|
|
tok.escaped = {};
|
|
|
|
function parse(c) {
|
|
var real = c;
|
|
// TODO: remove when people fix ":"
|
|
if (colons && ':' == c) c = '=';
|
|
switch (c) {
|
|
case ',':
|
|
case '\n':
|
|
switch (state()) {
|
|
case 'expr':
|
|
case 'array':
|
|
case 'string':
|
|
case 'object':
|
|
val += c;
|
|
break;
|
|
default:
|
|
states.push('key');
|
|
val = val.trim();
|
|
key = key.trim();
|
|
if ('' == key) return;
|
|
key = key.replace(/^['"]|['"]$/g, '').replace('!', '');
|
|
tok.escaped[key] = escapedAttr;
|
|
tok.attrs[key] = '' == val
|
|
? true
|
|
: interpolate(val);
|
|
key = val = '';
|
|
}
|
|
break;
|
|
case '=':
|
|
switch (state()) {
|
|
case 'key char':
|
|
key += real;
|
|
break;
|
|
case 'val':
|
|
case 'expr':
|
|
case 'array':
|
|
case 'string':
|
|
case 'object':
|
|
val += real;
|
|
break;
|
|
default:
|
|
escapedAttr = '!' != p;
|
|
states.push('val');
|
|
}
|
|
break;
|
|
case '(':
|
|
if ('val' == state()
|
|
|| 'expr' == state()) states.push('expr');
|
|
val += c;
|
|
break;
|
|
case ')':
|
|
if ('expr' == state()
|
|
|| 'val' == state()) states.pop();
|
|
val += c;
|
|
break;
|
|
case '{':
|
|
if ('val' == state()) states.push('object');
|
|
val += c;
|
|
break;
|
|
case '}':
|
|
if ('object' == state()) states.pop();
|
|
val += c;
|
|
break;
|
|
case '[':
|
|
if ('val' == state()) states.push('array');
|
|
val += c;
|
|
break;
|
|
case ']':
|
|
if ('array' == state()) states.pop();
|
|
val += c;
|
|
break;
|
|
case '"':
|
|
case "'":
|
|
switch (state()) {
|
|
case 'key':
|
|
states.push('key char');
|
|
break;
|
|
case 'key char':
|
|
states.pop();
|
|
break;
|
|
case 'string':
|
|
if (c == quote) states.pop();
|
|
val += c;
|
|
break;
|
|
default:
|
|
states.push('string');
|
|
val += c;
|
|
quote = c;
|
|
}
|
|
break;
|
|
case '':
|
|
break;
|
|
default:
|
|
switch (state()) {
|
|
case 'key':
|
|
case 'key char':
|
|
key += c;
|
|
break;
|
|
default:
|
|
val += c;
|
|
}
|
|
}
|
|
p = c;
|
|
}
|
|
|
|
for (var i = 0; i < len; ++i) {
|
|
parse(str.charAt(i));
|
|
}
|
|
|
|
parse(',');
|
|
|
|
if ('/' == this.input.charAt(0)) {
|
|
this.consume(1);
|
|
tok.selfClosing = true;
|
|
}
|
|
|
|
return tok;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Indent | Outdent | Newline.
|
|
*/
|
|
|
|
indent: function() {
|
|
var captures, re;
|
|
|
|
// established regexp
|
|
if (this.indentRe) {
|
|
captures = this.indentRe.exec(this.input);
|
|
// determine regexp
|
|
} else {
|
|
// tabs
|
|
re = /^\n(\t*) */;
|
|
captures = re.exec(this.input);
|
|
|
|
// spaces
|
|
if (captures && !captures[1].length) {
|
|
re = /^\n( *)/;
|
|
captures = re.exec(this.input);
|
|
}
|
|
|
|
// established
|
|
if (captures && captures[1].length) this.indentRe = re;
|
|
}
|
|
|
|
if (captures) {
|
|
var tok
|
|
, indents = captures[1].length;
|
|
|
|
++this.lineno;
|
|
this.consume(indents + 1);
|
|
|
|
if (' ' == this.input[0] || '\t' == this.input[0]) {
|
|
throw new Error('Invalid indentation, you can use tabs or spaces but not both');
|
|
}
|
|
|
|
// blank line
|
|
if ('\n' == this.input[0]) return this.tok('newline');
|
|
|
|
// outdent
|
|
if (this.indentStack.length && indents < this.indentStack[0]) {
|
|
while (this.indentStack.length && this.indentStack[0] > indents) {
|
|
this.stash.push(this.tok('outdent'));
|
|
this.indentStack.shift();
|
|
}
|
|
tok = this.stash.pop();
|
|
// indent
|
|
} else if (indents && indents != this.indentStack[0]) {
|
|
this.indentStack.unshift(indents);
|
|
tok = this.tok('indent', indents);
|
|
// newline
|
|
} else {
|
|
tok = this.tok('newline');
|
|
}
|
|
|
|
return tok;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Pipe-less text consumed only when
|
|
* pipeless is true;
|
|
*/
|
|
|
|
pipelessText: function() {
|
|
if (this.pipeless) {
|
|
if ('\n' == this.input[0]) return;
|
|
var i = this.input.indexOf('\n');
|
|
if (-1 == i) i = this.input.length;
|
|
var str = this.input.substr(0, i);
|
|
this.consume(str.length);
|
|
return this.tok('text', str);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* ':'
|
|
*/
|
|
|
|
colon: function() {
|
|
return this.scan(/^: */, ':');
|
|
},
|
|
|
|
/**
|
|
* Return the next token object, or those
|
|
* previously stashed by lookahead.
|
|
*
|
|
* @return {Object}
|
|
* @api private
|
|
*/
|
|
|
|
advance: function(){
|
|
return this.stashed()
|
|
|| this.next();
|
|
},
|
|
|
|
/**
|
|
* Return the next token object.
|
|
*
|
|
* @return {Object}
|
|
* @api private
|
|
*/
|
|
|
|
next: function() {
|
|
return this.deferred()
|
|
|| this.blank()
|
|
|| this.eos()
|
|
|| this.pipelessText()
|
|
|| this.yield()
|
|
|| this.doctype()
|
|
|| this.interpolation()
|
|
|| this["case"]()
|
|
|| this.when()
|
|
|| this["default"]()
|
|
|| this["extends"]()
|
|
|| this.append()
|
|
|| this.prepend()
|
|
|| this.block()
|
|
|| this.include()
|
|
|| this.mixin()
|
|
|| this.call()
|
|
|| this.conditional()
|
|
|| this.each()
|
|
|| this["while"]()
|
|
|| this.assignment()
|
|
|| this.tag()
|
|
|| this.filter()
|
|
|| this.code()
|
|
|| this.id()
|
|
|| this.className()
|
|
|| this.attrs()
|
|
|| this.indent()
|
|
|| this.comment()
|
|
|| this.colon()
|
|
|| this.text();
|
|
}
|
|
};
|
|
|
|
},{"./utils":5,"character-parser":28}],11:[function(require,module,exports){
|
|
(function(){/*!
|
|
* Jade - Compiler
|
|
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
/**
|
|
* Module dependencies.
|
|
*/
|
|
|
|
var nodes = require('./nodes')
|
|
, filters = require('./filters')
|
|
, doctypes = require('./doctypes')
|
|
, selfClosing = require('./self-closing')
|
|
, runtime = require('./runtime')
|
|
, utils = require('./utils')
|
|
, parseJSExpression = require('character-parser').parseMax
|
|
, isConstant = require('constantinople')
|
|
, toConstant = require('constantinople').toConstant
|
|
|
|
|
|
/**
|
|
* Initialize `Compiler` with the given `node`.
|
|
*
|
|
* @param {Node} node
|
|
* @param {Object} options
|
|
* @api public
|
|
*/
|
|
|
|
var Compiler = module.exports = function Compiler(node, options) {
|
|
this.options = options = options || {};
|
|
this.node = node;
|
|
this.hasCompiledDoctype = false;
|
|
this.hasCompiledTag = false;
|
|
this.pp = options.pretty || false;
|
|
this.debug = false !== options.compileDebug;
|
|
this.indents = 0;
|
|
this.parentIndents = 0;
|
|
if (options.doctype) this.setDoctype(options.doctype);
|
|
};
|
|
|
|
/**
|
|
* Compiler prototype.
|
|
*/
|
|
|
|
Compiler.prototype = {
|
|
|
|
/**
|
|
* Compile parse tree to JavaScript.
|
|
*
|
|
* @api public
|
|
*/
|
|
|
|
compile: function(){
|
|
this.buf = [];
|
|
if (this.pp) this.buf.push("jade.indent = [];");
|
|
this.lastBufferedIdx = -1;
|
|
this.visit(this.node);
|
|
return this.buf.join('\n');
|
|
},
|
|
|
|
/**
|
|
* Sets the default doctype `name`. Sets terse mode to `true` when
|
|
* html 5 is used, causing self-closing tags to end with ">" vs "/>",
|
|
* and boolean attributes are not mirrored.
|
|
*
|
|
* @param {string} name
|
|
* @api public
|
|
*/
|
|
|
|
setDoctype: function(name){
|
|
name = name || 'default';
|
|
this.doctype = doctypes[name.toLowerCase()] || '<!DOCTYPE ' + name + '>';
|
|
this.terse = this.doctype.toLowerCase() == '<!doctype html>';
|
|
this.xml = 0 == this.doctype.indexOf('<?xml');
|
|
},
|
|
|
|
/**
|
|
* Buffer the given `str` exactly as is or with interpolation
|
|
*
|
|
* @param {String} str
|
|
* @param {Boolean} interpolate
|
|
* @api public
|
|
*/
|
|
|
|
buffer: function (str, interpolate) {
|
|
var self = this;
|
|
if (interpolate) {
|
|
var match = /(\\)?([#!]){((?:.|\n)*)$/.exec(str);
|
|
if (match) {
|
|
this.buffer(str.substr(0, match.index), false);
|
|
if (match[1]) { // escape
|
|
this.buffer(match[2] + '{', false);
|
|
this.buffer(match[3], true);
|
|
return;
|
|
} else {
|
|
try {
|
|
var rest = match[3];
|
|
var range = parseJSExpression(rest);
|
|
var code = ('!' == match[2] ? '' : 'jade.escape') + "((jade.interp = " + range.src + ") == null ? '' : jade.interp)";
|
|
} catch (ex) {
|
|
throw ex;
|
|
//didn't match, just as if escaped
|
|
this.buffer(match[2] + '{', false);
|
|
this.buffer(match[3], true);
|
|
return;
|
|
}
|
|
this.bufferExpression(code);
|
|
this.buffer(rest.substr(range.end + 1), true);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
str = JSON.stringify(str);
|
|
str = str.substr(1, str.length - 2);
|
|
|
|
if (this.lastBufferedIdx == this.buf.length) {
|
|
if (this.lastBufferedType === 'code') this.lastBuffered += ' + "';
|
|
this.lastBufferedType = 'text';
|
|
this.lastBuffered += str;
|
|
this.buf[this.lastBufferedIdx - 1] = 'buf.push(' + this.bufferStartChar + this.lastBuffered + '");'
|
|
} else {
|
|
this.buf.push('buf.push("' + str + '");');
|
|
this.lastBufferedType = 'text';
|
|
this.bufferStartChar = '"';
|
|
this.lastBuffered = str;
|
|
this.lastBufferedIdx = this.buf.length;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Buffer the given `src` so it is evaluated at run time
|
|
*
|
|
* @param {String} src
|
|
* @api public
|
|
*/
|
|
|
|
bufferExpression: function (src) {
|
|
if (isConstant(src)) {
|
|
return this.buffer(toConstant(src), false)
|
|
}
|
|
if (this.lastBufferedIdx == this.buf.length) {
|
|
if (this.lastBufferedType === 'text') this.lastBuffered += '"';
|
|
this.lastBufferedType = 'code';
|
|
this.lastBuffered += ' + (' + src + ')';
|
|
this.buf[this.lastBufferedIdx - 1] = 'buf.push(' + this.bufferStartChar + this.lastBuffered + ');'
|
|
} else {
|
|
this.buf.push('buf.push(' + src + ');');
|
|
this.lastBufferedType = 'code';
|
|
this.bufferStartChar = '';
|
|
this.lastBuffered = '(' + src + ')';
|
|
this.lastBufferedIdx = this.buf.length;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Buffer an indent based on the current `indent`
|
|
* property and an additional `offset`.
|
|
*
|
|
* @param {Number} offset
|
|
* @param {Boolean} newline
|
|
* @api public
|
|
*/
|
|
|
|
prettyIndent: function(offset, newline){
|
|
offset = offset || 0;
|
|
newline = newline ? '\n' : '';
|
|
this.buffer(newline + Array(this.indents + offset).join(' '));
|
|
if (this.parentIndents)
|
|
this.buf.push("buf.push.apply(buf, jade.indent);");
|
|
},
|
|
|
|
/**
|
|
* Visit `node`.
|
|
*
|
|
* @param {Node} node
|
|
* @api public
|
|
*/
|
|
|
|
visit: function(node){
|
|
var debug = this.debug;
|
|
|
|
if (debug) {
|
|
this.buf.push('jade.debug.unshift({ lineno: ' + node.line
|
|
+ ', filename: ' + (node.filename
|
|
? JSON.stringify(node.filename)
|
|
: 'jade.debug[0].filename')
|
|
+ ' });');
|
|
}
|
|
|
|
// Massive hack to fix our context
|
|
// stack for - else[ if] etc
|
|
if (false === node.debug && this.debug) {
|
|
this.buf.pop();
|
|
this.buf.pop();
|
|
}
|
|
|
|
this.visitNode(node);
|
|
|
|
if (debug) this.buf.push('jade.debug.shift();');
|
|
},
|
|
|
|
/**
|
|
* Visit `node`.
|
|
*
|
|
* @param {Node} node
|
|
* @api public
|
|
*/
|
|
|
|
visitNode: function(node){
|
|
var name = node.constructor.name
|
|
|| node.constructor.toString().match(/function ([^(\s]+)()/)[1];
|
|
return this['visit' + name](node);
|
|
},
|
|
|
|
/**
|
|
* Visit case `node`.
|
|
*
|
|
* @param {Literal} node
|
|
* @api public
|
|
*/
|
|
|
|
visitCase: function(node){
|
|
var _ = this.withinCase;
|
|
this.withinCase = true;
|
|
this.buf.push('switch (' + node.expr + '){');
|
|
this.visit(node.block);
|
|
this.buf.push('}');
|
|
this.withinCase = _;
|
|
},
|
|
|
|
/**
|
|
* Visit when `node`.
|
|
*
|
|
* @param {Literal} node
|
|
* @api public
|
|
*/
|
|
|
|
visitWhen: function(node){
|
|
if ('default' == node.expr) {
|
|
this.buf.push('default:');
|
|
} else {
|
|
this.buf.push('case ' + node.expr + ':');
|
|
}
|
|
this.visit(node.block);
|
|
this.buf.push(' break;');
|
|
},
|
|
|
|
/**
|
|
* Visit literal `node`.
|
|
*
|
|
* @param {Literal} node
|
|
* @api public
|
|
*/
|
|
|
|
visitLiteral: function(node){
|
|
this.buffer(node.str);
|
|
},
|
|
|
|
/**
|
|
* Visit all nodes in `block`.
|
|
*
|
|
* @param {Block} block
|
|
* @api public
|
|
*/
|
|
|
|
visitBlock: function(block){
|
|
var len = block.nodes.length
|
|
, escape = this.escape
|
|
, pp = this.pp
|
|
|
|
// Block keyword has a special meaning in mixins
|
|
if (this.parentIndents && block.mode) {
|
|
if (pp) this.buf.push("jade.indent.push('" + Array(this.indents + 1).join(' ') + "');")
|
|
this.buf.push('block && block();');
|
|
if (pp) this.buf.push("jade.indent.pop();")
|
|
return;
|
|
}
|
|
|
|
// Pretty print multi-line text
|
|
if (pp && len > 1 && !escape && block.nodes[0].isText && block.nodes[1].isText)
|
|
this.prettyIndent(1, true);
|
|
|
|
for (var i = 0; i < len; ++i) {
|
|
// Pretty print text
|
|
if (pp && i > 0 && !escape && block.nodes[i].isText && block.nodes[i-1].isText)
|
|
this.prettyIndent(1, false);
|
|
|
|
this.visit(block.nodes[i]);
|
|
// Multiple text nodes are separated by newlines
|
|
if (block.nodes[i+1] && block.nodes[i].isText && block.nodes[i+1].isText)
|
|
this.buffer('\n');
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Visit `doctype`. Sets terse mode to `true` when html 5
|
|
* is used, causing self-closing tags to end with ">" vs "/>",
|
|
* and boolean attributes are not mirrored.
|
|
*
|
|
* @param {Doctype} doctype
|
|
* @api public
|
|
*/
|
|
|
|
visitDoctype: function(doctype){
|
|
if (doctype && (doctype.val || !this.doctype)) {
|
|
this.setDoctype(doctype.val || 'default');
|
|
}
|
|
|
|
if (this.doctype) this.buffer(this.doctype);
|
|
this.hasCompiledDoctype = true;
|
|
},
|
|
|
|
/**
|
|
* Visit `mixin`, generating a function that
|
|
* may be called within the template.
|
|
*
|
|
* @param {Mixin} mixin
|
|
* @api public
|
|
*/
|
|
|
|
visitMixin: function(mixin){
|
|
var name = mixin.name.replace(/-/g, '_') + '_mixin'
|
|
, args = mixin.args || ''
|
|
, block = mixin.block
|
|
, attrs = mixin.attrs
|
|
, pp = this.pp;
|
|
|
|
if (mixin.call) {
|
|
if (pp) this.buf.push("jade.indent.push('" + Array(this.indents + 1).join(' ') + "');")
|
|
if (block || attrs.length) {
|
|
|
|
this.buf.push(name + '.call({');
|
|
|
|
if (block) {
|
|
this.buf.push('block: function(){');
|
|
|
|
// Render block with no indents, dynamically added when rendered
|
|
this.parentIndents++;
|
|
var _indents = this.indents;
|
|
this.indents = 0;
|
|
this.visit(mixin.block);
|
|
this.indents = _indents;
|
|
this.parentIndents--;
|
|
|
|
if (attrs.length) {
|
|
this.buf.push('},');
|
|
} else {
|
|
this.buf.push('}');
|
|
}
|
|
}
|
|
|
|
if (attrs.length) {
|
|
var val = this.attrs(attrs);
|
|
if (val.inherits) {
|
|
this.buf.push('attributes: jade.merge({' + val.buf
|
|
+ '}, attributes), escaped: jade.merge(' + val.escaped + ', escaped, true)');
|
|
} else {
|
|
this.buf.push('attributes: {' + val.buf + '}, escaped: ' + val.escaped);
|
|
}
|
|
}
|
|
|
|
if (args) {
|
|
this.buf.push('}, ' + args + ');');
|
|
} else {
|
|
this.buf.push('});');
|
|
}
|
|
|
|
} else {
|
|
this.buf.push(name + '(' + args + ');');
|
|
}
|
|
if (pp) this.buf.push("jade.indent.pop();")
|
|
} else {
|
|
this.buf.push('var ' + name + ' = function(' + args + '){');
|
|
this.buf.push('var block = this.block, attributes = this.attributes || {}, escaped = this.escaped || {};');
|
|
this.parentIndents++;
|
|
this.visit(block);
|
|
this.parentIndents--;
|
|
this.buf.push('};');
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Visit `tag` buffering tag markup, generating
|
|
* attributes, visiting the `tag`'s code and block.
|
|
*
|
|
* @param {Tag} tag
|
|
* @api public
|
|
*/
|
|
|
|
visitTag: function(tag){
|
|
this.indents++;
|
|
var name = tag.name
|
|
, pp = this.pp
|
|
, self = this;
|
|
|
|
function bufferName() {
|
|
if (tag.buffer) self.bufferExpression(name);
|
|
else self.buffer(name);
|
|
}
|
|
|
|
if (!this.hasCompiledTag) {
|
|
if (!this.hasCompiledDoctype && 'html' == name) {
|
|
this.visitDoctype();
|
|
}
|
|
this.hasCompiledTag = true;
|
|
}
|
|
|
|
// pretty print
|
|
if (pp && !tag.isInline())
|
|
this.prettyIndent(0, true);
|
|
|
|
if ((~selfClosing.indexOf(name) || tag.selfClosing) && !this.xml) {
|
|
this.buffer('<');
|
|
bufferName();
|
|
this.visitAttributes(tag.attrs);
|
|
this.terse
|
|
? this.buffer('>')
|
|
: this.buffer('/>');
|
|
} else {
|
|
// Optimize attributes buffering
|
|
if (tag.attrs.length) {
|
|
this.buffer('<');
|
|
bufferName();
|
|
if (tag.attrs.length) this.visitAttributes(tag.attrs);
|
|
this.buffer('>');
|
|
} else {
|
|
this.buffer('<');
|
|
bufferName();
|
|
this.buffer('>');
|
|
}
|
|
if (tag.code) this.visitCode(tag.code);
|
|
this.escape = 'pre' == tag.name;
|
|
this.visit(tag.block);
|
|
|
|
// pretty print
|
|
if (pp && !tag.isInline() && 'pre' != tag.name && !tag.canInline())
|
|
this.prettyIndent(0, true);
|
|
|
|
this.buffer('</');
|
|
bufferName();
|
|
this.buffer('>');
|
|
}
|
|
this.indents--;
|
|
},
|
|
|
|
/**
|
|
* Visit `filter`, throwing when the filter does not exist.
|
|
*
|
|
* @param {Filter} filter
|
|
* @api public
|
|
*/
|
|
|
|
visitFilter: function(filter){
|
|
var text = filter.block.nodes.map(
|
|
function(node){ return node.val; }
|
|
).join('\n');
|
|
filter.attrs = filter.attrs || {};
|
|
filter.attrs.filename = this.options.filename;
|
|
this.buffer(filters(filter.name, text, filter.attrs), true);
|
|
},
|
|
|
|
/**
|
|
* Visit `text` node.
|
|
*
|
|
* @param {Text} text
|
|
* @api public
|
|
*/
|
|
|
|
visitText: function(text){
|
|
this.buffer(text.val, true);
|
|
},
|
|
|
|
/**
|
|
* Visit a `comment`, only buffering when the buffer flag is set.
|
|
*
|
|
* @param {Comment} comment
|
|
* @api public
|
|
*/
|
|
|
|
visitComment: function(comment){
|
|
if (!comment.buffer) return;
|
|
if (this.pp) this.prettyIndent(1, true);
|
|
this.buffer('<!--' + comment.val + '-->');
|
|
},
|
|
|
|
/**
|
|
* Visit a `BlockComment`.
|
|
*
|
|
* @param {Comment} comment
|
|
* @api public
|
|
*/
|
|
|
|
visitBlockComment: function(comment){
|
|
if (!comment.buffer) return;
|
|
if (0 == comment.val.trim().indexOf('if')) {
|
|
this.buffer('<!--[' + comment.val.trim() + ']>');
|
|
this.visit(comment.block);
|
|
this.buffer('<![endif]-->');
|
|
} else {
|
|
this.buffer('<!--' + comment.val);
|
|
this.visit(comment.block);
|
|
this.buffer('-->');
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Visit `code`, respecting buffer / escape flags.
|
|
* If the code is followed by a block, wrap it in
|
|
* a self-calling function.
|
|
*
|
|
* @param {Code} code
|
|
* @api public
|
|
*/
|
|
|
|
visitCode: function(code){
|
|
// Wrap code blocks with {}.
|
|
// we only wrap unbuffered code blocks ATM
|
|
// since they are usually flow control
|
|
|
|
// Buffer code
|
|
if (code.buffer) {
|
|
var val = code.val.trimLeft();
|
|
val = 'null == (jade.interp = '+val+') ? "" : jade.interp';
|
|
if (code.escape) val = 'jade.escape(' + val + ')';
|
|
this.bufferExpression(val);
|
|
} else {
|
|
this.buf.push(code.val);
|
|
}
|
|
|
|
// Block support
|
|
if (code.block) {
|
|
if (!code.buffer) this.buf.push('{');
|
|
this.visit(code.block);
|
|
if (!code.buffer) this.buf.push('}');
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Visit `each` block.
|
|
*
|
|
* @param {Each} each
|
|
* @api public
|
|
*/
|
|
|
|
visitEach: function(each){
|
|
this.buf.push(''
|
|
+ '// iterate ' + each.obj + '\n'
|
|
+ ';(function(){\n'
|
|
+ ' var $$obj = ' + each.obj + ';\n'
|
|
+ ' if (\'number\' == typeof $$obj.length) {\n');
|
|
|
|
if (each.alternative) {
|
|
this.buf.push(' if ($$obj.length) {');
|
|
}
|
|
|
|
this.buf.push(''
|
|
+ ' for (var ' + each.key + ' = 0, $$l = $$obj.length; ' + each.key + ' < $$l; ' + each.key + '++) {\n'
|
|
+ ' var ' + each.val + ' = $$obj[' + each.key + '];\n');
|
|
|
|
this.visit(each.block);
|
|
|
|
this.buf.push(' }\n');
|
|
|
|
if (each.alternative) {
|
|
this.buf.push(' } else {');
|
|
this.visit(each.alternative);
|
|
this.buf.push(' }');
|
|
}
|
|
|
|
this.buf.push(''
|
|
+ ' } else {\n'
|
|
+ ' var $$l = 0;\n'
|
|
+ ' for (var ' + each.key + ' in $$obj) {\n'
|
|
+ ' $$l++;'
|
|
+ ' var ' + each.val + ' = $$obj[' + each.key + '];\n');
|
|
|
|
this.visit(each.block);
|
|
|
|
this.buf.push(' }\n');
|
|
if (each.alternative) {
|
|
this.buf.push(' if ($$l === 0) {');
|
|
this.visit(each.alternative);
|
|
this.buf.push(' }');
|
|
}
|
|
this.buf.push(' }\n}).call(this);\n');
|
|
},
|
|
|
|
/**
|
|
* Visit `attrs`.
|
|
*
|
|
* @param {Array} attrs
|
|
* @api public
|
|
*/
|
|
|
|
visitAttributes: function(attrs){
|
|
var val = this.attrs(attrs);
|
|
if (val.inherits) {
|
|
this.bufferExpression("jade.attrs(jade.merge({ " + val.buf +
|
|
" }, attributes), jade.merge(" + val.escaped + ", escaped, true))");
|
|
} else if (val.constant) {
|
|
this.buffer(runtime.attrs(toConstant('{' + val.buf + '}'), JSON.parse(val.escaped)));
|
|
} else {
|
|
this.bufferExpression("jade.attrs({ " + val.buf + " }, " + val.escaped + ")");
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Compile attributes.
|
|
*/
|
|
|
|
attrs: function(attrs){
|
|
var buf = []
|
|
, classes = []
|
|
, escaped = {}
|
|
, constant = attrs.every(function(attr){ return isConstant(attr.val) })
|
|
, inherits = false;
|
|
|
|
if (this.terse) buf.push('terse: true');
|
|
|
|
attrs.forEach(function(attr){
|
|
if (attr.name == 'attributes') return inherits = true;
|
|
escaped[attr.name] = attr.escaped;
|
|
if (attr.name == 'class') {
|
|
classes.push('(' + attr.val + ')');
|
|
} else {
|
|
var pair = "'" + attr.name + "':(" + attr.val + ')';
|
|
buf.push(pair);
|
|
}
|
|
});
|
|
|
|
if (classes.length) {
|
|
buf.push('"class": [' + classes.join(',') + ']');
|
|
}
|
|
|
|
return {
|
|
buf: buf.join(', '),
|
|
escaped: JSON.stringify(escaped),
|
|
inherits: inherits,
|
|
constant: constant
|
|
};
|
|
}
|
|
};
|
|
})()
|
|
},{"./filters":6,"./doctypes":3,"./self-closing":4,"./utils":5,"./runtime":2,"./nodes":13,"character-parser":28,"constantinople":29}],17:[function(require,module,exports){
|
|
|
|
/*!
|
|
* Jade - nodes - Tag
|
|
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
/**
|
|
* Module dependencies.
|
|
*/
|
|
|
|
var Attrs = require('./attrs'),
|
|
Block = require('./block'),
|
|
inlineTags = require('../inline-tags');
|
|
|
|
/**
|
|
* Initialize a `Tag` node with the given tag `name` and optional `block`.
|
|
*
|
|
* @param {String} name
|
|
* @param {Block} block
|
|
* @api public
|
|
*/
|
|
|
|
var Tag = module.exports = function Tag(name, block) {
|
|
this.name = name;
|
|
this.attrs = [];
|
|
this.block = block || new Block;
|
|
};
|
|
|
|
/**
|
|
* Inherit from `Attrs`.
|
|
*/
|
|
|
|
Tag.prototype.__proto__ = Attrs.prototype;
|
|
|
|
/**
|
|
* Clone this tag.
|
|
*
|
|
* @return {Tag}
|
|
* @api private
|
|
*/
|
|
|
|
Tag.prototype.clone = function(){
|
|
var clone = new Tag(this.name, this.block.clone());
|
|
clone.line = this.line;
|
|
clone.attrs = this.attrs;
|
|
clone.textOnly = this.textOnly;
|
|
return clone;
|
|
};
|
|
|
|
/**
|
|
* Check if this tag is an inline tag.
|
|
*
|
|
* @return {Boolean}
|
|
* @api private
|
|
*/
|
|
|
|
Tag.prototype.isInline = function(){
|
|
return ~inlineTags.indexOf(this.name);
|
|
};
|
|
|
|
/**
|
|
* Check if this tag's contents can be inlined. Used for pretty printing.
|
|
*
|
|
* @return {Boolean}
|
|
* @api private
|
|
*/
|
|
|
|
Tag.prototype.canInline = function(){
|
|
var nodes = this.block.nodes;
|
|
|
|
function isInline(node){
|
|
// Recurse if the node is a block
|
|
if (node.isBlock) return node.nodes.every(isInline);
|
|
return node.isText || (node.isInline && node.isInline());
|
|
}
|
|
|
|
// Empty tag
|
|
if (!nodes.length) return true;
|
|
|
|
// Text-only or inline-only tag
|
|
if (1 == nodes.length) return isInline(nodes[0]);
|
|
|
|
// Multi-line inline-only tag
|
|
if (this.block.nodes.every(isInline)) {
|
|
for (var i = 1, len = nodes.length; i < len; ++i) {
|
|
if (nodes[i-1].isText && nodes[i].isText)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Mixed tag
|
|
return false;
|
|
};
|
|
},{"./attrs":30,"./block":21,"../inline-tags":31}],20:[function(require,module,exports){
|
|
|
|
/*!
|
|
* Jade - nodes - Case
|
|
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
/**
|
|
* Module dependencies.
|
|
*/
|
|
|
|
var Node = require('./node');
|
|
|
|
/**
|
|
* Initialize a new `Case` with `expr`.
|
|
*
|
|
* @param {String} expr
|
|
* @api public
|
|
*/
|
|
|
|
var Case = exports = module.exports = function Case(expr, block){
|
|
this.expr = expr;
|
|
this.block = block;
|
|
};
|
|
|
|
/**
|
|
* Inherit from `Node`.
|
|
*/
|
|
|
|
Case.prototype.__proto__ = Node.prototype;
|
|
|
|
var When = exports.When = function When(expr, block){
|
|
this.expr = expr;
|
|
this.block = block;
|
|
this.debug = false;
|
|
};
|
|
|
|
/**
|
|
* Inherit from `Node`.
|
|
*/
|
|
|
|
When.prototype.__proto__ = Node.prototype;
|
|
|
|
|
|
},{"./node":15}],16:[function(require,module,exports){
|
|
|
|
/*!
|
|
* Jade - nodes - Each
|
|
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
/**
|
|
* Module dependencies.
|
|
*/
|
|
|
|
var Node = require('./node');
|
|
|
|
/**
|
|
* Initialize an `Each` node, representing iteration
|
|
*
|
|
* @param {String} obj
|
|
* @param {String} val
|
|
* @param {String} key
|
|
* @param {Block} block
|
|
* @api public
|
|
*/
|
|
|
|
var Each = module.exports = function Each(obj, val, key, block) {
|
|
this.obj = obj;
|
|
this.val = val;
|
|
this.key = key;
|
|
this.block = block;
|
|
};
|
|
|
|
/**
|
|
* Inherit from `Node`.
|
|
*/
|
|
|
|
Each.prototype.__proto__ = Node.prototype;
|
|
},{"./node":15}],24:[function(require,module,exports){
|
|
|
|
/*!
|
|
* Jade - nodes - Mixin
|
|
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
/**
|
|
* Module dependencies.
|
|
*/
|
|
|
|
var Attrs = require('./attrs');
|
|
|
|
/**
|
|
* Initialize a new `Mixin` with `name` and `block`.
|
|
*
|
|
* @param {String} name
|
|
* @param {String} args
|
|
* @param {Block} block
|
|
* @api public
|
|
*/
|
|
|
|
var Mixin = module.exports = function Mixin(name, args, block, call){
|
|
this.name = name;
|
|
this.args = args;
|
|
this.block = block;
|
|
this.attrs = [];
|
|
this.call = call;
|
|
};
|
|
|
|
/**
|
|
* Inherit from `Attrs`.
|
|
*/
|
|
|
|
Mixin.prototype.__proto__ = Attrs.prototype;
|
|
|
|
|
|
},{"./attrs":30}],25:[function(require,module,exports){
|
|
|
|
/*!
|
|
* Jade - nodes - Literal
|
|
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
/**
|
|
* Module dependencies.
|
|
*/
|
|
|
|
var Node = require('./node');
|
|
|
|
/**
|
|
* Initialize a `Literal` node with the given `str.
|
|
*
|
|
* @param {String} str
|
|
* @api public
|
|
*/
|
|
|
|
var Literal = module.exports = function Literal(str) {
|
|
this.str = str;
|
|
};
|
|
|
|
/**
|
|
* Inherit from `Node`.
|
|
*/
|
|
|
|
Literal.prototype.__proto__ = Node.prototype;
|
|
|
|
},{"./node":15}],18:[function(require,module,exports){
|
|
|
|
/*!
|
|
* Jade - nodes - Text
|
|
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
/**
|
|
* Module dependencies.
|
|
*/
|
|
|
|
var Node = require('./node');
|
|
|
|
/**
|
|
* Initialize a `Text` node with optional `line`.
|
|
*
|
|
* @param {String} line
|
|
* @api public
|
|
*/
|
|
|
|
var Text = module.exports = function Text(line) {
|
|
this.val = '';
|
|
if ('string' == typeof line) this.val = line;
|
|
};
|
|
|
|
/**
|
|
* Inherit from `Node`.
|
|
*/
|
|
|
|
Text.prototype.__proto__ = Node.prototype;
|
|
|
|
/**
|
|
* Flag as text.
|
|
*/
|
|
|
|
Text.prototype.isText = true;
|
|
},{"./node":15}],27:[function(require,module,exports){
|
|
|
|
/*!
|
|
* Jade - nodes - BlockComment
|
|
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
/**
|
|
* Module dependencies.
|
|
*/
|
|
|
|
var Node = require('./node');
|
|
|
|
/**
|
|
* Initialize a `BlockComment` with the given `block`.
|
|
*
|
|
* @param {String} val
|
|
* @param {Block} block
|
|
* @param {Boolean} buffer
|
|
* @api public
|
|
*/
|
|
|
|
var BlockComment = module.exports = function BlockComment(val, block, buffer) {
|
|
this.block = block;
|
|
this.val = val;
|
|
this.buffer = buffer;
|
|
};
|
|
|
|
/**
|
|
* Inherit from `Node`.
|
|
*/
|
|
|
|
BlockComment.prototype.__proto__ = Node.prototype;
|
|
},{"./node":15}],19:[function(require,module,exports){
|
|
|
|
/*!
|
|
* Jade - nodes - Code
|
|
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
/**
|
|
* Module dependencies.
|
|
*/
|
|
|
|
var Node = require('./node');
|
|
|
|
/**
|
|
* Initialize a `Code` node with the given code `val`.
|
|
* Code may also be optionally buffered and escaped.
|
|
*
|
|
* @param {String} val
|
|
* @param {Boolean} buffer
|
|
* @param {Boolean} escape
|
|
* @api public
|
|
*/
|
|
|
|
var Code = module.exports = function Code(val, buffer, escape) {
|
|
this.val = val;
|
|
this.buffer = buffer;
|
|
this.escape = escape;
|
|
if (val.match(/^ *else/)) this.debug = false;
|
|
};
|
|
|
|
/**
|
|
* Inherit from `Node`.
|
|
*/
|
|
|
|
Code.prototype.__proto__ = Node.prototype;
|
|
},{"./node":15}],22:[function(require,module,exports){
|
|
|
|
/*!
|
|
* Jade - nodes - Filter
|
|
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
/**
|
|
* Module dependencies.
|
|
*/
|
|
|
|
var Node = require('./node')
|
|
, Block = require('./block');
|
|
|
|
/**
|
|
* Initialize a `Filter` node with the given
|
|
* filter `name` and `block`.
|
|
*
|
|
* @param {String} name
|
|
* @param {Block|Node} block
|
|
* @api public
|
|
*/
|
|
|
|
var Filter = module.exports = function Filter(name, block, attrs) {
|
|
this.name = name;
|
|
this.block = block;
|
|
this.attrs = attrs;
|
|
};
|
|
|
|
/**
|
|
* Inherit from `Node`.
|
|
*/
|
|
|
|
Filter.prototype.__proto__ = Node.prototype;
|
|
},{"./node":15,"./block":21}],23:[function(require,module,exports){
|
|
|
|
/*!
|
|
* Jade - nodes - Comment
|
|
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
/**
|
|
* Module dependencies.
|
|
*/
|
|
|
|
var Node = require('./node');
|
|
|
|
/**
|
|
* Initialize a `Comment` with the given `val`, optionally `buffer`,
|
|
* otherwise the comment may render in the output.
|
|
*
|
|
* @param {String} val
|
|
* @param {Boolean} buffer
|
|
* @api public
|
|
*/
|
|
|
|
var Comment = module.exports = function Comment(val, buffer) {
|
|
this.val = val;
|
|
this.buffer = buffer;
|
|
};
|
|
|
|
/**
|
|
* Inherit from `Node`.
|
|
*/
|
|
|
|
Comment.prototype.__proto__ = Node.prototype;
|
|
},{"./node":15}],26:[function(require,module,exports){
|
|
|
|
/*!
|
|
* Jade - nodes - Doctype
|
|
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
/**
|
|
* Module dependencies.
|
|
*/
|
|
|
|
var Node = require('./node');
|
|
|
|
/**
|
|
* Initialize a `Doctype` with the given `val`.
|
|
*
|
|
* @param {String} val
|
|
* @api public
|
|
*/
|
|
|
|
var Doctype = module.exports = function Doctype(val) {
|
|
this.val = val;
|
|
};
|
|
|
|
/**
|
|
* Inherit from `Node`.
|
|
*/
|
|
|
|
Doctype.prototype.__proto__ = Node.prototype;
|
|
},{"./node":15}],21:[function(require,module,exports){
|
|
|
|
/*!
|
|
* Jade - nodes - Block
|
|
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
/**
|
|
* Module dependencies.
|
|
*/
|
|
|
|
var Node = require('./node');
|
|
|
|
/**
|
|
* Initialize a new `Block` with an optional `node`.
|
|
*
|
|
* @param {Node} node
|
|
* @api public
|
|
*/
|
|
|
|
var Block = module.exports = function Block(node){
|
|
this.nodes = [];
|
|
if (node) this.push(node);
|
|
};
|
|
|
|
/**
|
|
* Inherit from `Node`.
|
|
*/
|
|
|
|
Block.prototype.__proto__ = Node.prototype;
|
|
|
|
/**
|
|
* Block flag.
|
|
*/
|
|
|
|
Block.prototype.isBlock = true;
|
|
|
|
/**
|
|
* Replace the nodes in `other` with the nodes
|
|
* in `this` block.
|
|
*
|
|
* @param {Block} other
|
|
* @api private
|
|
*/
|
|
|
|
Block.prototype.replace = function(other){
|
|
other.nodes = this.nodes;
|
|
};
|
|
|
|
/**
|
|
* Pust the given `node`.
|
|
*
|
|
* @param {Node} node
|
|
* @return {Number}
|
|
* @api public
|
|
*/
|
|
|
|
Block.prototype.push = function(node){
|
|
return this.nodes.push(node);
|
|
};
|
|
|
|
/**
|
|
* Check if this block is empty.
|
|
*
|
|
* @return {Boolean}
|
|
* @api public
|
|
*/
|
|
|
|
Block.prototype.isEmpty = function(){
|
|
return 0 == this.nodes.length;
|
|
};
|
|
|
|
/**
|
|
* Unshift the given `node`.
|
|
*
|
|
* @param {Node} node
|
|
* @return {Number}
|
|
* @api public
|
|
*/
|
|
|
|
Block.prototype.unshift = function(node){
|
|
return this.nodes.unshift(node);
|
|
};
|
|
|
|
/**
|
|
* Return the "last" block, or the first `yield` node.
|
|
*
|
|
* @return {Block}
|
|
* @api private
|
|
*/
|
|
|
|
Block.prototype.includeBlock = function(){
|
|
var ret = this
|
|
, node;
|
|
|
|
for (var i = 0, len = this.nodes.length; i < len; ++i) {
|
|
node = this.nodes[i];
|
|
if (node.yield) return node;
|
|
else if (node.textOnly) continue;
|
|
else if (node.includeBlock) ret = node.includeBlock();
|
|
else if (node.block && !node.block.isEmpty()) ret = node.block.includeBlock();
|
|
if (ret.yield) return ret;
|
|
}
|
|
|
|
return ret;
|
|
};
|
|
|
|
/**
|
|
* Return a clone of this block.
|
|
*
|
|
* @return {Block}
|
|
* @api private
|
|
*/
|
|
|
|
Block.prototype.clone = function(){
|
|
var clone = new Block;
|
|
for (var i = 0, len = this.nodes.length; i < len; ++i) {
|
|
clone.push(this.nodes[i].clone());
|
|
}
|
|
return clone;
|
|
};
|
|
|
|
|
|
},{"./node":15}],28:[function(require,module,exports){
|
|
exports = (module.exports = parse);
|
|
exports.parse = parse;
|
|
function parse(src, state, options) {
|
|
options = options || {};
|
|
state = state || exports.defaultState();
|
|
var start = options.start || 0;
|
|
var end = options.end || src.length;
|
|
var index = start;
|
|
while (index < end) {
|
|
if (state.roundDepth < 0 || state.curlyDepth < 0 || state.squareDepth < 0) {
|
|
throw new SyntaxError('Mismatched Bracket: ' + src[index - 1]);
|
|
}
|
|
exports.parseChar(src[index++], state);
|
|
}
|
|
return state;
|
|
}
|
|
|
|
exports.parseMax = parseMax;
|
|
function parseMax(src, options) {
|
|
options = options || {};
|
|
var start = options.start || 0;
|
|
var index = start;
|
|
var state = exports.defaultState();
|
|
while (state.roundDepth >= 0 && state.curlyDepth >= 0 && state.squareDepth >= 0) {
|
|
if (index >= src.length) {
|
|
throw new Error('The end of the string was reached with no closing bracket found.');
|
|
}
|
|
exports.parseChar(src[index++], state);
|
|
}
|
|
var end = index - 1;
|
|
return {
|
|
start: start,
|
|
end: end,
|
|
src: src.substring(start, end)
|
|
};
|
|
}
|
|
|
|
exports.parseUntil = parseUntil;
|
|
function parseUntil(src, delimiter, options) {
|
|
options = options || {};
|
|
var includeLineComment = options.includeLineComment || false;
|
|
var start = options.start || 0;
|
|
var index = start;
|
|
var state = exports.defaultState();
|
|
while (state.singleQuote || state.doubleQuote || state.regexp || state.blockComment ||
|
|
(!includeLineComment && state.lineComment) || !startsWith(src, delimiter, index)) {
|
|
exports.parseChar(src[index++], state);
|
|
}
|
|
var end = index;
|
|
return {
|
|
start: start,
|
|
end: end,
|
|
src: src.substring(start, end)
|
|
};
|
|
}
|
|
|
|
|
|
exports.parseChar = parseChar;
|
|
function parseChar(character, state) {
|
|
if (character.length !== 1) throw new Error('Character must be a string of length 1');
|
|
state = state || defaultState();
|
|
var wasComment = state.blockComment || state.lineComment;
|
|
var lastChar = state.history ? state.history[0] : '';
|
|
if (state.lineComment) {
|
|
if (character === '\n') {
|
|
state.lineComment = false;
|
|
}
|
|
} else if (state.blockComment) {
|
|
if (state.lastChar === '*' && character === '/') {
|
|
state.blockComment = false;
|
|
}
|
|
} else if (state.singleQuote) {
|
|
if (character === '\'' && !state.escaped) {
|
|
state.singleQuote = false;
|
|
} else if (character === '\\' && !state.escaped) {
|
|
state.escaped = true;
|
|
} else {
|
|
state.escaped = false;
|
|
}
|
|
} else if (state.doubleQuote) {
|
|
if (character === '"' && !state.escaped) {
|
|
state.doubleQuote = false;
|
|
} else if (character === '\\' && !state.escaped) {
|
|
state.escaped = true;
|
|
} else {
|
|
state.escaped = false;
|
|
}
|
|
} else if (state.regexp) {
|
|
if (character === '/' && !state.escaped) {
|
|
state.regexp = false;
|
|
} else if (character === '\\' && !state.escaped) {
|
|
state.escaped = true;
|
|
} else {
|
|
state.escaped = false;
|
|
}
|
|
} else if (lastChar === '/' && character === '/') {
|
|
history = history.substr(1);
|
|
state.lineComment = true;
|
|
} else if (lastChar === '/' && character === '*') {
|
|
history = history.substr(1);
|
|
state.blockComment = true;
|
|
} else if (character === '/') {
|
|
//could be start of regexp or divide sign
|
|
var history = state.history.replace(/^\s*/, '');
|
|
if (history[0] === ')') {
|
|
//unless its an `if`, `while`, `for` or `with` it's a divide
|
|
//this is probably best left though
|
|
} else if (history[0] === '}') {
|
|
//unless it's a function expression, it's a regexp
|
|
//this is probably best left though
|
|
} else if (isPunctuator(history[0])) {
|
|
state.regexp = true;
|
|
} else if (/^\w+\b/.test(history) && isKeyword(/^\w+\b/.exec(history)[0])) {
|
|
state.regexp = true;
|
|
} else {
|
|
// assume it's divide
|
|
}
|
|
} else if (character === '\'') {
|
|
state.singleQuote = true;
|
|
} else if (character === '"') {
|
|
state.doubleQuote = true;
|
|
} else if (character === '(') {
|
|
state.roundDepth++;
|
|
} else if (character === ')') {
|
|
state.roundDepth--;
|
|
} else if (character === '{') {
|
|
state.curlyDepth++;
|
|
} else if (character === '}') {
|
|
state.curlyDepth--;
|
|
} else if (character === '[') {
|
|
state.squareDepth++;
|
|
} else if (character === ']') {
|
|
state.squareDepth--;
|
|
}
|
|
if (!state.blockComment && !state.lineComment && !wasComment) state.history = character + state.history;
|
|
return state;
|
|
}
|
|
|
|
exports.defaultState = defaultState;
|
|
function defaultState() {
|
|
return {
|
|
lineComment: false,
|
|
blockComment: false,
|
|
|
|
singleQuote: false,
|
|
doubleQuote: false,
|
|
regexp: false,
|
|
escaped: false,
|
|
|
|
roundDepth: 0,
|
|
curlyDepth: 0,
|
|
squareDepth: 0,
|
|
|
|
history: ''
|
|
};
|
|
}
|
|
|
|
function startsWith(str, start, i) {
|
|
return str.substr(i || 0, start.length) === start;
|
|
}
|
|
|
|
function isPunctuator(c) {
|
|
var code = c.charCodeAt(0)
|
|
|
|
switch (code) {
|
|
case 46: // . dot
|
|
case 40: // ( open bracket
|
|
case 41: // ) close bracket
|
|
case 59: // ; semicolon
|
|
case 44: // , comma
|
|
case 123: // { open curly brace
|
|
case 125: // } close curly brace
|
|
case 91: // [
|
|
case 93: // ]
|
|
case 58: // :
|
|
case 63: // ?
|
|
case 126: // ~
|
|
case 37: // %
|
|
case 38: // &
|
|
case 42: // *:
|
|
case 43: // +
|
|
case 45: // -
|
|
case 47: // /
|
|
case 60: // <
|
|
case 62: // >
|
|
case 94: // ^
|
|
case 124: // |
|
|
case 33: // !
|
|
case 61: // =
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
function isKeyword(id) {
|
|
return (id === 'if') || (id === 'in') || (id === 'do') || (id === 'var') || (id === 'for') || (id === 'new') ||
|
|
(id === 'try') || (id === 'let') || (id === 'this') || (id === 'else') || (id === 'case') ||
|
|
(id === 'void') || (id === 'with') || (id === 'enum') || (id === 'while') || (id === 'break') || (id === 'catch') ||
|
|
(id === 'throw') || (id === 'const') || (id === 'yield') || (id === 'class') || (id === 'super') ||
|
|
(id === 'return') || (id === 'typeof') || (id === 'delete') || (id === 'switch') || (id === 'export') ||
|
|
(id === 'import') || (id === 'default') || (id === 'finally') || (id === 'extends') || (id === 'function') ||
|
|
(id === 'continue') || (id === 'debugger') || (id === 'package') || (id === 'private') || (id === 'interface') ||
|
|
(id === 'instanceof') || (id === 'implements') || (id === 'protected') || (id === 'public') || (id === 'static') ||
|
|
(id === 'yield') || (id === 'let');
|
|
}
|
|
|
|
},{}],31:[function(require,module,exports){
|
|
|
|
/*!
|
|
* Jade - inline tags
|
|
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
module.exports = [
|
|
'a'
|
|
, 'abbr'
|
|
, 'acronym'
|
|
, 'b'
|
|
, 'br'
|
|
, 'code'
|
|
, 'em'
|
|
, 'font'
|
|
, 'i'
|
|
, 'img'
|
|
, 'ins'
|
|
, 'kbd'
|
|
, 'map'
|
|
, 'samp'
|
|
, 'small'
|
|
, 'span'
|
|
, 'strong'
|
|
, 'sub'
|
|
, 'sup'
|
|
];
|
|
},{}],14:[function(require,module,exports){
|
|
(function(global){var uglify = require('uglify-js')
|
|
|
|
|
|
module.exports = addWith
|
|
|
|
function addWith(obj, src, exclude) {
|
|
exclude = exclude || []
|
|
exclude = exclude.concat(detect(obj))
|
|
var vars = detect('(function () {' + src + '}())')//allows the `return` keyword
|
|
.filter(function (v) {
|
|
return !(v in global) && exclude.indexOf(v) === -1
|
|
})
|
|
|
|
if (vars.length === 0) return src
|
|
|
|
var declareLocal = ''
|
|
var local = 'locals'
|
|
if (/^[a-zA-Z0-9$_]+$/.test(obj)) {
|
|
local = obj
|
|
} else {
|
|
while (vars.indexOf(local) != -1 || exclude.indexOf(local) != -1) {
|
|
local += '_'
|
|
}
|
|
declareLocal = local + ' = (' + obj + '),'
|
|
}
|
|
return 'var ' + declareLocal + vars
|
|
.map(function (v) {
|
|
return v + ' = ' + local + '.' + v
|
|
}).join(',') + ';' + src
|
|
}
|
|
|
|
function detect(src) {
|
|
var ast = uglify.parse(src.toString())
|
|
ast.figure_out_scope()
|
|
var globals = ast.globals
|
|
.map(function (node, name) {
|
|
return name
|
|
})
|
|
return globals;
|
|
}
|
|
})(window)
|
|
},{"uglify-js":32}],30:[function(require,module,exports){
|
|
|
|
/*!
|
|
* Jade - nodes - Attrs
|
|
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
/**
|
|
* Module dependencies.
|
|
*/
|
|
|
|
var Node = require('./node'),
|
|
Block = require('./block');
|
|
|
|
/**
|
|
* Initialize a `Attrs` node.
|
|
*
|
|
* @api public
|
|
*/
|
|
|
|
var Attrs = module.exports = function Attrs() {
|
|
this.attrs = [];
|
|
};
|
|
|
|
/**
|
|
* Inherit from `Node`.
|
|
*/
|
|
|
|
Attrs.prototype.__proto__ = Node.prototype;
|
|
|
|
/**
|
|
* Set attribute `name` to `val`, keep in mind these become
|
|
* part of a raw js object literal, so to quote a value you must
|
|
* '"quote me"', otherwise or example 'user.name' is literal JavaScript.
|
|
*
|
|
* @param {String} name
|
|
* @param {String} val
|
|
* @param {Boolean} escaped
|
|
* @return {Tag} for chaining
|
|
* @api public
|
|
*/
|
|
|
|
Attrs.prototype.setAttribute = function(name, val, escaped){
|
|
this.attrs.push({ name: name, val: val, escaped: escaped });
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Remove attribute `name` when present.
|
|
*
|
|
* @param {String} name
|
|
* @api public
|
|
*/
|
|
|
|
Attrs.prototype.removeAttribute = function(name){
|
|
for (var i = 0, len = this.attrs.length; i < len; ++i) {
|
|
if (this.attrs[i] && this.attrs[i].name == name) {
|
|
delete this.attrs[i];
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Get attribute value by `name`.
|
|
*
|
|
* @param {String} name
|
|
* @return {String}
|
|
* @api public
|
|
*/
|
|
|
|
Attrs.prototype.getAttribute = function(name){
|
|
for (var i = 0, len = this.attrs.length; i < len; ++i) {
|
|
if (this.attrs[i] && this.attrs[i].name == name) {
|
|
return this.attrs[i].val;
|
|
}
|
|
}
|
|
};
|
|
|
|
},{"./node":15,"./block":21}],29:[function(require,module,exports){
|
|
'use strict'
|
|
|
|
var uglify = require('uglify-js')
|
|
|
|
var lastSRC = '(null)'
|
|
var lastRes = true
|
|
|
|
module.exports = isConstant
|
|
function isConstant(src) {
|
|
src = '(' + src + ')'
|
|
if (lastSRC === src) return lastRes
|
|
lastSRC = src
|
|
try {
|
|
return lastRes = (detect(src).length === 0)
|
|
} catch (ex) {
|
|
return lastRes = false
|
|
}
|
|
}
|
|
isConstant.isConstant = isConstant
|
|
|
|
isConstant.toConstant = toConstant
|
|
function toConstant(src) {
|
|
if (!isConstant(src)) throw new Error(JSON.stringify(src) + ' is not constant.')
|
|
return Function('return (' + src + ')')()
|
|
}
|
|
|
|
function detect(src) {
|
|
var ast = uglify.parse(src.toString())
|
|
ast.figure_out_scope()
|
|
var globals = ast.globals
|
|
.map(function (node, name) {
|
|
return name
|
|
})
|
|
return globals
|
|
}
|
|
},{"uglify-js":32}],33:[function(require,module,exports){
|
|
var Object_keys = function (obj) {
|
|
if (Object.keys) return Object.keys(obj)
|
|
else {
|
|
var res = [];
|
|
for (var key in obj) res.push(key)
|
|
return res;
|
|
}
|
|
};
|
|
|
|
var forEach = function (xs, fn) {
|
|
if (xs.forEach) return xs.forEach(fn)
|
|
else for (var i = 0; i < xs.length; i++) {
|
|
fn(xs[i], i, xs);
|
|
}
|
|
};
|
|
|
|
var Script = exports.Script = function NodeScript (code) {
|
|
if (!(this instanceof Script)) return new Script(code);
|
|
this.code = code;
|
|
};
|
|
|
|
Script.prototype.runInNewContext = function (context) {
|
|
if (!context) context = {};
|
|
|
|
var iframe = document.createElement('iframe');
|
|
if (!iframe.style) iframe.style = {};
|
|
iframe.style.display = 'none';
|
|
|
|
document.body.appendChild(iframe);
|
|
|
|
var win = iframe.contentWindow;
|
|
|
|
forEach(Object_keys(context), function (key) {
|
|
win[key] = context[key];
|
|
});
|
|
|
|
if (!win.eval && win.execScript) {
|
|
// win.eval() magically appears when this is called in IE:
|
|
win.execScript('null');
|
|
}
|
|
|
|
var res = win.eval(this.code);
|
|
|
|
forEach(Object_keys(win), function (key) {
|
|
context[key] = win[key];
|
|
});
|
|
|
|
document.body.removeChild(iframe);
|
|
|
|
return res;
|
|
};
|
|
|
|
Script.prototype.runInThisContext = function () {
|
|
return eval(this.code); // maybe...
|
|
};
|
|
|
|
Script.prototype.runInContext = function (context) {
|
|
// seems to be just runInNewContext on magical context objects which are
|
|
// otherwise indistinguishable from objects except plain old objects
|
|
// for the parameter segfaults node
|
|
return this.runInNewContext(context);
|
|
};
|
|
|
|
forEach(Object_keys(Script.prototype), function (name) {
|
|
exports[name] = Script[name] = function (code) {
|
|
var s = Script(code);
|
|
return s[name].apply(s, [].slice.call(arguments, 1));
|
|
};
|
|
});
|
|
|
|
exports.createScript = function (code) {
|
|
return exports.Script(code);
|
|
};
|
|
|
|
exports.createContext = Script.createContext = function (context) {
|
|
// not really sure what this one does
|
|
// seems to just make a shallow copy
|
|
var copy = {};
|
|
if(typeof context === 'object') {
|
|
forEach(Object_keys(context), function (key) {
|
|
copy[key] = context[key];
|
|
});
|
|
}
|
|
return copy;
|
|
};
|
|
|
|
},{}],32:[function(require,module,exports){
|
|
(function(process,__filename){var path = require("path");
|
|
var fs = require("fs");
|
|
var vm = require("vm");
|
|
var sys = require("util");
|
|
|
|
var UglifyJS = vm.createContext({
|
|
sys : sys,
|
|
console : console,
|
|
MOZ_SourceMap : require("source-map")
|
|
});
|
|
|
|
function load_global(file) {
|
|
file = path.resolve(path.dirname(module.filename), file);
|
|
try {
|
|
var code = fs.readFileSync(file, "utf8");
|
|
return vm.runInContext(code, UglifyJS, file);
|
|
} catch(ex) {
|
|
// XXX: in case of a syntax error, the message is kinda
|
|
// useless. (no location information).
|
|
sys.debug("ERROR in file: " + file + " / " + ex);
|
|
process.exit(1);
|
|
}
|
|
};
|
|
|
|
var FILES = exports.FILES = [
|
|
"../lib/utils.js",
|
|
"../lib/ast.js",
|
|
"../lib/parse.js",
|
|
"../lib/transform.js",
|
|
"../lib/scope.js",
|
|
"../lib/output.js",
|
|
"../lib/compress.js",
|
|
"../lib/sourcemap.js",
|
|
"../lib/mozilla-ast.js"
|
|
].map(function(file){
|
|
return path.join(path.dirname(fs.realpathSync(__filename)), file);
|
|
});
|
|
|
|
FILES.forEach(load_global);
|
|
|
|
UglifyJS.AST_Node.warn_function = function(txt) {
|
|
sys.error("WARN: " + txt);
|
|
};
|
|
|
|
// XXX: perhaps we shouldn't export everything but heck, I'm lazy.
|
|
for (var i in UglifyJS) {
|
|
if (UglifyJS.hasOwnProperty(i)) {
|
|
exports[i] = UglifyJS[i];
|
|
}
|
|
}
|
|
|
|
exports.minify = function(files, options) {
|
|
options = UglifyJS.defaults(options, {
|
|
outSourceMap : null,
|
|
sourceRoot : null,
|
|
inSourceMap : null,
|
|
fromString : false,
|
|
warnings : false,
|
|
mangle : {},
|
|
output : null,
|
|
compress : {}
|
|
});
|
|
if (typeof files == "string")
|
|
files = [ files ];
|
|
|
|
// 1. parse
|
|
var toplevel = null;
|
|
files.forEach(function(file){
|
|
var code = options.fromString
|
|
? file
|
|
: fs.readFileSync(file, "utf8");
|
|
toplevel = UglifyJS.parse(code, {
|
|
filename: options.fromString ? "?" : file,
|
|
toplevel: toplevel
|
|
});
|
|
});
|
|
|
|
// 2. compress
|
|
if (options.compress) {
|
|
var compress = { warnings: options.warnings };
|
|
UglifyJS.merge(compress, options.compress);
|
|
toplevel.figure_out_scope();
|
|
var sq = UglifyJS.Compressor(compress);
|
|
toplevel = toplevel.transform(sq);
|
|
}
|
|
|
|
// 3. mangle
|
|
if (options.mangle) {
|
|
toplevel.figure_out_scope();
|
|
toplevel.compute_char_frequency();
|
|
toplevel.mangle_names(options.mangle);
|
|
}
|
|
|
|
// 4. output
|
|
var inMap = options.inSourceMap;
|
|
var output = {};
|
|
if (typeof options.inSourceMap == "string") {
|
|
inMap = fs.readFileSync(options.inSourceMap, "utf8");
|
|
}
|
|
if (options.outSourceMap) {
|
|
output.source_map = UglifyJS.SourceMap({
|
|
file: options.outSourceMap,
|
|
orig: inMap,
|
|
root: options.sourceRoot
|
|
});
|
|
}
|
|
if (options.output) {
|
|
UglifyJS.merge(output, options.output);
|
|
}
|
|
var stream = UglifyJS.OutputStream(output);
|
|
toplevel.print(stream);
|
|
return {
|
|
code : stream + "",
|
|
map : output.source_map + ""
|
|
};
|
|
};
|
|
|
|
// exports.describe_ast = function() {
|
|
// function doitem(ctor) {
|
|
// var sub = {};
|
|
// ctor.SUBCLASSES.forEach(function(ctor){
|
|
// sub[ctor.TYPE] = doitem(ctor);
|
|
// });
|
|
// var ret = {};
|
|
// if (ctor.SELF_PROPS.length > 0) ret.props = ctor.SELF_PROPS;
|
|
// if (ctor.SUBCLASSES.length > 0) ret.sub = sub;
|
|
// return ret;
|
|
// }
|
|
// return doitem(UglifyJS.AST_Node).sub;
|
|
// }
|
|
|
|
exports.describe_ast = function() {
|
|
var out = UglifyJS.OutputStream({ beautify: true });
|
|
function doitem(ctor) {
|
|
out.print("AST_" + ctor.TYPE);
|
|
var props = ctor.SELF_PROPS.filter(function(prop){
|
|
return !/^\$/.test(prop);
|
|
});
|
|
if (props.length > 0) {
|
|
out.space();
|
|
out.with_parens(function(){
|
|
props.forEach(function(prop, i){
|
|
if (i) out.space();
|
|
out.print(prop);
|
|
});
|
|
});
|
|
}
|
|
if (ctor.documentation) {
|
|
out.space();
|
|
out.print_string(ctor.documentation);
|
|
}
|
|
if (ctor.SUBCLASSES.length > 0) {
|
|
out.space();
|
|
out.with_block(function(){
|
|
ctor.SUBCLASSES.forEach(function(ctor, i){
|
|
out.indent();
|
|
doitem(ctor);
|
|
out.newline();
|
|
});
|
|
});
|
|
}
|
|
};
|
|
doitem(UglifyJS.AST_Node);
|
|
return out + "";
|
|
};
|
|
|
|
})(require("__browserify_process"),"/..\\node_modules\\uglify-js\\tools\\node.js")
|
|
},{"path":8,"fs":1,"vm":33,"util":34,"source-map":35,"__browserify_process":7}],34:[function(require,module,exports){
|
|
var events = require('events');
|
|
|
|
exports.isArray = isArray;
|
|
exports.isDate = function(obj){return Object.prototype.toString.call(obj) === '[object Date]'};
|
|
exports.isRegExp = function(obj){return Object.prototype.toString.call(obj) === '[object RegExp]'};
|
|
|
|
|
|
exports.print = function () {};
|
|
exports.puts = function () {};
|
|
exports.debug = function() {};
|
|
|
|
exports.inspect = function(obj, showHidden, depth, colors) {
|
|
var seen = [];
|
|
|
|
var stylize = function(str, styleType) {
|
|
// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
|
|
var styles =
|
|
{ '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] };
|
|
|
|
var style =
|
|
{ 'special': 'cyan',
|
|
'number': 'blue',
|
|
'boolean': 'yellow',
|
|
'undefined': 'grey',
|
|
'null': 'bold',
|
|
'string': 'green',
|
|
'date': 'magenta',
|
|
// "name": intentionally not styling
|
|
'regexp': 'red' }[styleType];
|
|
|
|
if (style) {
|
|
return '\033[' + styles[style][0] + 'm' + str +
|
|
'\033[' + styles[style][1] + 'm';
|
|
} else {
|
|
return str;
|
|
}
|
|
};
|
|
if (! colors) {
|
|
stylize = function(str, styleType) { return str; };
|
|
}
|
|
|
|
function format(value, recurseTimes) {
|
|
// Provide a hook for user-specified inspect functions.
|
|
// Check that value is an object with an inspect function on it
|
|
if (value && typeof value.inspect === 'function' &&
|
|
// Filter out the util module, it's inspect function is special
|
|
value !== exports &&
|
|
// Also filter out any prototype objects using the circular check.
|
|
!(value.constructor && value.constructor.prototype === value)) {
|
|
return value.inspect(recurseTimes);
|
|
}
|
|
|
|
// Primitive types cannot have properties
|
|
switch (typeof value) {
|
|
case 'undefined':
|
|
return stylize('undefined', 'undefined');
|
|
|
|
case 'string':
|
|
var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
|
|
.replace(/'/g, "\\'")
|
|
.replace(/\\"/g, '"') + '\'';
|
|
return stylize(simple, 'string');
|
|
|
|
case 'number':
|
|
return stylize('' + value, 'number');
|
|
|
|
case 'boolean':
|
|
return stylize('' + value, 'boolean');
|
|
}
|
|
// For some reason typeof null is "object", so special case here.
|
|
if (value === null) {
|
|
return stylize('null', 'null');
|
|
}
|
|
|
|
// Look up the keys of the object.
|
|
var visible_keys = Object_keys(value);
|
|
var keys = showHidden ? Object_getOwnPropertyNames(value) : visible_keys;
|
|
|
|
// Functions without properties can be shortcutted.
|
|
if (typeof value === 'function' && keys.length === 0) {
|
|
if (isRegExp(value)) {
|
|
return stylize('' + value, 'regexp');
|
|
} else {
|
|
var name = value.name ? ': ' + value.name : '';
|
|
return stylize('[Function' + name + ']', 'special');
|
|
}
|
|
}
|
|
|
|
// Dates without properties can be shortcutted
|
|
if (isDate(value) && keys.length === 0) {
|
|
return stylize(value.toUTCString(), 'date');
|
|
}
|
|
|
|
var base, type, braces;
|
|
// Determine the object type
|
|
if (isArray(value)) {
|
|
type = 'Array';
|
|
braces = ['[', ']'];
|
|
} else {
|
|
type = 'Object';
|
|
braces = ['{', '}'];
|
|
}
|
|
|
|
// Make functions say that they are functions
|
|
if (typeof value === 'function') {
|
|
var n = value.name ? ': ' + value.name : '';
|
|
base = (isRegExp(value)) ? ' ' + value : ' [Function' + n + ']';
|
|
} else {
|
|
base = '';
|
|
}
|
|
|
|
// Make dates with properties first say the date
|
|
if (isDate(value)) {
|
|
base = ' ' + value.toUTCString();
|
|
}
|
|
|
|
if (keys.length === 0) {
|
|
return braces[0] + base + braces[1];
|
|
}
|
|
|
|
if (recurseTimes < 0) {
|
|
if (isRegExp(value)) {
|
|
return stylize('' + value, 'regexp');
|
|
} else {
|
|
return stylize('[Object]', 'special');
|
|
}
|
|
}
|
|
|
|
seen.push(value);
|
|
|
|
var output = keys.map(function(key) {
|
|
var name, str;
|
|
if (value.__lookupGetter__) {
|
|
if (value.__lookupGetter__(key)) {
|
|
if (value.__lookupSetter__(key)) {
|
|
str = stylize('[Getter/Setter]', 'special');
|
|
} else {
|
|
str = stylize('[Getter]', 'special');
|
|
}
|
|
} else {
|
|
if (value.__lookupSetter__(key)) {
|
|
str = stylize('[Setter]', 'special');
|
|
}
|
|
}
|
|
}
|
|
if (visible_keys.indexOf(key) < 0) {
|
|
name = '[' + key + ']';
|
|
}
|
|
if (!str) {
|
|
if (seen.indexOf(value[key]) < 0) {
|
|
if (recurseTimes === null) {
|
|
str = format(value[key]);
|
|
} else {
|
|
str = format(value[key], recurseTimes - 1);
|
|
}
|
|
if (str.indexOf('\n') > -1) {
|
|
if (isArray(value)) {
|
|
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 = stylize('[Circular]', 'special');
|
|
}
|
|
}
|
|
if (typeof name === 'undefined') {
|
|
if (type === '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 = stylize(name, 'name');
|
|
} else {
|
|
name = name.replace(/'/g, "\\'")
|
|
.replace(/\\"/g, '"')
|
|
.replace(/(^"|"$)/g, "'");
|
|
name = stylize(name, 'string');
|
|
}
|
|
}
|
|
|
|
return name + ': ' + str;
|
|
});
|
|
|
|
seen.pop();
|
|
|
|
var numLinesEst = 0;
|
|
var length = output.reduce(function(prev, cur) {
|
|
numLinesEst++;
|
|
if (cur.indexOf('\n') >= 0) numLinesEst++;
|
|
return prev + cur.length + 1;
|
|
}, 0);
|
|
|
|
if (length > 50) {
|
|
output = braces[0] +
|
|
(base === '' ? '' : base + '\n ') +
|
|
' ' +
|
|
output.join(',\n ') +
|
|
' ' +
|
|
braces[1];
|
|
|
|
} else {
|
|
output = braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
|
|
}
|
|
|
|
return output;
|
|
}
|
|
return format(obj, (typeof depth === 'undefined' ? 2 : depth));
|
|
};
|
|
|
|
|
|
function isArray(ar) {
|
|
return ar instanceof Array ||
|
|
Array.isArray(ar) ||
|
|
(ar && ar !== Object.prototype && isArray(ar.__proto__));
|
|
}
|
|
|
|
|
|
function isRegExp(re) {
|
|
return re instanceof RegExp ||
|
|
(typeof re === 'object' && Object.prototype.toString.call(re) === '[object RegExp]');
|
|
}
|
|
|
|
|
|
function isDate(d) {
|
|
if (d instanceof Date) return true;
|
|
if (typeof d !== 'object') return false;
|
|
var properties = Date.prototype && Object_getOwnPropertyNames(Date.prototype);
|
|
var proto = d.__proto__ && Object_getOwnPropertyNames(d.__proto__);
|
|
return JSON.stringify(proto) === JSON.stringify(properties);
|
|
}
|
|
|
|
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(' ');
|
|
}
|
|
|
|
exports.log = function (msg) {};
|
|
|
|
exports.pump = null;
|
|
|
|
var Object_keys = Object.keys || function (obj) {
|
|
var res = [];
|
|
for (var key in obj) res.push(key);
|
|
return res;
|
|
};
|
|
|
|
var Object_getOwnPropertyNames = Object.getOwnPropertyNames || function (obj) {
|
|
var res = [];
|
|
for (var key in obj) {
|
|
if (Object.hasOwnProperty.call(obj, key)) res.push(key);
|
|
}
|
|
return res;
|
|
};
|
|
|
|
var Object_create = Object.create || function (prototype, properties) {
|
|
// from es5-shim
|
|
var object;
|
|
if (prototype === null) {
|
|
object = { '__proto__' : null };
|
|
}
|
|
else {
|
|
if (typeof prototype !== 'object') {
|
|
throw new TypeError(
|
|
'typeof prototype[' + (typeof prototype) + '] != \'object\''
|
|
);
|
|
}
|
|
var Type = function () {};
|
|
Type.prototype = prototype;
|
|
object = new Type();
|
|
object.__proto__ = prototype;
|
|
}
|
|
if (typeof properties !== 'undefined' && Object.defineProperties) {
|
|
Object.defineProperties(object, properties);
|
|
}
|
|
return object;
|
|
};
|
|
|
|
exports.inherits = function(ctor, superCtor) {
|
|
ctor.super_ = superCtor;
|
|
ctor.prototype = Object_create(superCtor.prototype, {
|
|
constructor: {
|
|
value: ctor,
|
|
enumerable: false,
|
|
writable: true,
|
|
configurable: true
|
|
}
|
|
});
|
|
};
|
|
|
|
var formatRegExp = /%[sdj%]/g;
|
|
exports.format = function(f) {
|
|
if (typeof f !== 'string') {
|
|
var objects = [];
|
|
for (var i = 0; i < arguments.length; i++) {
|
|
objects.push(exports.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': return JSON.stringify(args[i++]);
|
|
default:
|
|
return x;
|
|
}
|
|
});
|
|
for(var x = args[i]; i < len; x = args[++i]){
|
|
if (x === null || typeof x !== 'object') {
|
|
str += ' ' + x;
|
|
} else {
|
|
str += ' ' + exports.inspect(x);
|
|
}
|
|
}
|
|
return str;
|
|
};
|
|
|
|
},{"events":36}],35:[function(require,module,exports){
|
|
/*
|
|
* Copyright 2009-2011 Mozilla Foundation and contributors
|
|
* Licensed under the New BSD license. See LICENSE.txt or:
|
|
* http://opensource.org/licenses/BSD-3-Clause
|
|
*/
|
|
exports.SourceMapGenerator = require('./source-map/source-map-generator').SourceMapGenerator;
|
|
exports.SourceMapConsumer = require('./source-map/source-map-consumer').SourceMapConsumer;
|
|
exports.SourceNode = require('./source-map/source-node').SourceNode;
|
|
|
|
},{"./source-map/source-map-generator":37,"./source-map/source-map-consumer":38,"./source-map/source-node":39}],36:[function(require,module,exports){
|
|
(function(process){if (!process.EventEmitter) process.EventEmitter = function () {};
|
|
|
|
var EventEmitter = exports.EventEmitter = process.EventEmitter;
|
|
var isArray = typeof Array.isArray === 'function'
|
|
? Array.isArray
|
|
: function (xs) {
|
|
return Object.prototype.toString.call(xs) === '[object Array]'
|
|
}
|
|
;
|
|
function indexOf (xs, x) {
|
|
if (xs.indexOf) return xs.indexOf(x);
|
|
for (var i = 0; i < xs.length; i++) {
|
|
if (x === xs[i]) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// 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.
|
|
//
|
|
// Obviously not all Emitters should be limited to 10. This function allows
|
|
// that to be increased. Set to zero for unlimited.
|
|
var defaultMaxListeners = 10;
|
|
EventEmitter.prototype.setMaxListeners = function(n) {
|
|
if (!this._events) this._events = {};
|
|
this._events.maxListeners = n;
|
|
};
|
|
|
|
|
|
EventEmitter.prototype.emit = function(type) {
|
|
// If there is no 'error' event listener then throw.
|
|
if (type === 'error') {
|
|
if (!this._events || !this._events.error ||
|
|
(isArray(this._events.error) && !this._events.error.length))
|
|
{
|
|
if (arguments[1] instanceof Error) {
|
|
throw arguments[1]; // Unhandled 'error' event
|
|
} else {
|
|
throw new Error("Uncaught, unspecified 'error' event.");
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!this._events) return false;
|
|
var handler = this._events[type];
|
|
if (!handler) return false;
|
|
|
|
if (typeof handler == 'function') {
|
|
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:
|
|
var args = Array.prototype.slice.call(arguments, 1);
|
|
handler.apply(this, args);
|
|
}
|
|
return true;
|
|
|
|
} else if (isArray(handler)) {
|
|
var args = Array.prototype.slice.call(arguments, 1);
|
|
|
|
var listeners = handler.slice();
|
|
for (var i = 0, l = listeners.length; i < l; i++) {
|
|
listeners[i].apply(this, args);
|
|
}
|
|
return true;
|
|
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
// EventEmitter is defined in src/node_events.cc
|
|
// EventEmitter.prototype.emit() is also defined there.
|
|
EventEmitter.prototype.addListener = function(type, listener) {
|
|
if ('function' !== typeof listener) {
|
|
throw new Error('addListener only takes instances of Function');
|
|
}
|
|
|
|
if (!this._events) this._events = {};
|
|
|
|
// To avoid recursion in the case that type == "newListeners"! Before
|
|
// adding it to the listeners, first emit "newListeners".
|
|
this.emit('newListener', type, listener);
|
|
|
|
if (!this._events[type]) {
|
|
// Optimize the case of one listener. Don't need the extra array object.
|
|
this._events[type] = listener;
|
|
} else if (isArray(this._events[type])) {
|
|
|
|
// Check for listener leak
|
|
if (!this._events[type].warned) {
|
|
var m;
|
|
if (this._events.maxListeners !== undefined) {
|
|
m = this._events.maxListeners;
|
|
} else {
|
|
m = 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);
|
|
console.trace();
|
|
}
|
|
}
|
|
|
|
// 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];
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
|
|
|
|
EventEmitter.prototype.once = function(type, listener) {
|
|
var self = this;
|
|
self.on(type, function g() {
|
|
self.removeListener(type, g);
|
|
listener.apply(this, arguments);
|
|
});
|
|
|
|
return this;
|
|
};
|
|
|
|
EventEmitter.prototype.removeListener = function(type, listener) {
|
|
if ('function' !== typeof listener) {
|
|
throw new Error('removeListener only takes instances of Function');
|
|
}
|
|
|
|
// does not use listeners(), so no side effect of creating _events[type]
|
|
if (!this._events || !this._events[type]) return this;
|
|
|
|
var list = this._events[type];
|
|
|
|
if (isArray(list)) {
|
|
var i = indexOf(list, listener);
|
|
if (i < 0) return this;
|
|
list.splice(i, 1);
|
|
if (list.length == 0)
|
|
delete this._events[type];
|
|
} else if (this._events[type] === listener) {
|
|
delete this._events[type];
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
EventEmitter.prototype.removeAllListeners = function(type) {
|
|
if (arguments.length === 0) {
|
|
this._events = {};
|
|
return this;
|
|
}
|
|
|
|
// does not use listeners(), so no side effect of creating _events[type]
|
|
if (type && this._events && this._events[type]) this._events[type] = null;
|
|
return this;
|
|
};
|
|
|
|
EventEmitter.prototype.listeners = function(type) {
|
|
if (!this._events) this._events = {};
|
|
if (!this._events[type]) this._events[type] = [];
|
|
if (!isArray(this._events[type])) {
|
|
this._events[type] = [this._events[type]];
|
|
}
|
|
return this._events[type];
|
|
};
|
|
|
|
})(require("__browserify_process"))
|
|
},{"__browserify_process":7}],39:[function(require,module,exports){
|
|
/* -*- Mode: js; js-indent-level: 2; -*- */
|
|
/*
|
|
* Copyright 2011 Mozilla Foundation and contributors
|
|
* Licensed under the New BSD license. See LICENSE or:
|
|
* http://opensource.org/licenses/BSD-3-Clause
|
|
*/
|
|
if (typeof define !== 'function') {
|
|
var define = require('amdefine')(module);
|
|
}
|
|
define(function (require, exports, module) {
|
|
|
|
var SourceMapGenerator = require('./source-map-generator').SourceMapGenerator;
|
|
var util = require('./util');
|
|
|
|
/**
|
|
* SourceNodes provide a way to abstract over interpolating/concatenating
|
|
* snippets of generated JavaScript source code while maintaining the line and
|
|
* column information associated with the original source code.
|
|
*
|
|
* @param aLine The original line number.
|
|
* @param aColumn The original column number.
|
|
* @param aSource The original source's filename.
|
|
* @param aChunks Optional. An array of strings which are snippets of
|
|
* generated JS, or other SourceNodes.
|
|
* @param aName The original identifier.
|
|
*/
|
|
function SourceNode(aLine, aColumn, aSource, aChunks, aName) {
|
|
this.children = [];
|
|
this.sourceContents = {};
|
|
this.line = aLine === undefined ? null : aLine;
|
|
this.column = aColumn === undefined ? null : aColumn;
|
|
this.source = aSource === undefined ? null : aSource;
|
|
this.name = aName === undefined ? null : aName;
|
|
if (aChunks != null) this.add(aChunks);
|
|
}
|
|
|
|
/**
|
|
* Creates a SourceNode from generated code and a SourceMapConsumer.
|
|
*
|
|
* @param aGeneratedCode The generated code
|
|
* @param aSourceMapConsumer The SourceMap for the generated code
|
|
*/
|
|
SourceNode.fromStringWithSourceMap =
|
|
function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer) {
|
|
// The SourceNode we want to fill with the generated code
|
|
// and the SourceMap
|
|
var node = new SourceNode();
|
|
|
|
// The generated code
|
|
// Processed fragments are removed from this array.
|
|
var remainingLines = aGeneratedCode.split('\n');
|
|
|
|
// We need to remember the position of "remainingLines"
|
|
var lastGeneratedLine = 1, lastGeneratedColumn = 0;
|
|
|
|
// The generate SourceNodes we need a code range.
|
|
// To extract it current and last mapping is used.
|
|
// Here we store the last mapping.
|
|
var lastMapping = null;
|
|
|
|
aSourceMapConsumer.eachMapping(function (mapping) {
|
|
if (lastMapping === null) {
|
|
// We add the generated code until the first mapping
|
|
// to the SourceNode without any mapping.
|
|
// Each line is added as separate string.
|
|
while (lastGeneratedLine < mapping.generatedLine) {
|
|
node.add(remainingLines.shift() + "\n");
|
|
lastGeneratedLine++;
|
|
}
|
|
if (lastGeneratedColumn < mapping.generatedColumn) {
|
|
var nextLine = remainingLines[0];
|
|
node.add(nextLine.substr(0, mapping.generatedColumn));
|
|
remainingLines[0] = nextLine.substr(mapping.generatedColumn);
|
|
lastGeneratedColumn = mapping.generatedColumn;
|
|
}
|
|
} else {
|
|
// We add the code from "lastMapping" to "mapping":
|
|
// First check if there is a new line in between.
|
|
if (lastGeneratedLine < mapping.generatedLine) {
|
|
var code = "";
|
|
// Associate full lines with "lastMapping"
|
|
do {
|
|
code += remainingLines.shift() + "\n";
|
|
lastGeneratedLine++;
|
|
lastGeneratedColumn = 0;
|
|
} while (lastGeneratedLine < mapping.generatedLine);
|
|
// When we reached the correct line, we add code until we
|
|
// reach the correct column too.
|
|
if (lastGeneratedColumn < mapping.generatedColumn) {
|
|
var nextLine = remainingLines[0];
|
|
code += nextLine.substr(0, mapping.generatedColumn);
|
|
remainingLines[0] = nextLine.substr(mapping.generatedColumn);
|
|
lastGeneratedColumn = mapping.generatedColumn;
|
|
}
|
|
// Create the SourceNode.
|
|
addMappingWithCode(lastMapping, code);
|
|
} else {
|
|
// There is no new line in between.
|
|
// Associate the code between "lastGeneratedColumn" and
|
|
// "mapping.generatedColumn" with "lastMapping"
|
|
var nextLine = remainingLines[0];
|
|
var code = nextLine.substr(0, mapping.generatedColumn -
|
|
lastGeneratedColumn);
|
|
remainingLines[0] = nextLine.substr(mapping.generatedColumn -
|
|
lastGeneratedColumn);
|
|
lastGeneratedColumn = mapping.generatedColumn;
|
|
addMappingWithCode(lastMapping, code);
|
|
}
|
|
}
|
|
lastMapping = mapping;
|
|
}, this);
|
|
// We have processed all mappings.
|
|
// Associate the remaining code in the current line with "lastMapping"
|
|
// and add the remaining lines without any mapping
|
|
addMappingWithCode(lastMapping, remainingLines.join("\n"));
|
|
|
|
// Copy sourcesContent into SourceNode
|
|
aSourceMapConsumer.sources.forEach(function (sourceFile) {
|
|
var content = aSourceMapConsumer.sourceContentFor(sourceFile);
|
|
if (content) {
|
|
node.setSourceContent(sourceFile, content);
|
|
}
|
|
});
|
|
|
|
return node;
|
|
|
|
function addMappingWithCode(mapping, code) {
|
|
if (mapping.source === undefined) {
|
|
node.add(code);
|
|
} else {
|
|
node.add(new SourceNode(mapping.originalLine,
|
|
mapping.originalColumn,
|
|
mapping.source,
|
|
code,
|
|
mapping.name));
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Add a chunk of generated JS to this source node.
|
|
*
|
|
* @param aChunk A string snippet of generated JS code, another instance of
|
|
* SourceNode, or an array where each member is one of those things.
|
|
*/
|
|
SourceNode.prototype.add = function SourceNode_add(aChunk) {
|
|
if (Array.isArray(aChunk)) {
|
|
aChunk.forEach(function (chunk) {
|
|
this.add(chunk);
|
|
}, this);
|
|
}
|
|
else if (aChunk instanceof SourceNode || typeof aChunk === "string") {
|
|
if (aChunk) {
|
|
this.children.push(aChunk);
|
|
}
|
|
}
|
|
else {
|
|
throw new TypeError(
|
|
"Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk
|
|
);
|
|
}
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Add a chunk of generated JS to the beginning of this source node.
|
|
*
|
|
* @param aChunk A string snippet of generated JS code, another instance of
|
|
* SourceNode, or an array where each member is one of those things.
|
|
*/
|
|
SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) {
|
|
if (Array.isArray(aChunk)) {
|
|
for (var i = aChunk.length-1; i >= 0; i--) {
|
|
this.prepend(aChunk[i]);
|
|
}
|
|
}
|
|
else if (aChunk instanceof SourceNode || typeof aChunk === "string") {
|
|
this.children.unshift(aChunk);
|
|
}
|
|
else {
|
|
throw new TypeError(
|
|
"Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk
|
|
);
|
|
}
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Walk over the tree of JS snippets in this node and its children. The
|
|
* walking function is called once for each snippet of JS and is passed that
|
|
* snippet and the its original associated source's line/column location.
|
|
*
|
|
* @param aFn The traversal function.
|
|
*/
|
|
SourceNode.prototype.walk = function SourceNode_walk(aFn) {
|
|
this.children.forEach(function (chunk) {
|
|
if (chunk instanceof SourceNode) {
|
|
chunk.walk(aFn);
|
|
}
|
|
else {
|
|
if (chunk !== '') {
|
|
aFn(chunk, { source: this.source,
|
|
line: this.line,
|
|
column: this.column,
|
|
name: this.name });
|
|
}
|
|
}
|
|
}, this);
|
|
};
|
|
|
|
/**
|
|
* Like `String.prototype.join` except for SourceNodes. Inserts `aStr` between
|
|
* each of `this.children`.
|
|
*
|
|
* @param aSep The separator.
|
|
*/
|
|
SourceNode.prototype.join = function SourceNode_join(aSep) {
|
|
var newChildren;
|
|
var i;
|
|
var len = this.children.length;
|
|
if (len > 0) {
|
|
newChildren = [];
|
|
for (i = 0; i < len-1; i++) {
|
|
newChildren.push(this.children[i]);
|
|
newChildren.push(aSep);
|
|
}
|
|
newChildren.push(this.children[i]);
|
|
this.children = newChildren;
|
|
}
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Call String.prototype.replace on the very right-most source snippet. Useful
|
|
* for trimming whitespace from the end of a source node, etc.
|
|
*
|
|
* @param aPattern The pattern to replace.
|
|
* @param aReplacement The thing to replace the pattern with.
|
|
*/
|
|
SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) {
|
|
var lastChild = this.children[this.children.length - 1];
|
|
if (lastChild instanceof SourceNode) {
|
|
lastChild.replaceRight(aPattern, aReplacement);
|
|
}
|
|
else if (typeof lastChild === 'string') {
|
|
this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement);
|
|
}
|
|
else {
|
|
this.children.push(''.replace(aPattern, aReplacement));
|
|
}
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Set the source content for a source file. This will be added to the SourceMapGenerator
|
|
* in the sourcesContent field.
|
|
*
|
|
* @param aSourceFile The filename of the source file
|
|
* @param aSourceContent The content of the source file
|
|
*/
|
|
SourceNode.prototype.setSourceContent =
|
|
function SourceNode_setSourceContent(aSourceFile, aSourceContent) {
|
|
this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent;
|
|
};
|
|
|
|
/**
|
|
* Walk over the tree of SourceNodes. The walking function is called for each
|
|
* source file content and is passed the filename and source content.
|
|
*
|
|
* @param aFn The traversal function.
|
|
*/
|
|
SourceNode.prototype.walkSourceContents =
|
|
function SourceNode_walkSourceContents(aFn) {
|
|
this.children.forEach(function (chunk) {
|
|
if (chunk instanceof SourceNode) {
|
|
chunk.walkSourceContents(aFn);
|
|
}
|
|
}, this);
|
|
Object.keys(this.sourceContents).forEach(function (sourceFileKey) {
|
|
aFn(util.fromSetString(sourceFileKey), this.sourceContents[sourceFileKey]);
|
|
}, this);
|
|
};
|
|
|
|
/**
|
|
* Return the string representation of this source node. Walks over the tree
|
|
* and concatenates all the various snippets together to one string.
|
|
*/
|
|
SourceNode.prototype.toString = function SourceNode_toString() {
|
|
var str = "";
|
|
this.walk(function (chunk) {
|
|
str += chunk;
|
|
});
|
|
return str;
|
|
};
|
|
|
|
/**
|
|
* Returns the string representation of this source node along with a source
|
|
* map.
|
|
*/
|
|
SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) {
|
|
var generated = {
|
|
code: "",
|
|
line: 1,
|
|
column: 0
|
|
};
|
|
var map = new SourceMapGenerator(aArgs);
|
|
var sourceMappingActive = false;
|
|
this.walk(function (chunk, original) {
|
|
generated.code += chunk;
|
|
if (original.source !== null
|
|
&& original.line !== null
|
|
&& original.column !== null) {
|
|
map.addMapping({
|
|
source: original.source,
|
|
original: {
|
|
line: original.line,
|
|
column: original.column
|
|
},
|
|
generated: {
|
|
line: generated.line,
|
|
column: generated.column
|
|
},
|
|
name: original.name
|
|
});
|
|
sourceMappingActive = true;
|
|
} else if (sourceMappingActive) {
|
|
map.addMapping({
|
|
generated: {
|
|
line: generated.line,
|
|
column: generated.column
|
|
}
|
|
});
|
|
sourceMappingActive = false;
|
|
}
|
|
chunk.split('').forEach(function (ch) {
|
|
if (ch === '\n') {
|
|
generated.line++;
|
|
generated.column = 0;
|
|
} else {
|
|
generated.column++;
|
|
}
|
|
});
|
|
});
|
|
this.walkSourceContents(function (sourceFile, sourceContent) {
|
|
map.setSourceContent(sourceFile, sourceContent);
|
|
});
|
|
|
|
return { code: generated.code, map: map };
|
|
};
|
|
|
|
exports.SourceNode = SourceNode;
|
|
|
|
});
|
|
|
|
},{"./source-map-generator":37,"./util":40,"amdefine":41}],38:[function(require,module,exports){
|
|
/* -*- Mode: js; js-indent-level: 2; -*- */
|
|
/*
|
|
* Copyright 2011 Mozilla Foundation and contributors
|
|
* Licensed under the New BSD license. See LICENSE or:
|
|
* http://opensource.org/licenses/BSD-3-Clause
|
|
*/
|
|
if (typeof define !== 'function') {
|
|
var define = require('amdefine')(module);
|
|
}
|
|
define(function (require, exports, module) {
|
|
|
|
var util = require('./util');
|
|
var binarySearch = require('./binary-search');
|
|
var ArraySet = require('./array-set').ArraySet;
|
|
var base64VLQ = require('./base64-vlq');
|
|
|
|
/**
|
|
* A SourceMapConsumer instance represents a parsed source map which we can
|
|
* query for information about the original file positions by giving it a file
|
|
* position in the generated source.
|
|
*
|
|
* The only parameter is the raw source map (either as a JSON string, or
|
|
* already parsed to an object). According to the spec, source maps have the
|
|
* following attributes:
|
|
*
|
|
* - version: Which version of the source map spec this map is following.
|
|
* - sources: An array of URLs to the original source files.
|
|
* - names: An array of identifiers which can be referrenced by individual mappings.
|
|
* - sourceRoot: Optional. The URL root from which all sources are relative.
|
|
* - sourcesContent: Optional. An array of contents of the original source files.
|
|
* - mappings: A string of base64 VLQs which contain the actual mappings.
|
|
* - file: The generated file this source map is associated with.
|
|
*
|
|
* Here is an example source map, taken from the source map spec[0]:
|
|
*
|
|
* {
|
|
* version : 3,
|
|
* file: "out.js",
|
|
* sourceRoot : "",
|
|
* sources: ["foo.js", "bar.js"],
|
|
* names: ["src", "maps", "are", "fun"],
|
|
* mappings: "AA,AB;;ABCDE;"
|
|
* }
|
|
*
|
|
* [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1#
|
|
*/
|
|
function SourceMapConsumer(aSourceMap) {
|
|
var sourceMap = aSourceMap;
|
|
if (typeof aSourceMap === 'string') {
|
|
sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, ''));
|
|
}
|
|
|
|
var version = util.getArg(sourceMap, 'version');
|
|
var sources = util.getArg(sourceMap, 'sources');
|
|
var names = util.getArg(sourceMap, 'names');
|
|
var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null);
|
|
var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null);
|
|
var mappings = util.getArg(sourceMap, 'mappings');
|
|
var file = util.getArg(sourceMap, 'file');
|
|
|
|
if (version !== this._version) {
|
|
throw new Error('Unsupported version: ' + version);
|
|
}
|
|
|
|
this._names = ArraySet.fromArray(names);
|
|
this._sources = ArraySet.fromArray(sources);
|
|
this.sourceRoot = sourceRoot;
|
|
this.sourcesContent = sourcesContent;
|
|
this.file = file;
|
|
|
|
// `this._generatedMappings` and `this._originalMappings` hold the parsed
|
|
// mapping coordinates from the source map's "mappings" attribute. Each
|
|
// object in the array is of the form
|
|
//
|
|
// {
|
|
// generatedLine: The line number in the generated code,
|
|
// generatedColumn: The column number in the generated code,
|
|
// source: The path to the original source file that generated this
|
|
// chunk of code,
|
|
// originalLine: The line number in the original source that
|
|
// corresponds to this chunk of generated code,
|
|
// originalColumn: The column number in the original source that
|
|
// corresponds to this chunk of generated code,
|
|
// name: The name of the original symbol which generated this chunk of
|
|
// code.
|
|
// }
|
|
//
|
|
// All properties except for `generatedLine` and `generatedColumn` can be
|
|
// `null`.
|
|
//
|
|
// `this._generatedMappings` is ordered by the generated positions.
|
|
//
|
|
// `this._originalMappings` is ordered by the original positions.
|
|
this._generatedMappings = [];
|
|
this._originalMappings = [];
|
|
this._parseMappings(mappings, sourceRoot);
|
|
}
|
|
|
|
/**
|
|
* The version of the source mapping spec that we are consuming.
|
|
*/
|
|
SourceMapConsumer.prototype._version = 3;
|
|
|
|
/**
|
|
* The list of original sources.
|
|
*/
|
|
Object.defineProperty(SourceMapConsumer.prototype, 'sources', {
|
|
get: function () {
|
|
return this._sources.toArray().map(function (s) {
|
|
return this.sourceRoot ? util.join(this.sourceRoot, s) : s;
|
|
}, this);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Parse the mappings in a string in to a data structure which we can easily
|
|
* query (an ordered list in this._generatedMappings).
|
|
*/
|
|
SourceMapConsumer.prototype._parseMappings =
|
|
function SourceMapConsumer_parseMappings(aStr, aSourceRoot) {
|
|
var generatedLine = 1;
|
|
var previousGeneratedColumn = 0;
|
|
var previousOriginalLine = 0;
|
|
var previousOriginalColumn = 0;
|
|
var previousSource = 0;
|
|
var previousName = 0;
|
|
var mappingSeparator = /^[,;]/;
|
|
var str = aStr;
|
|
var mapping;
|
|
var temp;
|
|
|
|
while (str.length > 0) {
|
|
if (str.charAt(0) === ';') {
|
|
generatedLine++;
|
|
str = str.slice(1);
|
|
previousGeneratedColumn = 0;
|
|
}
|
|
else if (str.charAt(0) === ',') {
|
|
str = str.slice(1);
|
|
}
|
|
else {
|
|
mapping = {};
|
|
mapping.generatedLine = generatedLine;
|
|
|
|
// Generated column.
|
|
temp = base64VLQ.decode(str);
|
|
mapping.generatedColumn = previousGeneratedColumn + temp.value;
|
|
previousGeneratedColumn = mapping.generatedColumn;
|
|
str = temp.rest;
|
|
|
|
if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) {
|
|
// Original source.
|
|
temp = base64VLQ.decode(str);
|
|
mapping.source = this._sources.at(previousSource + temp.value);
|
|
previousSource += temp.value;
|
|
str = temp.rest;
|
|
if (str.length === 0 || mappingSeparator.test(str.charAt(0))) {
|
|
throw new Error('Found a source, but no line and column');
|
|
}
|
|
|
|
// Original line.
|
|
temp = base64VLQ.decode(str);
|
|
mapping.originalLine = previousOriginalLine + temp.value;
|
|
previousOriginalLine = mapping.originalLine;
|
|
// Lines are stored 0-based
|
|
mapping.originalLine += 1;
|
|
str = temp.rest;
|
|
if (str.length === 0 || mappingSeparator.test(str.charAt(0))) {
|
|
throw new Error('Found a source and line, but no column');
|
|
}
|
|
|
|
// Original column.
|
|
temp = base64VLQ.decode(str);
|
|
mapping.originalColumn = previousOriginalColumn + temp.value;
|
|
previousOriginalColumn = mapping.originalColumn;
|
|
str = temp.rest;
|
|
|
|
if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) {
|
|
// Original name.
|
|
temp = base64VLQ.decode(str);
|
|
mapping.name = this._names.at(previousName + temp.value);
|
|
previousName += temp.value;
|
|
str = temp.rest;
|
|
}
|
|
}
|
|
|
|
this._generatedMappings.push(mapping);
|
|
if (typeof mapping.originalLine === 'number') {
|
|
this._originalMappings.push(mapping);
|
|
}
|
|
}
|
|
}
|
|
|
|
this._originalMappings.sort(this._compareOriginalPositions);
|
|
};
|
|
|
|
/**
|
|
* Comparator between two mappings where the original positions are compared.
|
|
*/
|
|
SourceMapConsumer.prototype._compareOriginalPositions =
|
|
function SourceMapConsumer_compareOriginalPositions(mappingA, mappingB) {
|
|
if (mappingA.source > mappingB.source) {
|
|
return 1;
|
|
}
|
|
else if (mappingA.source < mappingB.source) {
|
|
return -1;
|
|
}
|
|
else {
|
|
var cmp = mappingA.originalLine - mappingB.originalLine;
|
|
return cmp === 0
|
|
? mappingA.originalColumn - mappingB.originalColumn
|
|
: cmp;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Comparator between two mappings where the generated positions are compared.
|
|
*/
|
|
SourceMapConsumer.prototype._compareGeneratedPositions =
|
|
function SourceMapConsumer_compareGeneratedPositions(mappingA, mappingB) {
|
|
var cmp = mappingA.generatedLine - mappingB.generatedLine;
|
|
return cmp === 0
|
|
? mappingA.generatedColumn - mappingB.generatedColumn
|
|
: cmp;
|
|
};
|
|
|
|
/**
|
|
* Find the mapping that best matches the hypothetical "needle" mapping that
|
|
* we are searching for in the given "haystack" of mappings.
|
|
*/
|
|
SourceMapConsumer.prototype._findMapping =
|
|
function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName,
|
|
aColumnName, aComparator) {
|
|
// To return the position we are searching for, we must first find the
|
|
// mapping for the given position and then return the opposite position it
|
|
// points to. Because the mappings are sorted, we can use binary search to
|
|
// find the best mapping.
|
|
|
|
if (aNeedle[aLineName] <= 0) {
|
|
throw new TypeError('Line must be greater than or equal to 1, got '
|
|
+ aNeedle[aLineName]);
|
|
}
|
|
if (aNeedle[aColumnName] < 0) {
|
|
throw new TypeError('Column must be greater than or equal to 0, got '
|
|
+ aNeedle[aColumnName]);
|
|
}
|
|
|
|
return binarySearch.search(aNeedle, aMappings, aComparator);
|
|
};
|
|
|
|
/**
|
|
* Returns the original source, line, and column information for the generated
|
|
* source's line and column positions provided. The only argument is an object
|
|
* with the following properties:
|
|
*
|
|
* - line: The line number in the generated source.
|
|
* - column: The column number in the generated source.
|
|
*
|
|
* and an object is returned with the following properties:
|
|
*
|
|
* - source: The original source file, or null.
|
|
* - line: The line number in the original source, or null.
|
|
* - column: The column number in the original source, or null.
|
|
* - name: The original identifier, or null.
|
|
*/
|
|
SourceMapConsumer.prototype.originalPositionFor =
|
|
function SourceMapConsumer_originalPositionFor(aArgs) {
|
|
var needle = {
|
|
generatedLine: util.getArg(aArgs, 'line'),
|
|
generatedColumn: util.getArg(aArgs, 'column')
|
|
};
|
|
|
|
var mapping = this._findMapping(needle,
|
|
this._generatedMappings,
|
|
"generatedLine",
|
|
"generatedColumn",
|
|
this._compareGeneratedPositions);
|
|
|
|
if (mapping) {
|
|
var source = util.getArg(mapping, 'source', null);
|
|
if (source && this.sourceRoot) {
|
|
source = util.join(this.sourceRoot, source);
|
|
}
|
|
return {
|
|
source: source,
|
|
line: util.getArg(mapping, 'originalLine', null),
|
|
column: util.getArg(mapping, 'originalColumn', null),
|
|
name: util.getArg(mapping, 'name', null)
|
|
};
|
|
}
|
|
|
|
return {
|
|
source: null,
|
|
line: null,
|
|
column: null,
|
|
name: null
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Returns the original source content. The only argument is
|
|
* the url of the original source file. Returns null if no
|
|
* original source content is availible.
|
|
*/
|
|
SourceMapConsumer.prototype.sourceContentFor =
|
|
function SourceMapConsumer_sourceContentFor(aSource) {
|
|
if (!this.sourcesContent) {
|
|
return null;
|
|
}
|
|
|
|
if (this.sourceRoot) {
|
|
aSource = util.relative(this.sourceRoot, aSource);
|
|
}
|
|
|
|
if (this._sources.has(aSource)) {
|
|
return this.sourcesContent[this._sources.indexOf(aSource)];
|
|
}
|
|
|
|
var url;
|
|
if (this.sourceRoot
|
|
&& (url = util.urlParse(this.sourceRoot))
|
|
&& (!url.path || url.path == "/")
|
|
&& this._sources.has("/" + aSource)) {
|
|
return this.sourcesContent[this._sources.indexOf("/" + aSource)];
|
|
}
|
|
|
|
throw new Error('"' + aSource + '" is not in the SourceMap.');
|
|
};
|
|
|
|
/**
|
|
* Returns the generated line and column information for the original source,
|
|
* line, and column positions provided. The only argument is an object with
|
|
* the following properties:
|
|
*
|
|
* - source: The filename of the original source.
|
|
* - line: The line number in the original source.
|
|
* - column: The column number in the original source.
|
|
*
|
|
* and an object is returned with the following properties:
|
|
*
|
|
* - line: The line number in the generated source, or null.
|
|
* - column: The column number in the generated source, or null.
|
|
*/
|
|
SourceMapConsumer.prototype.generatedPositionFor =
|
|
function SourceMapConsumer_generatedPositionFor(aArgs) {
|
|
var needle = {
|
|
source: util.getArg(aArgs, 'source'),
|
|
originalLine: util.getArg(aArgs, 'line'),
|
|
originalColumn: util.getArg(aArgs, 'column')
|
|
};
|
|
|
|
if (this.sourceRoot) {
|
|
needle.source = util.relative(this.sourceRoot, needle.source);
|
|
}
|
|
|
|
var mapping = this._findMapping(needle,
|
|
this._originalMappings,
|
|
"originalLine",
|
|
"originalColumn",
|
|
this._compareOriginalPositions);
|
|
|
|
if (mapping) {
|
|
return {
|
|
line: util.getArg(mapping, 'generatedLine', null),
|
|
column: util.getArg(mapping, 'generatedColumn', null)
|
|
};
|
|
}
|
|
|
|
return {
|
|
line: null,
|
|
column: null
|
|
};
|
|
};
|
|
|
|
SourceMapConsumer.GENERATED_ORDER = 1;
|
|
SourceMapConsumer.ORIGINAL_ORDER = 2;
|
|
|
|
/**
|
|
* Iterate over each mapping between an original source/line/column and a
|
|
* generated line/column in this source map.
|
|
*
|
|
* @param Function aCallback
|
|
* The function that is called with each mapping.
|
|
* @param Object aContext
|
|
* Optional. If specified, this object will be the value of `this` every
|
|
* time that `aCallback` is called.
|
|
* @param aOrder
|
|
* Either `SourceMapConsumer.GENERATED_ORDER` or
|
|
* `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to
|
|
* iterate over the mappings sorted by the generated file's line/column
|
|
* order or the original's source/line/column order, respectively. Defaults to
|
|
* `SourceMapConsumer.GENERATED_ORDER`.
|
|
*/
|
|
SourceMapConsumer.prototype.eachMapping =
|
|
function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) {
|
|
var context = aContext || null;
|
|
var order = aOrder || SourceMapConsumer.GENERATED_ORDER;
|
|
|
|
var mappings;
|
|
switch (order) {
|
|
case SourceMapConsumer.GENERATED_ORDER:
|
|
mappings = this._generatedMappings;
|
|
break;
|
|
case SourceMapConsumer.ORIGINAL_ORDER:
|
|
mappings = this._originalMappings;
|
|
break;
|
|
default:
|
|
throw new Error("Unknown order of iteration.");
|
|
}
|
|
|
|
var sourceRoot = this.sourceRoot;
|
|
mappings.map(function (mapping) {
|
|
var source = mapping.source;
|
|
if (source && sourceRoot) {
|
|
source = util.join(sourceRoot, source);
|
|
}
|
|
return {
|
|
source: source,
|
|
generatedLine: mapping.generatedLine,
|
|
generatedColumn: mapping.generatedColumn,
|
|
originalLine: mapping.originalLine,
|
|
originalColumn: mapping.originalColumn,
|
|
name: mapping.name
|
|
};
|
|
}).forEach(aCallback, context);
|
|
};
|
|
|
|
exports.SourceMapConsumer = SourceMapConsumer;
|
|
|
|
});
|
|
|
|
},{"./binary-search":42,"./util":40,"./array-set":43,"./base64-vlq":44,"amdefine":41}],37:[function(require,module,exports){
|
|
/* -*- Mode: js; js-indent-level: 2; -*- */
|
|
/*
|
|
* Copyright 2011 Mozilla Foundation and contributors
|
|
* Licensed under the New BSD license. See LICENSE or:
|
|
* http://opensource.org/licenses/BSD-3-Clause
|
|
*/
|
|
if (typeof define !== 'function') {
|
|
var define = require('amdefine')(module);
|
|
}
|
|
define(function (require, exports, module) {
|
|
|
|
var base64VLQ = require('./base64-vlq');
|
|
var util = require('./util');
|
|
var ArraySet = require('./array-set').ArraySet;
|
|
|
|
/**
|
|
* An instance of the SourceMapGenerator represents a source map which is
|
|
* being built incrementally. To create a new one, you must pass an object
|
|
* with the following properties:
|
|
*
|
|
* - file: The filename of the generated source.
|
|
* - sourceRoot: An optional root for all URLs in this source map.
|
|
*/
|
|
function SourceMapGenerator(aArgs) {
|
|
this._file = util.getArg(aArgs, 'file');
|
|
this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null);
|
|
this._sources = new ArraySet();
|
|
this._names = new ArraySet();
|
|
this._mappings = [];
|
|
this._sourcesContents = null;
|
|
}
|
|
|
|
SourceMapGenerator.prototype._version = 3;
|
|
|
|
/**
|
|
* Creates a new SourceMapGenerator based on a SourceMapConsumer
|
|
*
|
|
* @param aSourceMapConsumer The SourceMap.
|
|
*/
|
|
SourceMapGenerator.fromSourceMap =
|
|
function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) {
|
|
var sourceRoot = aSourceMapConsumer.sourceRoot;
|
|
var generator = new SourceMapGenerator({
|
|
file: aSourceMapConsumer.file,
|
|
sourceRoot: sourceRoot
|
|
});
|
|
aSourceMapConsumer.eachMapping(function (mapping) {
|
|
var newMapping = {
|
|
generated: {
|
|
line: mapping.generatedLine,
|
|
column: mapping.generatedColumn
|
|
}
|
|
};
|
|
|
|
if (mapping.source) {
|
|
newMapping.source = mapping.source;
|
|
if (sourceRoot) {
|
|
newMapping.source = util.relative(sourceRoot, newMapping.source);
|
|
}
|
|
|
|
newMapping.original = {
|
|
line: mapping.originalLine,
|
|
column: mapping.originalColumn
|
|
};
|
|
|
|
if (mapping.name) {
|
|
newMapping.name = mapping.name;
|
|
}
|
|
}
|
|
|
|
generator.addMapping(newMapping);
|
|
});
|
|
aSourceMapConsumer.sources.forEach(function (sourceFile) {
|
|
var content = aSourceMapConsumer.sourceContentFor(sourceFile);
|
|
if (content) {
|
|
generator.setSourceContent(sourceFile, content);
|
|
}
|
|
});
|
|
return generator;
|
|
};
|
|
|
|
/**
|
|
* Add a single mapping from original source line and column to the generated
|
|
* source's line and column for this source map being created. The mapping
|
|
* object should have the following properties:
|
|
*
|
|
* - generated: An object with the generated line and column positions.
|
|
* - original: An object with the original line and column positions.
|
|
* - source: The original source file (relative to the sourceRoot).
|
|
* - name: An optional original token name for this mapping.
|
|
*/
|
|
SourceMapGenerator.prototype.addMapping =
|
|
function SourceMapGenerator_addMapping(aArgs) {
|
|
var generated = util.getArg(aArgs, 'generated');
|
|
var original = util.getArg(aArgs, 'original', null);
|
|
var source = util.getArg(aArgs, 'source', null);
|
|
var name = util.getArg(aArgs, 'name', null);
|
|
|
|
this._validateMapping(generated, original, source, name);
|
|
|
|
if (source && !this._sources.has(source)) {
|
|
this._sources.add(source);
|
|
}
|
|
|
|
if (name && !this._names.has(name)) {
|
|
this._names.add(name);
|
|
}
|
|
|
|
this._mappings.push({
|
|
generated: generated,
|
|
original: original,
|
|
source: source,
|
|
name: name
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Set the source content for a source file.
|
|
*/
|
|
SourceMapGenerator.prototype.setSourceContent =
|
|
function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) {
|
|
var source = aSourceFile;
|
|
if (this._sourceRoot) {
|
|
source = util.relative(this._sourceRoot, source);
|
|
}
|
|
|
|
if (aSourceContent !== null) {
|
|
// Add the source content to the _sourcesContents map.
|
|
// Create a new _sourcesContents map if the property is null.
|
|
if (!this._sourcesContents) {
|
|
this._sourcesContents = {};
|
|
}
|
|
this._sourcesContents[util.toSetString(source)] = aSourceContent;
|
|
} else {
|
|
// Remove the source file from the _sourcesContents map.
|
|
// If the _sourcesContents map is empty, set the property to null.
|
|
delete this._sourcesContents[util.toSetString(source)];
|
|
if (Object.keys(this._sourcesContents).length === 0) {
|
|
this._sourcesContents = null;
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Applies the mappings of a sub-source-map for a specific source file to the
|
|
* source map being generated. Each mapping to the supplied source file is
|
|
* rewritten using the supplied source map. Note: The resolution for the
|
|
* resulting mappings is the minimium of this map and the supplied map.
|
|
*
|
|
* @param aSourceMapConsumer The source map to be applied.
|
|
* @param aSourceFile Optional. The filename of the source file.
|
|
* If omitted, SourceMapConsumer's file property will be used.
|
|
*/
|
|
SourceMapGenerator.prototype.applySourceMap =
|
|
function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile) {
|
|
// If aSourceFile is omitted, we will use the file property of the SourceMap
|
|
if (!aSourceFile) {
|
|
aSourceFile = aSourceMapConsumer.file;
|
|
}
|
|
var sourceRoot = this._sourceRoot;
|
|
// Make "aSourceFile" relative if an absolute Url is passed.
|
|
if (sourceRoot) {
|
|
aSourceFile = util.relative(sourceRoot, aSourceFile);
|
|
}
|
|
// Applying the SourceMap can add and remove items from the sources and
|
|
// the names array.
|
|
var newSources = new ArraySet();
|
|
var newNames = new ArraySet();
|
|
|
|
// Find mappings for the "aSourceFile"
|
|
this._mappings.forEach(function (mapping) {
|
|
if (mapping.source === aSourceFile && mapping.original) {
|
|
// Check if it can be mapped by the source map, then update the mapping.
|
|
var original = aSourceMapConsumer.originalPositionFor({
|
|
line: mapping.original.line,
|
|
column: mapping.original.column
|
|
});
|
|
if (original.source !== null) {
|
|
// Copy mapping
|
|
if (sourceRoot) {
|
|
mapping.source = util.relative(sourceRoot, original.source);
|
|
} else {
|
|
mapping.source = original.source;
|
|
}
|
|
mapping.original.line = original.line;
|
|
mapping.original.column = original.column;
|
|
if (original.name !== null && mapping.name !== null) {
|
|
// Only use the identifier name if it's an identifier
|
|
// in both SourceMaps
|
|
mapping.name = original.name;
|
|
}
|
|
}
|
|
}
|
|
|
|
var source = mapping.source;
|
|
if (source && !newSources.has(source)) {
|
|
newSources.add(source);
|
|
}
|
|
|
|
var name = mapping.name;
|
|
if (name && !newNames.has(name)) {
|
|
newNames.add(name);
|
|
}
|
|
|
|
}, this);
|
|
this._sources = newSources;
|
|
this._names = newNames;
|
|
|
|
// Copy sourcesContents of applied map.
|
|
aSourceMapConsumer.sources.forEach(function (sourceFile) {
|
|
var content = aSourceMapConsumer.sourceContentFor(sourceFile);
|
|
if (content) {
|
|
if (sourceRoot) {
|
|
sourceFile = util.relative(sourceRoot, sourceFile);
|
|
}
|
|
this.setSourceContent(sourceFile, content);
|
|
}
|
|
}, this);
|
|
};
|
|
|
|
/**
|
|
* A mapping can have one of the three levels of data:
|
|
*
|
|
* 1. Just the generated position.
|
|
* 2. The Generated position, original position, and original source.
|
|
* 3. Generated and original position, original source, as well as a name
|
|
* token.
|
|
*
|
|
* To maintain consistency, we validate that any new mapping being added falls
|
|
* in to one of these categories.
|
|
*/
|
|
SourceMapGenerator.prototype._validateMapping =
|
|
function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource,
|
|
aName) {
|
|
if (aGenerated && 'line' in aGenerated && 'column' in aGenerated
|
|
&& aGenerated.line > 0 && aGenerated.column >= 0
|
|
&& !aOriginal && !aSource && !aName) {
|
|
// Case 1.
|
|
return;
|
|
}
|
|
else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated
|
|
&& aOriginal && 'line' in aOriginal && 'column' in aOriginal
|
|
&& aGenerated.line > 0 && aGenerated.column >= 0
|
|
&& aOriginal.line > 0 && aOriginal.column >= 0
|
|
&& aSource) {
|
|
// Cases 2 and 3.
|
|
return;
|
|
}
|
|
else {
|
|
throw new Error('Invalid mapping.');
|
|
}
|
|
};
|
|
|
|
function cmpLocation(loc1, loc2) {
|
|
var cmp = (loc1 && loc1.line) - (loc2 && loc2.line);
|
|
return cmp ? cmp : (loc1 && loc1.column) - (loc2 && loc2.column);
|
|
}
|
|
|
|
function strcmp(str1, str2) {
|
|
str1 = str1 || '';
|
|
str2 = str2 || '';
|
|
return (str1 > str2) - (str1 < str2);
|
|
}
|
|
|
|
function cmpMapping(mappingA, mappingB) {
|
|
return cmpLocation(mappingA.generated, mappingB.generated) ||
|
|
cmpLocation(mappingA.original, mappingB.original) ||
|
|
strcmp(mappingA.source, mappingB.source) ||
|
|
strcmp(mappingA.name, mappingB.name);
|
|
}
|
|
|
|
/**
|
|
* Serialize the accumulated mappings in to the stream of base 64 VLQs
|
|
* specified by the source map format.
|
|
*/
|
|
SourceMapGenerator.prototype._serializeMappings =
|
|
function SourceMapGenerator_serializeMappings() {
|
|
var previousGeneratedColumn = 0;
|
|
var previousGeneratedLine = 1;
|
|
var previousOriginalColumn = 0;
|
|
var previousOriginalLine = 0;
|
|
var previousName = 0;
|
|
var previousSource = 0;
|
|
var result = '';
|
|
var mapping;
|
|
|
|
// The mappings must be guarenteed to be in sorted order before we start
|
|
// serializing them or else the generated line numbers (which are defined
|
|
// via the ';' separators) will be all messed up. Note: it might be more
|
|
// performant to maintain the sorting as we insert them, rather than as we
|
|
// serialize them, but the big O is the same either way.
|
|
this._mappings.sort(cmpMapping);
|
|
|
|
for (var i = 0, len = this._mappings.length; i < len; i++) {
|
|
mapping = this._mappings[i];
|
|
|
|
if (mapping.generated.line !== previousGeneratedLine) {
|
|
previousGeneratedColumn = 0;
|
|
while (mapping.generated.line !== previousGeneratedLine) {
|
|
result += ';';
|
|
previousGeneratedLine++;
|
|
}
|
|
}
|
|
else {
|
|
if (i > 0) {
|
|
if (!cmpMapping(mapping, this._mappings[i - 1])) {
|
|
continue;
|
|
}
|
|
result += ',';
|
|
}
|
|
}
|
|
|
|
result += base64VLQ.encode(mapping.generated.column
|
|
- previousGeneratedColumn);
|
|
previousGeneratedColumn = mapping.generated.column;
|
|
|
|
if (mapping.source && mapping.original) {
|
|
result += base64VLQ.encode(this._sources.indexOf(mapping.source)
|
|
- previousSource);
|
|
previousSource = this._sources.indexOf(mapping.source);
|
|
|
|
// lines are stored 0-based in SourceMap spec version 3
|
|
result += base64VLQ.encode(mapping.original.line - 1
|
|
- previousOriginalLine);
|
|
previousOriginalLine = mapping.original.line - 1;
|
|
|
|
result += base64VLQ.encode(mapping.original.column
|
|
- previousOriginalColumn);
|
|
previousOriginalColumn = mapping.original.column;
|
|
|
|
if (mapping.name) {
|
|
result += base64VLQ.encode(this._names.indexOf(mapping.name)
|
|
- previousName);
|
|
previousName = this._names.indexOf(mapping.name);
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
/**
|
|
* Externalize the source map.
|
|
*/
|
|
SourceMapGenerator.prototype.toJSON =
|
|
function SourceMapGenerator_toJSON() {
|
|
var map = {
|
|
version: this._version,
|
|
file: this._file,
|
|
sources: this._sources.toArray(),
|
|
names: this._names.toArray(),
|
|
mappings: this._serializeMappings()
|
|
};
|
|
if (this._sourceRoot) {
|
|
map.sourceRoot = this._sourceRoot;
|
|
}
|
|
if (this._sourcesContents) {
|
|
map.sourcesContent = map.sources.map(function (source) {
|
|
if (map.sourceRoot) {
|
|
source = util.relative(map.sourceRoot, source);
|
|
}
|
|
return Object.prototype.hasOwnProperty.call(
|
|
this._sourcesContents, util.toSetString(source))
|
|
? this._sourcesContents[util.toSetString(source)]
|
|
: null;
|
|
}, this);
|
|
}
|
|
return map;
|
|
};
|
|
|
|
/**
|
|
* Render the source map being generated to a string.
|
|
*/
|
|
SourceMapGenerator.prototype.toString =
|
|
function SourceMapGenerator_toString() {
|
|
return JSON.stringify(this);
|
|
};
|
|
|
|
exports.SourceMapGenerator = SourceMapGenerator;
|
|
|
|
});
|
|
|
|
},{"./util":40,"./base64-vlq":44,"./array-set":43,"amdefine":41}],41:[function(require,module,exports){
|
|
(function(process,__filename){/** vim: et:ts=4:sw=4:sts=4
|
|
* @license amdefine 0.0.5 Copyright (c) 2011, The Dojo Foundation All Rights Reserved.
|
|
* Available via the MIT or new BSD license.
|
|
* see: http://github.com/jrburke/amdefine for details
|
|
*/
|
|
|
|
/*jslint node: true */
|
|
/*global module, process */
|
|
'use strict';
|
|
|
|
var path = require('path');
|
|
|
|
/**
|
|
* Creates a define for node.
|
|
* @param {Object} module the "module" object that is defined by Node for the
|
|
* current module.
|
|
* @param {Function} [require]. Node's require function for the current module.
|
|
* It only needs to be passed in Node versions before 0.5, when module.require
|
|
* did not exist.
|
|
* @returns {Function} a define function that is usable for the current node
|
|
* module.
|
|
*/
|
|
function amdefine(module, require) {
|
|
var defineCache = {},
|
|
loaderCache = {},
|
|
alreadyCalled = false,
|
|
makeRequire, stringRequire;
|
|
|
|
/**
|
|
* Trims the . and .. from an array of path segments.
|
|
* It will keep a leading path segment if a .. will become
|
|
* the first path segment, to help with module name lookups,
|
|
* which act like paths, but can be remapped. But the end result,
|
|
* all paths that use this function should look normalized.
|
|
* NOTE: this method MODIFIES the input array.
|
|
* @param {Array} ary the array of path segments.
|
|
*/
|
|
function trimDots(ary) {
|
|
var i, part;
|
|
for (i = 0; ary[i]; i+= 1) {
|
|
part = ary[i];
|
|
if (part === '.') {
|
|
ary.splice(i, 1);
|
|
i -= 1;
|
|
} else if (part === '..') {
|
|
if (i === 1 && (ary[2] === '..' || ary[0] === '..')) {
|
|
//End of the line. Keep at least one non-dot
|
|
//path segment at the front so it can be mapped
|
|
//correctly to disk. Otherwise, there is likely
|
|
//no path mapping for a path starting with '..'.
|
|
//This can still fail, but catches the most reasonable
|
|
//uses of ..
|
|
break;
|
|
} else if (i > 0) {
|
|
ary.splice(i - 1, 2);
|
|
i -= 2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function normalize(name, baseName) {
|
|
var baseParts;
|
|
|
|
//Adjust any relative paths.
|
|
if (name && name.charAt(0) === '.') {
|
|
//If have a base name, try to normalize against it,
|
|
//otherwise, assume it is a top-level require that will
|
|
//be relative to baseUrl in the end.
|
|
if (baseName) {
|
|
baseParts = baseName.split('/');
|
|
baseParts = baseParts.slice(0, baseParts.length - 1);
|
|
baseParts = baseParts.concat(name.split('/'));
|
|
trimDots(baseParts);
|
|
name = baseParts.join('/');
|
|
}
|
|
}
|
|
|
|
return name;
|
|
}
|
|
|
|
/**
|
|
* Create the normalize() function passed to a loader plugin's
|
|
* normalize method.
|
|
*/
|
|
function makeNormalize(relName) {
|
|
return function (name) {
|
|
return normalize(name, relName);
|
|
};
|
|
}
|
|
|
|
function makeLoad(id) {
|
|
function load(value) {
|
|
loaderCache[id] = value;
|
|
}
|
|
|
|
load.fromText = function (id, text) {
|
|
//This one is difficult because the text can/probably uses
|
|
//define, and any relative paths and requires should be relative
|
|
//to that id was it would be found on disk. But this would require
|
|
//bootstrapping a module/require fairly deeply from node core.
|
|
//Not sure how best to go about that yet.
|
|
throw new Error('amdefine does not implement load.fromText');
|
|
};
|
|
|
|
return load;
|
|
}
|
|
|
|
makeRequire = function (systemRequire, exports, module, relId) {
|
|
function amdRequire(deps, callback) {
|
|
if (typeof deps === 'string') {
|
|
//Synchronous, single module require('')
|
|
return stringRequire(systemRequire, exports, module, deps, relId);
|
|
} else {
|
|
//Array of dependencies with a callback.
|
|
|
|
//Convert the dependencies to modules.
|
|
deps = deps.map(function (depName) {
|
|
return stringRequire(systemRequire, exports, module, depName, relId);
|
|
});
|
|
|
|
//Wait for next tick to call back the require call.
|
|
process.nextTick(function () {
|
|
callback.apply(null, deps);
|
|
});
|
|
}
|
|
}
|
|
|
|
amdRequire.toUrl = function (filePath) {
|
|
if (filePath.indexOf('.') === 0) {
|
|
return normalize(filePath, path.dirname(module.filename));
|
|
} else {
|
|
return filePath;
|
|
}
|
|
};
|
|
|
|
return amdRequire;
|
|
};
|
|
|
|
//Favor explicit value, passed in if the module wants to support Node 0.4.
|
|
require = require || function req() {
|
|
return module.require.apply(module, arguments);
|
|
};
|
|
|
|
function runFactory(id, deps, factory) {
|
|
var r, e, m, result;
|
|
|
|
if (id) {
|
|
e = loaderCache[id] = {};
|
|
m = {
|
|
id: id,
|
|
uri: __filename,
|
|
exports: e
|
|
};
|
|
r = makeRequire(require, e, m, id);
|
|
} else {
|
|
//Only support one define call per file
|
|
if (alreadyCalled) {
|
|
throw new Error('amdefine with no module ID cannot be called more than once per file.');
|
|
}
|
|
alreadyCalled = true;
|
|
|
|
//Use the real variables from node
|
|
//Use module.exports for exports, since
|
|
//the exports in here is amdefine exports.
|
|
e = module.exports;
|
|
m = module;
|
|
r = makeRequire(require, e, m, module.id);
|
|
}
|
|
|
|
//If there are dependencies, they are strings, so need
|
|
//to convert them to dependency values.
|
|
if (deps) {
|
|
deps = deps.map(function (depName) {
|
|
return r(depName);
|
|
});
|
|
}
|
|
|
|
//Call the factory with the right dependencies.
|
|
if (typeof factory === 'function') {
|
|
result = factory.apply(module.exports, deps);
|
|
} else {
|
|
result = factory;
|
|
}
|
|
|
|
if (result !== undefined) {
|
|
m.exports = result;
|
|
if (id) {
|
|
loaderCache[id] = m.exports;
|
|
}
|
|
}
|
|
}
|
|
|
|
stringRequire = function (systemRequire, exports, module, id, relId) {
|
|
//Split the ID by a ! so that
|
|
var index = id.indexOf('!'),
|
|
originalId = id,
|
|
prefix, plugin;
|
|
|
|
if (index === -1) {
|
|
id = normalize(id, relId);
|
|
|
|
//Straight module lookup. If it is one of the special dependencies,
|
|
//deal with it, otherwise, delegate to node.
|
|
if (id === 'require') {
|
|
return makeRequire(systemRequire, exports, module, relId);
|
|
} else if (id === 'exports') {
|
|
return exports;
|
|
} else if (id === 'module') {
|
|
return module;
|
|
} else if (loaderCache.hasOwnProperty(id)) {
|
|
return loaderCache[id];
|
|
} else if (defineCache[id]) {
|
|
runFactory.apply(null, defineCache[id]);
|
|
return loaderCache[id];
|
|
} else {
|
|
if(systemRequire) {
|
|
return systemRequire(originalId);
|
|
} else {
|
|
throw new Error('No module with ID: ' + id);
|
|
}
|
|
}
|
|
} else {
|
|
//There is a plugin in play.
|
|
prefix = id.substring(0, index);
|
|
id = id.substring(index + 1, id.length);
|
|
|
|
plugin = stringRequire(systemRequire, exports, module, prefix, relId);
|
|
|
|
if (plugin.normalize) {
|
|
id = plugin.normalize(id, makeNormalize(relId));
|
|
} else {
|
|
//Normalize the ID normally.
|
|
id = normalize(id, relId);
|
|
}
|
|
|
|
if (loaderCache[id]) {
|
|
return loaderCache[id];
|
|
} else {
|
|
plugin.load(id, makeRequire(systemRequire, exports, module, relId), makeLoad(id), {});
|
|
|
|
return loaderCache[id];
|
|
}
|
|
}
|
|
};
|
|
|
|
//Create a define function specific to the module asking for amdefine.
|
|
function define(id, deps, factory) {
|
|
if (Array.isArray(id)) {
|
|
factory = deps;
|
|
deps = id;
|
|
id = undefined;
|
|
} else if (typeof id !== 'string') {
|
|
factory = id;
|
|
id = deps = undefined;
|
|
}
|
|
|
|
if (deps && !Array.isArray(deps)) {
|
|
factory = deps;
|
|
deps = undefined;
|
|
}
|
|
|
|
if (!deps) {
|
|
deps = ['require', 'exports', 'module'];
|
|
}
|
|
|
|
//Set up properties for this module. If an ID, then use
|
|
//internal cache. If no ID, then use the external variables
|
|
//for this node module.
|
|
if (id) {
|
|
//Put the module in deep freeze until there is a
|
|
//require call for it.
|
|
defineCache[id] = [id, deps, factory];
|
|
} else {
|
|
runFactory(id, deps, factory);
|
|
}
|
|
}
|
|
|
|
//define.require, which has access to all the values in the
|
|
//cache. Useful for AMD modules that all have IDs in the file,
|
|
//but need to finally export a value to node based on one of those
|
|
//IDs.
|
|
define.require = function (id) {
|
|
if (loaderCache[id]) {
|
|
return loaderCache[id];
|
|
}
|
|
|
|
if (defineCache[id]) {
|
|
runFactory.apply(null, defineCache[id]);
|
|
return loaderCache[id];
|
|
}
|
|
};
|
|
|
|
define.amd = {};
|
|
|
|
return define;
|
|
}
|
|
|
|
module.exports = amdefine;
|
|
|
|
})(require("__browserify_process"),"/..\\node_modules\\uglify-js\\node_modules\\source-map\\node_modules\\amdefine\\amdefine.js")
|
|
},{"path":8,"__browserify_process":7}],42:[function(require,module,exports){
|
|
/* -*- Mode: js; js-indent-level: 2; -*- */
|
|
/*
|
|
* Copyright 2011 Mozilla Foundation and contributors
|
|
* Licensed under the New BSD license. See LICENSE or:
|
|
* http://opensource.org/licenses/BSD-3-Clause
|
|
*/
|
|
if (typeof define !== 'function') {
|
|
var define = require('amdefine')(module);
|
|
}
|
|
define(function (require, exports, module) {
|
|
|
|
/**
|
|
* Recursive implementation of binary search.
|
|
*
|
|
* @param aLow Indices here and lower do not contain the needle.
|
|
* @param aHigh Indices here and higher do not contain the needle.
|
|
* @param aNeedle The element being searched for.
|
|
* @param aHaystack The non-empty array being searched.
|
|
* @param aCompare Function which takes two elements and returns -1, 0, or 1.
|
|
*/
|
|
function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare) {
|
|
// This function terminates when one of the following is true:
|
|
//
|
|
// 1. We find the exact element we are looking for.
|
|
//
|
|
// 2. We did not find the exact element, but we can return the next
|
|
// closest element that is less than that element.
|
|
//
|
|
// 3. We did not find the exact element, and there is no next-closest
|
|
// element which is less than the one we are searching for, so we
|
|
// return null.
|
|
var mid = Math.floor((aHigh - aLow) / 2) + aLow;
|
|
var cmp = aCompare(aNeedle, aHaystack[mid]);
|
|
if (cmp === 0) {
|
|
// Found the element we are looking for.
|
|
return aHaystack[mid];
|
|
}
|
|
else if (cmp > 0) {
|
|
// aHaystack[mid] is greater than our needle.
|
|
if (aHigh - mid > 1) {
|
|
// The element is in the upper half.
|
|
return recursiveSearch(mid, aHigh, aNeedle, aHaystack, aCompare);
|
|
}
|
|
// We did not find an exact match, return the next closest one
|
|
// (termination case 2).
|
|
return aHaystack[mid];
|
|
}
|
|
else {
|
|
// aHaystack[mid] is less than our needle.
|
|
if (mid - aLow > 1) {
|
|
// The element is in the lower half.
|
|
return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare);
|
|
}
|
|
// The exact needle element was not found in this haystack. Determine if
|
|
// we are in termination case (2) or (3) and return the appropriate thing.
|
|
return aLow < 0
|
|
? null
|
|
: aHaystack[aLow];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This is an implementation of binary search which will always try and return
|
|
* the next lowest value checked if there is no exact hit. This is because
|
|
* mappings between original and generated line/col pairs are single points,
|
|
* and there is an implicit region between each of them, so a miss just means
|
|
* that you aren't on the very start of a region.
|
|
*
|
|
* @param aNeedle The element you are looking for.
|
|
* @param aHaystack The array that is being searched.
|
|
* @param aCompare A function which takes the needle and an element in the
|
|
* array and returns -1, 0, or 1 depending on whether the needle is less
|
|
* than, equal to, or greater than the element, respectively.
|
|
*/
|
|
exports.search = function search(aNeedle, aHaystack, aCompare) {
|
|
return aHaystack.length > 0
|
|
? recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, aCompare)
|
|
: null;
|
|
};
|
|
|
|
});
|
|
|
|
},{"amdefine":41}],43:[function(require,module,exports){
|
|
/* -*- Mode: js; js-indent-level: 2; -*- */
|
|
/*
|
|
* Copyright 2011 Mozilla Foundation and contributors
|
|
* Licensed under the New BSD license. See LICENSE or:
|
|
* http://opensource.org/licenses/BSD-3-Clause
|
|
*/
|
|
if (typeof define !== 'function') {
|
|
var define = require('amdefine')(module);
|
|
}
|
|
define(function (require, exports, module) {
|
|
|
|
var util = require('./util');
|
|
|
|
/**
|
|
* A data structure which is a combination of an array and a set. Adding a new
|
|
* member is O(1), testing for membership is O(1), and finding the index of an
|
|
* element is O(1). Removing elements from the set is not supported. Only
|
|
* strings are supported for membership.
|
|
*/
|
|
function ArraySet() {
|
|
this._array = [];
|
|
this._set = {};
|
|
}
|
|
|
|
/**
|
|
* Static method for creating ArraySet instances from an existing array.
|
|
*/
|
|
ArraySet.fromArray = function ArraySet_fromArray(aArray) {
|
|
var set = new ArraySet();
|
|
for (var i = 0, len = aArray.length; i < len; i++) {
|
|
set.add(aArray[i]);
|
|
}
|
|
return set;
|
|
};
|
|
|
|
/**
|
|
* Add the given string to this set.
|
|
*
|
|
* @param String aStr
|
|
*/
|
|
ArraySet.prototype.add = function ArraySet_add(aStr) {
|
|
if (this.has(aStr)) {
|
|
// Already a member; nothing to do.
|
|
return;
|
|
}
|
|
var idx = this._array.length;
|
|
this._array.push(aStr);
|
|
this._set[util.toSetString(aStr)] = idx;
|
|
};
|
|
|
|
/**
|
|
* Is the given string a member of this set?
|
|
*
|
|
* @param String aStr
|
|
*/
|
|
ArraySet.prototype.has = function ArraySet_has(aStr) {
|
|
return Object.prototype.hasOwnProperty.call(this._set,
|
|
util.toSetString(aStr));
|
|
};
|
|
|
|
/**
|
|
* What is the index of the given string in the array?
|
|
*
|
|
* @param String aStr
|
|
*/
|
|
ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) {
|
|
if (this.has(aStr)) {
|
|
return this._set[util.toSetString(aStr)];
|
|
}
|
|
throw new Error('"' + aStr + '" is not in the set.');
|
|
};
|
|
|
|
/**
|
|
* What is the element at the given index?
|
|
*
|
|
* @param Number aIdx
|
|
*/
|
|
ArraySet.prototype.at = function ArraySet_at(aIdx) {
|
|
if (aIdx >= 0 && aIdx < this._array.length) {
|
|
return this._array[aIdx];
|
|
}
|
|
throw new Error('No element indexed by ' + aIdx);
|
|
};
|
|
|
|
/**
|
|
* Returns the array representation of this set (which has the proper indices
|
|
* indicated by indexOf). Note that this is a copy of the internal array used
|
|
* for storing the members so that no one can mess with internal state.
|
|
*/
|
|
ArraySet.prototype.toArray = function ArraySet_toArray() {
|
|
return this._array.slice();
|
|
};
|
|
|
|
exports.ArraySet = ArraySet;
|
|
|
|
});
|
|
|
|
},{"./util":40,"amdefine":41}],40:[function(require,module,exports){
|
|
/* -*- Mode: js; js-indent-level: 2; -*- */
|
|
/*
|
|
* Copyright 2011 Mozilla Foundation and contributors
|
|
* Licensed under the New BSD license. See LICENSE or:
|
|
* http://opensource.org/licenses/BSD-3-Clause
|
|
*/
|
|
if (typeof define !== 'function') {
|
|
var define = require('amdefine')(module);
|
|
}
|
|
define(function (require, exports, module) {
|
|
|
|
/**
|
|
* This is a helper function for getting values from parameter/options
|
|
* objects.
|
|
*
|
|
* @param args The object we are extracting values from
|
|
* @param name The name of the property we are getting.
|
|
* @param defaultValue An optional value to return if the property is missing
|
|
* from the object. If this is not specified and the property is missing, an
|
|
* error will be thrown.
|
|
*/
|
|
function getArg(aArgs, aName, aDefaultValue) {
|
|
if (aName in aArgs) {
|
|
return aArgs[aName];
|
|
} else if (arguments.length === 3) {
|
|
return aDefaultValue;
|
|
} else {
|
|
throw new Error('"' + aName + '" is a required argument.');
|
|
}
|
|
}
|
|
exports.getArg = getArg;
|
|
|
|
var urlRegexp = /([\w+\-.]+):\/\/((\w+:\w+)@)?([\w.]+)?(:(\d+))?(\S+)?/;
|
|
|
|
function urlParse(aUrl) {
|
|
var match = aUrl.match(urlRegexp);
|
|
if (!match) {
|
|
return null;
|
|
}
|
|
return {
|
|
scheme: match[1],
|
|
auth: match[3],
|
|
host: match[4],
|
|
port: match[6],
|
|
path: match[7]
|
|
};
|
|
}
|
|
exports.urlParse = urlParse;
|
|
|
|
function urlGenerate(aParsedUrl) {
|
|
var url = aParsedUrl.scheme + "://";
|
|
if (aParsedUrl.auth) {
|
|
url += aParsedUrl.auth + "@"
|
|
}
|
|
if (aParsedUrl.host) {
|
|
url += aParsedUrl.host;
|
|
}
|
|
if (aParsedUrl.port) {
|
|
url += ":" + aParsedUrl.port
|
|
}
|
|
if (aParsedUrl.path) {
|
|
url += aParsedUrl.path;
|
|
}
|
|
return url;
|
|
}
|
|
exports.urlGenerate = urlGenerate;
|
|
|
|
function join(aRoot, aPath) {
|
|
var url;
|
|
|
|
if (aPath.match(urlRegexp)) {
|
|
return aPath;
|
|
}
|
|
|
|
if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) {
|
|
url.path = aPath;
|
|
return urlGenerate(url);
|
|
}
|
|
|
|
return aRoot.replace(/\/$/, '') + '/' + aPath;
|
|
}
|
|
exports.join = join;
|
|
|
|
/**
|
|
* Because behavior goes wacky when you set `__proto__` on objects, we
|
|
* have to prefix all the strings in our set with an arbitrary character.
|
|
*
|
|
* See https://github.com/mozilla/source-map/pull/31 and
|
|
* https://github.com/mozilla/source-map/issues/30
|
|
*
|
|
* @param String aStr
|
|
*/
|
|
function toSetString(aStr) {
|
|
return '$' + aStr;
|
|
}
|
|
exports.toSetString = toSetString;
|
|
|
|
function fromSetString(aStr) {
|
|
return aStr.substr(1);
|
|
}
|
|
exports.fromSetString = fromSetString;
|
|
|
|
function relative(aRoot, aPath) {
|
|
aRoot = aRoot.replace(/\/$/, '');
|
|
|
|
var url = urlParse(aRoot);
|
|
if (aPath.charAt(0) == "/" && url && url.path == "/") {
|
|
return aPath.slice(1);
|
|
}
|
|
|
|
return aPath.indexOf(aRoot + '/') === 0
|
|
? aPath.substr(aRoot.length + 1)
|
|
: aPath;
|
|
}
|
|
exports.relative = relative;
|
|
|
|
});
|
|
|
|
},{"amdefine":41}],44:[function(require,module,exports){
|
|
/* -*- Mode: js; js-indent-level: 2; -*- */
|
|
/*
|
|
* Copyright 2011 Mozilla Foundation and contributors
|
|
* Licensed under the New BSD license. See LICENSE or:
|
|
* http://opensource.org/licenses/BSD-3-Clause
|
|
*
|
|
* Based on the Base 64 VLQ implementation in Closure Compiler:
|
|
* https://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/debugging/sourcemap/Base64VLQ.java
|
|
*
|
|
* Copyright 2011 The Closure Compiler Authors. All rights reserved.
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above
|
|
* copyright notice, this list of conditions and the following
|
|
* disclaimer in the documentation and/or other materials provided
|
|
* with the distribution.
|
|
* * Neither the name of Google Inc. nor the names of its
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
if (typeof define !== 'function') {
|
|
var define = require('amdefine')(module);
|
|
}
|
|
define(function (require, exports, module) {
|
|
|
|
var base64 = require('./base64');
|
|
|
|
// A single base 64 digit can contain 6 bits of data. For the base 64 variable
|
|
// length quantities we use in the source map spec, the first bit is the sign,
|
|
// the next four bits are the actual value, and the 6th bit is the
|
|
// continuation bit. The continuation bit tells us whether there are more
|
|
// digits in this value following this digit.
|
|
//
|
|
// Continuation
|
|
// | Sign
|
|
// | |
|
|
// V V
|
|
// 101011
|
|
|
|
var VLQ_BASE_SHIFT = 5;
|
|
|
|
// binary: 100000
|
|
var VLQ_BASE = 1 << VLQ_BASE_SHIFT;
|
|
|
|
// binary: 011111
|
|
var VLQ_BASE_MASK = VLQ_BASE - 1;
|
|
|
|
// binary: 100000
|
|
var VLQ_CONTINUATION_BIT = VLQ_BASE;
|
|
|
|
/**
|
|
* Converts from a two-complement value to a value where the sign bit is
|
|
* is placed in the least significant bit. For example, as decimals:
|
|
* 1 becomes 2 (10 binary), -1 becomes 3 (11 binary)
|
|
* 2 becomes 4 (100 binary), -2 becomes 5 (101 binary)
|
|
*/
|
|
function toVLQSigned(aValue) {
|
|
return aValue < 0
|
|
? ((-aValue) << 1) + 1
|
|
: (aValue << 1) + 0;
|
|
}
|
|
|
|
/**
|
|
* Converts to a two-complement value from a value where the sign bit is
|
|
* is placed in the least significant bit. For example, as decimals:
|
|
* 2 (10 binary) becomes 1, 3 (11 binary) becomes -1
|
|
* 4 (100 binary) becomes 2, 5 (101 binary) becomes -2
|
|
*/
|
|
function fromVLQSigned(aValue) {
|
|
var isNegative = (aValue & 1) === 1;
|
|
var shifted = aValue >> 1;
|
|
return isNegative
|
|
? -shifted
|
|
: shifted;
|
|
}
|
|
|
|
/**
|
|
* Returns the base 64 VLQ encoded value.
|
|
*/
|
|
exports.encode = function base64VLQ_encode(aValue) {
|
|
var encoded = "";
|
|
var digit;
|
|
|
|
var vlq = toVLQSigned(aValue);
|
|
|
|
do {
|
|
digit = vlq & VLQ_BASE_MASK;
|
|
vlq >>>= VLQ_BASE_SHIFT;
|
|
if (vlq > 0) {
|
|
// There are still more digits in this value, so we must make sure the
|
|
// continuation bit is marked.
|
|
digit |= VLQ_CONTINUATION_BIT;
|
|
}
|
|
encoded += base64.encode(digit);
|
|
} while (vlq > 0);
|
|
|
|
return encoded;
|
|
};
|
|
|
|
/**
|
|
* Decodes the next base 64 VLQ value from the given string and returns the
|
|
* value and the rest of the string.
|
|
*/
|
|
exports.decode = function base64VLQ_decode(aStr) {
|
|
var i = 0;
|
|
var strLen = aStr.length;
|
|
var result = 0;
|
|
var shift = 0;
|
|
var continuation, digit;
|
|
|
|
do {
|
|
if (i >= strLen) {
|
|
throw new Error("Expected more digits in base 64 VLQ value.");
|
|
}
|
|
digit = base64.decode(aStr.charAt(i++));
|
|
continuation = !!(digit & VLQ_CONTINUATION_BIT);
|
|
digit &= VLQ_BASE_MASK;
|
|
result = result + (digit << shift);
|
|
shift += VLQ_BASE_SHIFT;
|
|
} while (continuation);
|
|
|
|
return {
|
|
value: fromVLQSigned(result),
|
|
rest: aStr.slice(i)
|
|
};
|
|
};
|
|
|
|
});
|
|
|
|
},{"./base64":45,"amdefine":41}],45:[function(require,module,exports){
|
|
/* -*- Mode: js; js-indent-level: 2; -*- */
|
|
/*
|
|
* Copyright 2011 Mozilla Foundation and contributors
|
|
* Licensed under the New BSD license. See LICENSE or:
|
|
* http://opensource.org/licenses/BSD-3-Clause
|
|
*/
|
|
if (typeof define !== 'function') {
|
|
var define = require('amdefine')(module);
|
|
}
|
|
define(function (require, exports, module) {
|
|
|
|
var charToIntMap = {};
|
|
var intToCharMap = {};
|
|
|
|
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
|
.split('')
|
|
.forEach(function (ch, index) {
|
|
charToIntMap[ch] = index;
|
|
intToCharMap[index] = ch;
|
|
});
|
|
|
|
/**
|
|
* Encode an integer in the range of 0 to 63 to a single base 64 digit.
|
|
*/
|
|
exports.encode = function base64_encode(aNumber) {
|
|
if (aNumber in intToCharMap) {
|
|
return intToCharMap[aNumber];
|
|
}
|
|
throw new TypeError("Must be between 0 and 63: " + aNumber);
|
|
};
|
|
|
|
/**
|
|
* Decode a single base 64 digit to an integer.
|
|
*/
|
|
exports.decode = function base64_decode(aChar) {
|
|
if (aChar in charToIntMap) {
|
|
return charToIntMap[aChar];
|
|
}
|
|
throw new TypeError("Not a valid base 64 digit: " + aChar);
|
|
};
|
|
|
|
});
|
|
|
|
},{"amdefine":41}]},{},[9])(9)
|
|
});
|
|
; |