diff --git a/core.js b/core.js index 4d32632..4eee85c 100644 --- a/core.js +++ b/core.js @@ -2,9 +2,13 @@ var utils = require('./utils'), scope = require('./scope'), _global = require('./core/global'), _array = require('./core/array'), + _console = require('./core/console'), _date = require('./core/date'), _function = require('./core/function'), _json = require('./core/json'), + _object = require('./core/object'), + _promise = require('./core/promise'), + _regexp = require('./core/regexp'), _string = require('./core/string'), _math = require('./core/math'), _number = require('./core/number'); @@ -13,13 +17,67 @@ module.exports = { evaluate: function(node) { var handler = undefined; + var get = function(obj, name) { + if (obj.hasOwnProperty(name)) { return obj[name]; } + return undefined; + }; - if (node.property) { - var method = node.property.name; - handler = _array[method] || _date[method] || _function[method] || _json[method] || _string[method] || _math[method] || _number[method]; + if (utils.isType(node.object, 'MemberExpression')) { + var newNode = module.exports.evaluate(node.object); + if (newNode !== node.object) { + node.object = newNode; + newNode.parent = node; + } + } + + // Handle Array.prototype.slice.call(...) + if (utils.isId(node.property, 'call') && + utils.isType(node.object, 'MemberExpression') && + utils.isType(node.object.object, 'MemberExpression') && + utils.isId(node.object.object.object, /^(Array)$/) && + utils.isId(node.object.object.property, 'prototype')) { + var type = node.object.object.object.name; + var method = node.object.property.name; + var longName = type + '#' + method; + handler = get(_array, longName); + if (handler) { + // move the 1st argument to be the reciever + var args = utils.clone(node.parent.arguments); + var thisArg = args.shift(); + node = { + type: 'CallExpression', + callee: { + type: 'MemberExpression', + object: thisArg, + property: node.object.property, + isCallee: true, + }, + arguments: args, + parent: node.parent, + }; + node.parent.arguments = false; + } + } + if (utils.isType(node.object, 'Literal')) { + var method = node.property.name; + if (!(utils.isType(node.parent, 'CallExpression') && node === node.parent.callee)) { + method = '.' + method; + } + handler = node.object.regex ? get(_regexp, method) : get(_string, method); + } else if (utils.isId(node.object, /^(Array|Date|JSON|Math|Object|Promise|console)$/)) { + var longName = node.object.name + '.' + node.property.name; + handler = get(_array, longName) || get(_date, longName) || get(_json, longName) || get(_math, longName) || get(_object, longName) || get(_promise, longName) || get(_console, longName); + } else if (utils.isType(node.property, 'Identifier')) { + var method = node.property.name; + if (!(utils.isType(node.parent, 'CallExpression') && node === node.parent.callee)) { + method = '.' + method; + } + // _array should be before _string here so we pick up the correct + // multitype version of #length and #indexOf + handler = get(_array, method) || get(_date, method) || get(_function, method) || get(_json, method) || get(_regexp, method) || get(_string, method) || get(_math, method) || get(_number, method); } else if (node.callee) { - handler = _global[node.callee.name]; + handler = get(_global, node.callee.name); } if (handler) { diff --git a/core/array.js b/core/array.js index e87a9b7..bf132b2 100644 --- a/core/array.js +++ b/core/array.js @@ -3,10 +3,25 @@ var utils = require('../utils'), string = require('./string'); module.exports = { + 'Array.isArray': function(node) { + var args = utils.clone(node.parent.arguments); + node.parent.arguments = false; + return { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'is_array', + }, + arguments: args, + }; + }, unshift: function(node) { var args = utils.clone(node.parent.arguments); node.parent.arguments = false; + if (args.length === 1) { args[0].suppressParens = true; } + args.unshift(node.parent.callee.object); + scope.get(node).getDefinition(node.parent.callee.object); return { type: 'CallExpression', @@ -14,12 +29,13 @@ module.exports = { type: 'Identifier', name: 'array_unshift', }, - arguments: [node.parent.callee.object, args[0]] + arguments: args, }; }, shift: function(node) { node.parent.arguments = false; + scope.get(node).getDefinition(node.parent.callee.object); return { type: 'CallExpression', callee: { @@ -31,6 +47,8 @@ module.exports = { }, reverse: function(node) { + node.parent.arguments = false; + scope.get(node).getDefinition(node.parent.callee.object); return { type: 'CallExpression', callee: { @@ -44,6 +62,9 @@ module.exports = { push: function(node) { var args = utils.clone(node.parent.arguments); node.parent.arguments = false; + scope.get(node).getDefinition(node.parent.callee.object); + if (args.length === 1) { args[0].suppressParens = true; } + args.unshift(node.parent.callee.object); return { type: 'CallExpression', @@ -51,11 +72,13 @@ module.exports = { type: 'Identifier', name: 'array_push', }, - arguments: [ node.parent.callee.object, args[0] ] + arguments: args, }; }, pop: function(node) { + node.parent.arguments = false; + scope.get(node).getDefinition(node.parent.callee.object); return { type: 'CallExpression', callee: { @@ -69,22 +92,89 @@ module.exports = { join: function(node) { var args = utils.clone(node.parent.arguments); node.parent.arguments = false; + scope.get(node).getDefinition(node.parent.callee.object); + args[0].suppressParens = true; return { type: 'CallExpression', callee: { type: 'Identifier', - name: 'join', + name: 'implode', }, arguments: [ args[0], node.parent.callee.object ] }; }, - splice: function(node) { + map: function(node) { var args = utils.clone(node.parent.arguments); + node.parent.arguments = false; + scope.get(node).getDefinition(node.parent.callee.object); + args[0].suppressParens = true; + + return { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'array_map', + }, + arguments: [ node.parent.callee.object, args[0] ] + }; + }, + + reduce: function(node) { + var args = utils.clone(node.parent.arguments); + node.parent.arguments = false; + scope.get(node).getDefinition(node.parent.callee.object); + if (args.length === 1) { + args[0].suppressParens = true; + } args.unshift(node.parent.callee.object); + return { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'array_reduce', + }, + arguments: args, + }; + }, + + slice: function(node) { + var args = utils.clone(node.parent.arguments); + if (node.parent.arguments.length > 1) { + // Second argument to array_slice is very different from Array#slice + // unless it is negative. + if (args[1].type === 'UnaryExpression' && args[1].operator==='-' && + args[1].argument.type==='Literal') { + /* this is okay */ + } else { + args[1].trailingComments = [{ type: 'Block', value: 'CHECK THIS'}]; + } + } else if (node.parent.arguments.length === 0) { + args.unshift({ type: 'Literal', value: 0, raw: '0' }); + } else { + args[0].suppressParens = true; + } + args.unshift(node.parent.callee.object); + node.parent.arguments = false; + scope.get(node).getDefinition(node.parent.callee.object); + + return { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'array_slice', + }, + arguments: args + }; + }, + + splice: function(node) { + var args = utils.clone(node.parent.arguments); + args.unshift(node.parent.callee.object); node.parent.arguments = false; + scope.get(node).getDefinition(node.parent.callee.object); return { type: 'CallExpression', @@ -101,6 +191,8 @@ module.exports = { args = utils.clone(node.parent.arguments); node.parent.arguments = false; + scope.get(node).getDefinition(node.parent.callee.object); + args[0].suppressParens = true; var targetDefinition = scope.get(node).getDefinition(node.parent.callee.object); if (utils.isString(node.parent.callee.object) || (targetDefinition && targetDefinition.dataType == "String")) { @@ -122,7 +214,7 @@ module.exports = { }, - length: function(node) { + '.length': function(node) { var method, object = (node.parent.callee && node.parent.callee.object) || node.object, isString = utils.isString(object); @@ -130,7 +222,7 @@ module.exports = { var targetDefinition = scope.get(node).getDefinition(object); if (!isString && targetDefinition) { - if (targetDefinition.type == "Identifier" && targetDefinition.name == "string") { + if (utils.isId(targetDefinition, "string")) { isString = true; } else if (targetDefinition.dataType == "String") { isString = true; @@ -155,4 +247,6 @@ module.exports = { }; }, -} +}; + +utils.coreAddHash(module.exports, 'Array'); diff --git a/core/console.js b/core/console.js new file mode 100644 index 0000000..d4b1783 --- /dev/null +++ b/core/console.js @@ -0,0 +1,19 @@ +var utils = require('../utils'); + +module.exports = { + 'console.assert': function(node) { + return { + type: 'MemberExpression', + object: { + type: 'Identifier', + name: 'Assert', + }, + property: { + type: 'Identifier', + name: 'invariant', + } + }; + } +}; + +utils.coreAddHash(module.exports, 'console'); diff --git a/core/date.js b/core/date.js index f17ecf6..464365c 100644 --- a/core/date.js +++ b/core/date.js @@ -1,27 +1,21 @@ var utils = require('../utils'); -function isDateClass(node) { - return node.object.name == "Date"; -} - module.exports = { - now: function(node) { - if (isDateClass(node)) { - var args = utils.clone(node.parent.arguments); - node.parent.arguments = false; + 'Date.now': function(node) { + var args = utils.clone(node.parent.arguments); + node.parent.arguments = false; - return { - type: 'CallExpression', - callee: { - type: 'Identifier', - name: 'time', - }, - arguments: [] - }; - } else { - return node; - } + return { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'time', + }, + arguments: [] + }; } -} +}; + +utils.coreAddHash(module.exports, 'Date'); diff --git a/core/function.js b/core/function.js index fb0b214..3111631 100644 --- a/core/function.js +++ b/core/function.js @@ -1,3 +1,5 @@ +var utils = require('../utils'); + function apply(node, isCall) { var method, arguments = []; @@ -25,10 +27,14 @@ function apply(node, isCall) { } else { // .apply use call_user_func_array method = "call_user_func_array"; - arguments.push({ - type: "ArrayExpression", - elements: (node.parent.arguments[0] || {elements:[]}).elements - }); + if (node.parent.arguments[0]) { + arguments.push(node.parent.arguments[0]); + } else { + arguments.push({ + type: "ArrayExpression", + elements: [], + }); + } } node.parent.arguments = false; @@ -53,4 +59,6 @@ module.exports = { return apply(node, false) }, -} +}; + +utils.coreAddHash(module.exports, 'Function'); diff --git a/core/global.js b/core/global.js index 515011e..0cdeac0 100644 --- a/core/global.js +++ b/core/global.js @@ -14,4 +14,4 @@ module.exports = { return newNode; } -} +}; diff --git a/core/json.js b/core/json.js index 56f7a79..240f609 100644 --- a/core/json.js +++ b/core/json.js @@ -6,41 +6,35 @@ function isJSONClass(node) { module.exports = { - stringify: function(node) { - if (isJSONClass(node)) { - var args = utils.clone(node.parent.arguments); - node.parent.arguments = false; - - return { - type: 'CallExpression', - callee: { - type: 'Identifier', - name: 'json_encode', - }, - arguments: args - }; - } else { - return node; - } + 'JSON.stringify': function(node) { + var args = utils.clone(node.parent.arguments); + node.parent.arguments = false; + + return { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'json_encode', + }, + arguments: args + }; }, - parse: function(node) { - if (isJSONClass(node)) { - var args = utils.clone(node.parent.arguments); - node.parent.arguments = false; - - return { - type: 'CallExpression', - callee: { - type: 'Identifier', - name: 'json_decode', - }, - arguments: args, - forceSkip: true - }; - } else { - return node; - } - } + 'JSON.parse': function(node) { + var args = utils.clone(node.parent.arguments); + node.parent.arguments = false; -} + return { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'json_decode', + }, + arguments: args, + forceSkip: true + }; + }, + +}; + +utils.coreAddHash(module.exports, 'JSON'); diff --git a/core/math.js b/core/math.js index cefe08b..7d88829 100644 --- a/core/math.js +++ b/core/math.js @@ -13,7 +13,7 @@ function constant(node, name) { } function method(node, name) { - if (isMathClass(node)) { + if (isMathClass(node) && node.parent.type === 'CallExpression') { var args = utils.clone(node.parent.arguments); node.parent.arguments = false; return { type: 'CallExpression', callee: { type: 'Identifier', name: name, }, arguments: args }; @@ -25,51 +25,53 @@ function method(node, name) { module.exports = { // constants - E: function(node) { return constant(node, 'M_E'); }, - LN2: function(node) { return constant(node, 'M_LN2'); }, - LN10: function(node) { return constant(node, 'M_LN10'); }, - LOG2E: function(node) { return constant(node, 'M_LOG2E'); }, - LOG10E: function(node) { return constant(node, 'M_LOG10E'); }, - PI: function(node) { return constant(node, 'M_PI'); }, - SQRT2: function(node) { return constant(node, 'M_SQRT2'); }, - SQRT1_2: function(node) { return constant(node, 'M_SQRT1_2'); }, + 'Math.E': function(node) { return constant(node, 'M_E'); }, + 'Math.LN2': function(node) { return constant(node, 'M_LN2'); }, + 'Math.LN10': function(node) { return constant(node, 'M_LN10'); }, + 'Math.LOG2E': function(node) { return constant(node, 'M_LOG2E'); }, + 'Math.LOG10E': function(node) { return constant(node, 'M_LOG10E'); }, + 'Math.PI': function(node) { return constant(node, 'M_PI'); }, + 'Math.SQRT2': function(node) { return constant(node, 'M_SQRT2'); }, + 'Math.SQRT1_2': function(node) { return constant(node, 'M_SQRT1_2'); }, // methods - abs: function(node) { return method(node, 'abs'); }, - acos: function(node) { return method(node, 'acos'); }, - acosh: function(node) { return method(node, 'acosh'); }, - asin: function(node) { return method(node, 'asin'); }, - asinh: function(node) { return method(node, 'asinh'); }, - atan: function(node) { return method(node, 'atan'); }, - atanh: function(node) { return method(node, 'atanh'); }, - atan2: function(node) { return method(node, 'atan2'); }, - cbrt: function(node) { return method(node, 'cbrt'); }, - ceil: function(node) { return method(node, 'ceil'); }, - clz32: function(node) { return method(node, 'clz32'); }, - cos: function(node) { return method(node, 'cos'); }, - cosh: function(node) { return method(node, 'cosh'); }, - exp: function(node) { return method(node, 'exp'); }, - expm1: function(node) { return method(node, 'expm1'); }, - floor: function(node) { return method(node, 'floor'); }, + 'Math.abs': function(node) { return method(node, 'abs'); }, + 'Math.acos': function(node) { return method(node, 'acos'); }, + 'Math.acosh': function(node) { return method(node, 'acosh'); }, + 'Math.asin': function(node) { return method(node, 'asin'); }, + 'Math.asinh': function(node) { return method(node, 'asinh'); }, + 'Math.atan': function(node) { return method(node, 'atan'); }, + 'Math.atanh': function(node) { return method(node, 'atanh'); }, + 'Math.atan2': function(node) { return method(node, 'atan2'); }, + 'Math.cbrt': function(node) { return method(node, 'cbrt'); }, + 'Math.ceil': function(node) { return method(node, 'ceil'); }, + 'Math.clz32': function(node) { return method(node, 'clz32'); }, + 'Math.cos': function(node) { return method(node, 'cos'); }, + 'Math.cosh': function(node) { return method(node, 'cosh'); }, + 'Math.exp': function(node) { return method(node, 'exp'); }, + 'Math.expm1': function(node) { return method(node, 'expm1'); }, + 'Math.floor': function(node) { return method(node, 'floor'); }, // fround: function(node) { return method(node, 'fround'); }, - hypot: function(node) { return method(node, 'hypot'); }, + 'Math.hypot': function(node) { return method(node, 'hypot'); }, // imul: function(node) { return method(node, 'imul'); }, - log: function(node) { return method(node, 'log'); }, - log1p: function(node) { return method(node, 'log1p'); }, - log10: function(node) { return method(node, 'log10'); }, + 'Math.log': function(node) { return method(node, 'log'); }, + 'Math.log1p': function(node) { return method(node, 'log1p'); }, + 'Math.log10': function(node) { return method(node, 'log10'); }, // log2: function(node) { return method(node, 'log2'); }, - max: function(node) { return method(node, 'max'); }, - min: function(node) { return method(node, 'min'); }, - pow: function(node) { return method(node, 'pow'); }, - random: function(node) { return method(node, 'rand'); }, - round: function(node) { return method(node, 'round'); }, + 'Math.max': function(node) { return method(node, 'max'); }, + 'Math.min': function(node) { return method(node, 'min'); }, + 'Math.pow': function(node) { return method(node, 'pow'); }, + 'Math.random': function(node) { return method(node, 'rand'); }, + 'Math.round': function(node) { return method(node, 'round'); }, // sign: function(node) { return method(node, 'sign'); }, - sin: function(node) { return method(node, 'sin'); }, - sinh: function(node) { return method(node, 'sinh'); }, - sqrt: function(node) { return method(node, 'sqrt'); }, - tan: function(node) { return method(node, 'tan'); }, - tanh: function(node) { return method(node, 'tanh'); }, + 'Math.sin': function(node) { return method(node, 'sin'); }, + 'Math.sinh': function(node) { return method(node, 'sinh'); }, + 'Math.sqrt': function(node) { return method(node, 'sqrt'); }, + 'Math.tan': function(node) { return method(node, 'tan'); }, + 'Math.tanh': function(node) { return method(node, 'tanh'); }, // trunc: function(node) { return method(node, 'trunc'); }, -} +}; + +utils.coreAddHash(module.exports, 'Math'); diff --git a/core/number.js b/core/number.js index d4662a5..5039a9a 100644 --- a/core/number.js +++ b/core/number.js @@ -27,4 +27,6 @@ module.exports = { isInteger: function(node) { return method(node, 'is_int'); }, isFinite: function(node) { return method(node, 'is_finite'); }, -} \ No newline at end of file +}; + +utils.coreAddHash(module.exports, 'Number'); diff --git a/core/object.js b/core/object.js new file mode 100644 index 0000000..03d468e --- /dev/null +++ b/core/object.js @@ -0,0 +1,17 @@ +var utils = require('../utils'); + +module.exports = { + 'Object.create': function(node) { + var args = utils.clone(node.parent.arguments); + if (args.length === 1 && args[0].type === 'Literal' && args[0].value === null) { + node.parent.arguments = false; + return { + type: 'ObjectExpression', + properties: [], + }; + }; + return node; + } +}; + +utils.coreAddHash(module.exports, 'Object'); diff --git a/core/promise.js b/core/promise.js new file mode 100644 index 0000000..0ca139f --- /dev/null +++ b/core/promise.js @@ -0,0 +1,17 @@ +var utils = require('../utils'); + +module.exports = { + 'Promise.async': function(node) { + var args = utils.clone(node.parent.arguments); + if (args.length === 1) { + node.parent.arguments = false; + args[0].suppressParens = true; + args[0].leadingComments = args[0].leadingComments || []; + args[0].leadingComments.push({ type: 'Block', value: ' async ' }); + return args[0]; + }; + return node; + } +}; + +utils.coreAddHash(module.exports, 'Promise'); diff --git a/core/regexp.js b/core/regexp.js new file mode 100644 index 0000000..c87e9b1 --- /dev/null +++ b/core/regexp.js @@ -0,0 +1,85 @@ +var utils = require('../utils'), + scope = require('../scope'); + +module.exports = { + exec: function(node) { + var args = utils.clone(node.parent.arguments); + if (utils.isType(node.parent.callee.object, "Literal") && + node.parent.callee.object.regex) { + node.parent.arguments = false; + args[0].suppressParens = true; + var regexpData = node.parent.callee.object.raw + .match(/^\/((?:[^\/]|\\.)+)\/([gimy]+)?$/); + var pattern = (regexpData && regexpData[1]); + var flags = (regexpData && regexpData[2]) || ""; + var isGroup = flags.indexOf('g') >= 0; + var lit = node.parent.callee.object; + if (isGroup) { flags = flags.replace(/g/g, ''); } + lit.value = '/' + pattern + '/' + flags; + lit.raw = utils.stringify(lit.value); + lit.regex = undefined; + return { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: isGroup ? 'preg_match_all' : 'preg_match', + }, + arguments: [ node.parent.callee.object, args[0], { + type: 'Identifier', + name: 'FIXME', + }], + leadingComments: [{ type: 'Block', value: 'RegExp#exec' }], + }; + } else { + return node; + } + }, + + '.source': function(node) { + if (utils.isType(node.object, "Literal") && node.object.regex) { + node.object.value = node.object.regex.pattern; + node.object.raw = utils.stringify(node.object.value); + node.object.regex = undefined; + return node.object; + } else { + return node; + } + }, + + test: function(node) { + var args = utils.clone(node.parent.arguments); + node.parent.arguments = false; + scope.get(node).getDefinition(node.parent.callee.object); + args[0].suppressParens = true; + if (utils.isType(node.parent.callee.object, "Literal") && + node.parent.callee.object.regex) { + var lit = node.parent.callee.object; + if (lit.value.source) { + lit.value = '/' + lit.value.source + '/'; + } else { + lit.value = lit.raw; + } + lit.raw = utils.stringify(lit.value); + lit.regex = undefined; + return { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'preg_match', + }, + arguments: [ node.parent.callee.object, args[0] ], + }; + } else { + return { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'preg_match', + }, + arguments: [ node.parent.callee.object, args[0] ], + }; + } + }, +}; + +utils.coreAddHash(module.exports, 'RegExp'); diff --git a/core/string.js b/core/string.js index 26c0bea..34f8fa5 100644 --- a/core/string.js +++ b/core/string.js @@ -1,20 +1,49 @@ -var utils = require('../utils'); +var utils = require('../utils'), + scope = require('../scope'); module.exports = { // // string methods // + indexOf: function(node) { + var args = utils.clone(node.parent.arguments); + node.parent.arguments = false; + scope.get(node).getDefinition(node.parent.callee.object); + if (args.length === 1) { args[0].suppressParens = true; } + args.unshift(node.parent.callee.object); + + return { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'strpos', + }, + arguments: args + }; + }, + + '.length': function(node) { + var object = (node.parent.callee && node.parent.callee.object) || node.object; + return { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'strlen', + }, + arguments: [object], + }; + }, replace: function(node) { var method = "str_replace"; var args = utils.clone(node.parent.arguments); args.push(node.parent.callee.object) - node.parent.arguments = false; + scope.get(node).getDefinition(node.parent.callee.object); - if(args[0].type !== 'Identifier'){ - var regexpData = args[0].raw.match(/^\/([^\/]+)\/([gimy])?$/), + if(args[0].type === 'Literal'){ + var regexpData = args[0].raw.match(/^\/((?:[^\/]|\\.)+)\/([gimy]+)?$/), regex = regexpData && regexpData[1], flags = regexpData && regexpData[2] || "", isGroup = flags.indexOf('g') >= 0; @@ -22,8 +51,10 @@ module.exports = { // check for RegExp for preg_replace if (regexpData) { method = "preg_replace"; - args[0].raw = "'/" + regex + "/" + flags.replace("g", "") + "'"; + args[0].value = "/" + regex + "/" + flags.replace("g", ""); + args[0].raw = utils.stringify(args[0].value); args[0].type = "Literal"; + args[0].regex = false; // fill '$limit' param with only 1 replacement // http://php.net/manual/en/function.preg-replace.php @@ -43,8 +74,81 @@ module.exports = { }; }, + slice: function(node) { + var args = utils.clone(node.parent.arguments); + if (node.parent.arguments.length > 1) { + // Second argument to substr is very different from String#slice + // unless it is negative. + if (args[1].type === 'UnaryExpression' && args[1].operator==='-' && + args[1].argument.type==='Literal') { + /* this is okay */ + } else { + args[1].trailingComments = [{ type: 'Block', value: 'CHECK THIS'}]; + } + } else { + args[0].suppressParens = true; + } + args.unshift(node.parent.callee.object); + node.parent.arguments = false; + scope.get(node).getDefinition(node.parent.callee.object); + + return { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'substr', + }, + arguments: args + }; + }, + + substr: function(node) { + // This method is deprecated/discouraged in JS, but maps best to the PHP + // function. + var args = utils.clone(node.parent.arguments); + if (node.parent.arguments.length === 1) { + args[0].suppressParens = true; + } + args.unshift(node.parent.callee.object); + node.parent.arguments = false; + scope.get(node).getDefinition(node.parent.callee.object); + + return { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'substr', + }, + arguments: args + }; + }, + + substring: function(node) { + var args = utils.clone(node.parent.arguments); + if (node.parent.arguments.length > 1) { + // Second argument to substr is very different from String#substring + // (And String#substring is almost-but-not-quite-like String#slice) + args[1].trailingComments = [{ type: 'Block', value: 'CHECK THIS'}]; + } else { + args[0].suppressParens = true; + } + args.unshift(node.parent.callee.object); + node.parent.arguments = false; + scope.get(node).getDefinition(node.parent.callee.object); + + return { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'substr', + }, + arguments: args + }; + }, + trim: function(node) { node.parent.arguments = false; + scope.get(node).getDefinition(node.parent.callee.object); return { type: 'CallExpression', @@ -58,6 +162,7 @@ module.exports = { trimRight: function(node) { node.parent.arguments = false; + scope.get(node).getDefinition(node.parent.callee.object); return { type: 'CallExpression', @@ -71,6 +176,7 @@ module.exports = { trimLeft: function(node) { node.parent.arguments = false; + scope.get(node).getDefinition(node.parent.callee.object); return { type: 'CallExpression', @@ -84,6 +190,7 @@ module.exports = { toUpperCase: function(node) { node.parent.arguments = false; + scope.get(node).getDefinition(node.parent.callee.object); return { type: 'CallExpression', @@ -97,6 +204,7 @@ module.exports = { toLowerCase: function(node) { node.parent.arguments = false; + scope.get(node).getDefinition(node.parent.callee.object); return { type: 'CallExpression', @@ -112,23 +220,31 @@ module.exports = { var method = "explode"; var args = utils.clone(node.parent.arguments); args.push(node.parent.callee.object); - node.parent.arguments = false; + scope.get(node).getDefinition(node.parent.callee.object); - var regexpData = args[0].raw.match(/^\/([^\/]+)\/([gimy])?$/), + var regexpData = args[0].type==='Literal' && + args[0].raw.match(/^\/((?:[^\/]|\\.)+)\/([gimy]+)?$/), regex = regexpData && regexpData[1], flags = regexpData && regexpData[2] || ""; // check for RegExp for preg_replace if (regexpData) { method = "preg_split"; - args[0].raw = "'/" + regex + "/" + flags.replace("g", "") + "'"; + args[0].value = "/" + regex + "/" + flags.replace("g", ""); + args[0].raw = utils.stringify(args[0].value); args[0].type = "Literal"; + args[0].regex = false; + if (args.length === 2) { + args[0].suppressParens = true; + } } // If splitting with a blank delimiter, use str_split. else if (args[0].value === '') { method = "str_split"; args = [args[1]]; + } else if (args.length == 2) { + args[0].suppressParens = true; } return { @@ -143,9 +259,10 @@ module.exports = { substr: function(node) { var args = utils.clone(node.parent.arguments); - args.unshift(node.parent.callee.object); - node.parent.arguments = false; + scope.get(node).getDefinition(node.parent.callee.object); + if (args.length === 1) { args[0].suppressParens = true; } + args.unshift(node.parent.callee.object); return { type: 'CallExpression', @@ -159,25 +276,38 @@ module.exports = { match: function(node) { var args = utils.clone(node.parent.arguments); + args[0].suppressParens = true; args.push(node.parent.callee.object); if(args[0].type === 'Literal') { - var regexpData = args[0].raw.match(/^\/([^\/]+)\/([gimy])?$/), - regex = regexpData && regexpData[1], + var regexpData = args[0].regex && + args[0].raw.match(/^\/((?:[^\/]|\\.)+)\/([gimy]+)?$/), + pattern = regexpData && regexpData[1], flags = regexpData && regexpData[2] || "", isGroup = flags.indexOf('g') >= 0; + // String#match can be called with a raw string as well. + if ((!args[0].regex) && typeof args[0].value === 'string') { + var r = new RegExp(args[0].value); + pattern = r.source; + flags = ''; + isGroup = false; + } // remove unsupported /g from regexp, to use preg_match_all - if (isGroup) { flags = flags.replace("g", ""); } - regex = "/" + regex + "/" + flags; - - args[0].raw = "'" + regex + "'"; + if (isGroup) { flags = flags.replace(/g/g, ''); } + args[0].value = '/' + pattern + '/' + flags; + args[0].raw = utils.stringify(args[0].value); args[0].type = "Literal"; - + args[0].regex = undefined; } node.parent.arguments = false; + scope.get(node).getDefinition(node.parent.callee.object); + if (isGroup) { + // results come back in this out-argument + args.push({ type: 'Identifier', name: 'FIXME' }); + } return { type: 'CallExpression', @@ -190,4 +320,6 @@ module.exports = { }, -} +}; + +utils.coreAddHash(module.exports, 'String'); diff --git a/index.js b/index.js index 05e73ce..ca8728f 100644 --- a/index.js +++ b/index.js @@ -3,12 +3,58 @@ var core = require('./core'), utils = require('./utils'), espree = require('espree'); -module.exports = function(code) { +module.exports = function(code, options) { + options = options || {}; + if (options.braced) { + // special option to handle code inside braced regions only + var nest = 0, quote = null, outside = '', inside = ''; + var noptions = Object.assign({}, options, { + braced: false, watermark: false, noOpenTag: true, indent: 1, + }); + if (options.watermark) { outside += `/* ${options.watermark} */\n`; } + code.split( + // /([{}]|\/\*(?:(?!\*\/).)*\*\/|\/\/[^\n]*(?:\n|$)|"[^"]*"|'[^']'|\[[^\]]*\])/mg + /([{}'"\[\]]|\/\*|\*\/|\/\/|\n)/g + ).forEach(function(chunk) { + var isStartQuote = (nest === 0) && + (chunk==='"' || chunk==="'" || chunk==='[' || chunk==='/*' || chunk==='//'); + if (quote || isStartQuote) { + var trailingBackslash = outside.endsWith('\\'); + outside += chunk; + if (chunk === quote && !trailingBackslash) { quote = null; } + else if (!quote) { + switch (chunk) { + case '/*' : quote = '*/'; break; + case '//': quote = '\n'; break; + case '[': quote = ']'; break; + default: quote = chunk; break; + } + } + return; + } + if (chunk==='}') { nest--; } + if (nest <= 0) { + if (inside) { + outside += module.exports(inside, noptions); + inside = ''; + } + outside += chunk; + nest = 0; + } else { + inside += chunk; + } + if (chunk==='{') { nest++; } + }); + if (inside) { outside += module.exports(inside, noptions); } + return outside; + } + var useConciseArrays = (options.conciseArrays === false) ? false : true; var ast = espree.parse(code, { loc : true, range : true, tokens : true, comment : true, + attachComment: true, ecmaFeatures: { arrowFunctions: true, // enable parsing of arrow functions blockBindings: true, // enable parsing of let/const @@ -37,65 +83,348 @@ module.exports = function(code) { experimentalObjectRestSpread: true // allow experimental object rest/spread } }); + var tokenStartMap = Object.create(null), tokenEndMap = Object.create(null); + var locToKey = function(loc) { + return loc.line + '-' + loc.column; + }; + (function() { + var lines = code.split(/\n/g); + // slideFwd and slideBck skip over whitespace + var slideFwd = function(loc) { + loc = {line: loc.line, column: loc.column}; + while (loc.line <= lines.length) { + var l = lines[loc.line - 1]; + var c = l[loc.column]; + if (!/[ \t\r\n]/.test(c)) break; + loc.column++; + if (loc.column >= l.length) { loc.column = 0; loc.line++; } + } + return loc; + }; + var slideBck = function(loc) { + loc = {line: loc.line, column: loc.column}; + while (loc.line >= 1) { + var l = lines[loc.line - 1]; + var c = l[loc.column - 1]; + if (!/[ \t\r\n]/.test(c)) break; + loc.column--; + if (loc.column < 0) { + loc.line--; + loc.column = lines[loc.line - 1].length - 1; + } + } + return loc; + }; + ast.tokens.forEach(function(t) { + tokenStartMap[locToKey(slideBck(t.loc.start))] = t; + tokenEndMap[locToKey(slideFwd(t.loc.end))] = t; + }); + })(); var rootScope = scope.create(ast, scope.KIND_ROOT); + function Emitter() { + this.buffer = ''; + this.line = 1; + this.insertionPoints = []; + this.indentLevel = 0; + } + Emitter.prototype.toString = function() { return this.buffer; }; + Emitter.prototype.emit = function(str) { + this.buffer += str; + }; + Emitter.prototype.nl = function() { + this.buffer = this.buffer.replace(/[ \t]+$/, '') + '\n'; + for (var i = 0; i < this.indentLevel; i++) { + this.buffer += '\t'; + } + this.line++; + } + Emitter.prototype.block = function(open, f, close) { + var firstline = this.line; + this.emit(open); this.emit(' '); + var checkpoint = this.buffer.length; + this.incrIndent(); + f(); + if (this.line > firstline) { + this.ensureNl(); + } else if (this.buffer.length !== checkpoint) { + this.emit(' '); + } else { + // no content in block => no space + this.buffer = this.buffer.replace(/[\t ]+$/, ''); + } + this.decrIndent(); + this.emit(close); + }; + Emitter.prototype.incrIndent = function() { + this.indentLevel++; + if (/\t$/.test(this.buffer)) { this.emit('\t'); } + } + Emitter.prototype.decrIndent = function() { + this.indentLevel--; + if (/\t$/.test(this.buffer)) { + this.buffer = this.buffer.slice(0, this.buffer.length - 1); + } + } + Emitter.prototype.locStart = function(node) { + if (node.leadingComments && node.leadingComments.length) { + node.leadingComments.forEach(function(c) { + this.emitComment(c); + }, this); + } + if (node.type === 'Program') { return; } + if (node && node.loc) { + while (node.loc.start.line > this.line) { + this.nl(); + } + this.line = node.loc.start.line; + } + // Hack for preserving parentheses from the original + if (!(node && node.suppressParens)) { + var startT = node && node.loc && tokenEndMap[locToKey(node.loc.start)]; + var endT = node && node.loc && tokenStartMap[locToKey(node.loc.end)]; + if ( + node.forceParens || + (utils.isType(startT, 'Punctuator') && startT.value === '(' && + utils.isType(endT, 'Punctuator') && endT.value === ')') + ) { + this.emit('( '); + } + } + }; + Emitter.prototype.locEnd = function(node) { + // Hack for preserving parentheses from the original + if (!(node && node.suppressParens)) { + var startT = node && node.loc && tokenEndMap[locToKey(node.loc.start)]; + var endT = node && node.loc && tokenStartMap[locToKey(node.loc.end)]; + if (node.forceParens || + (utils.isType(startT, 'Punctuator') && startT.value === '(' && + utils.isType(endT, 'Punctuator') && endT.value === ')') + ) { + if (!this.endsInNl()) this.emit(' '); + this.emit(')'); + } + } + if (node && node.loc) { + while (node.loc.end.line > this.line) { + this.nl(); + } + this.line = node.loc.end.line; + } + if (node.trailingComments && node.trailingComments.length) { + node.trailingComments.forEach(function(c) { + this.emitComment(c); + }, this); + } + }; + Emitter.prototype.emitComment = function(c) { + if (c.emitted) { return; } + this.locStart(c); + if (c.type==='Block') { + this.emit('/*'); + c.value.split(/\n/).forEach(function(l, idx) { + if (idx > 0) { this.nl(); } + this.emit(l.replace(/^\t+/, '')); + }, this); + this.emit('*/'); + } else { + this.emit('//' + c.value); this.nl(); + } + c.emitted = true; + }; + Emitter.prototype.endsInNl = function() { + return /\n[ \t]*$/.test(this.buffer); + }; + Emitter.prototype.isSemiLast = function() { + return this.buffer.match(/;\n?[ ]*$/); + } + Emitter.prototype.ensureSemi = function() { + if (!emitter.isSemiLast()) { this.emit('; '); } + }; + Emitter.prototype.ensureNl = function() { + if (!this.endsInNl()) { + this.nl(); + } + }; + Emitter.prototype.replaceSemiWithComma = function() { + this.buffer = this.buffer.replace(/;([ \t]*)$/, ', $1'); + }; + Emitter.prototype.pushInsertionPoint = function() { + this.insertionPoints.push(this.buffer.length); + } + Emitter.prototype.popInsertionPoint = function() { + this.insertionPoints.pop(); + } + Emitter.prototype.insertAt = function(depth, str) { + var idx = this.insertionPoints.length - depth - 1; + var at = this.insertionPoints[idx]; + this.buffer = this.buffer.slice(0, at) + str + this.buffer.slice(at); + while (++idx < this.insertionPoints.length) { + this.insertionPoints[idx] += str.length; + } + } + var emitter = new Emitter(); + if (options.indent) { emitter.indentLevel = options.indent; } + + function handleImport(parent, node) { + node.declarations.forEach(function(d) { + if (d.type !== 'VariableDeclarator') { return; } + scope.get(parent).register(d); + d.isImport = true; + // the RHS is require('..some string..') but we're going to ignore that + if (d.id.type === 'ObjectPattern') { + emitter.locStart(d); + d.id.properties.forEach(function(p, idx) { + scope.get(parent).register({ + type: 'VariableDeclarator', + id: { type: 'Identifier', name: p.value.name }, + isImport: true, + }); + if (idx > 0) { emitter.nl(); } + var name = utils.classize(p.key.name); + if (options.namespace) { name = options.namespace + "\\" + name; } + emitter.emit("use " + name); + if (p.key.name !== p.value.name || options.namespace) { + emitter.emit(" as " + utils.classize(p.value.name)); + } + emitter.emit(";"); + }); + emitter.locEnd(d); + } else if (d.id.type === 'Identifier') { + var name = d.id.name; + emitter.locStart(d); + if (options.namespace) { + emitter.emit(`use ${options.namespace}\\${name} as ${name};`); + } else { + emitter.emit(`use ${name};`); + } + emitter.locEnd(d); + } + }); + } function visit(node, parent) { - var content = "", semicolon = false; + var semicolon = false; // set parent node if (parent) { node.parent = parent; } + if (!node.suppressLoc) { emitter.locStart(node); } + + if (utils.isType(node, /^(Program|BlockStatement|ClassBody)$/)) { + // Skip strictness declaration + if (utils.isType(node.body[0], 'ExpressionStatement') && + utils.isType(node.body[0].expression, 'Literal') && + node.body[0].expression.raw.match(/^["']use strict["']$/)) { + emitter.locStart(node.body[0]); // flush leading comment + node.body.shift(); + } + if (node.type === 'Program') { + if (options.namespace && !options.noOpenTag) { + // Add optional namespace. + emitter.emit(`namespace ${options.namespace};`); + emitter.nl(); + } + + // skip core update require + while (utils.isType(node.body[0], 'ExpressionStatement') && + utils.isType(node.body[0].expression, 'CallExpression') && + utils.isId(node.body[0].expression.callee, 'require')) { + node.body.shift(); // discard this + } - if (node.type == "Program" || node.type == "BlockStatement" || node.type == "ClassBody") { + // Look for require declarations + while (utils.isType(node.body[0], 'VariableDeclaration') && + utils.isType(node.body[0].declarations[0], 'VariableDeclarator') && + utils.isType(node.body[0].declarations[0].init, 'CallExpression') && + utils.isId(node.body[0].declarations[0].init.callee, 'require')) { + handleImport(node, node.body.shift()); + } + } for (var i=0,length = node.body.length;i 0 && node.parent.type !== "Program") { - content += "use (" + using.map(function(identifier) { - return "&$" + identifier; - }).join(', ') + ") "; } + emitter.block('(', function() { + + // function declaration creates a new scope + scope.create(node); + + // compute function params + for (var i=0; i < node.params.length; i++) { + if (defaults[i]) { + visit({ + type: "BinaryExpression", + left: node.params[i], + operator: '=', + right: defaults[i] + }, node); + } else { + if (node.params.length===1) { node.params[i].suppressParens=true; } + visit(node.params[i], node) + } + if ((i+1) < node.params.length) { + emitter.emit(', '); + } - content += "{\n"; + // register parameter identifiers + if (scope.get(node).parent) { + scope.get(node).register(node.params[i]); + } + } + }, ')'); + emitter.emit(' '); + emitter.pushInsertionPoint(); + emitter.emit('{'); + emitter.pushInsertionPoint(); + emitter.block('', function() { + + visit(node.body, node); /* function contents */ + var using = scope.get(node).using + // XXX I don't understand why I have to do this: + .filter(function(u) { return u!==undefined;}); + + // try to use parent's variables + // http://php.net/manual/pt_BR/functions.anonymous.php + if (using.length > 0 && + !utils.isType(node.parent, /^(Program|MethodDefinition)$/)) { + emitter.insertAt(1, "use ( " + using.map(function(identifier) { + return "&$" + identifier; + }).join(', ') + " ) "); + } - // workaround when scope doesn't allow to have the `use` keyword. - if (node.parent.type === "Program") { - content += using.map(function(identifier) { - return `global $${identifier};`; - }).join("\n"); - } + // workaround when scope doesn't allow to have the `use` keyword. + if (node.parent.type === "Program") { + emitter.insertAt(0, using.map(function(identifier) { + return `\n\tglobal $${identifier};`; + }).join('')); + } - if (node.body.type === 'BinaryExpression') { - // x => x * 2 - content += "return " + func_contents + ";\n"; - } else { - content += func_contents; - } - content += "}\n"; + if (node.expression) { + // x => x * 2 + emitter.insertAt(0, 'return '); + emitter.emit(';'); + } + }, '}'); + emitter.popInsertionPoint(); + emitter.popInsertionPoint(); } else if (node.type == "ObjectExpression") { - var properties = []; - for (var i=0; i < node.properties.length; i++) { - properties.push( visit(node.properties[i], node) ) - } - content = "array(" + properties.join(", ") + ")"; + emitter.block(useConciseArrays ? '[' : 'array(', function() { + for (var i=0; i < node.properties.length; i++) { + visit(node.properties[i], node); + if ((i+1) < node.properties.length) { emitter.emit(', '); } + } + }, useConciseArrays ? ']' : ')'); } else if (node.type == "ArrayExpression") { - var elements = []; - for (var i=0; i < node.elements.length; i++) { - elements.push( visit(node.elements[i], node) ) - } - content = "array(" + elements.join(", ") + ")"; + emitter.block(useConciseArrays ? '[' : 'array(', function() { + for (var i=0; i < node.elements.length; i++) { + visit(node.elements[i], node); + if ((i+1) < node.elements.length) { emitter.emit(', '); } + } + }, useConciseArrays ? ']' : ')'); } else if (node.type == "Property") { var property = (node.key.type == 'Identifier') ? node.key.name : node.key.value; - content = '"'+property+'" => ' + visit(node.value, node); + if (typeof(property)==='string') { property = utils.stringify(property); } + emitter.emit(String(property) + ' => '); + visit(node.value, node); } else if (node.type == "ReturnStatement") { semicolon = true; - content = "return"; + emitter.emit('return'); if (node.argument) { - content += " " + visit(node.argument, node); + emitter.emit(' '); + visit(node.argument, node); } } else if (node.type == "ClassDeclaration") { - content = "class " + node.id.name + emitter.emit("class " + node.id.name + " "); if (node.superClass) { - content += " extends " + node.superClass.name; + emitter.emit("extends " + node.superClass.name + " "); } var s = scope.create(node); - content += "\n{\n"; - content += visit(node.body, node); + emitter.emit('{'); emitter.incrIndent(); + visit(node.body, node); if (s.getters.length > 0) { - content += "function __get($_property) {\n"; - for (var i=0;i 0) { - content += "function __set($_property, $value) {\n"; - for (var i=0;i $___)"; - content += "{" + visit(node.body, node) + "}"; + emitter.emit("foreach "); + emitter.block('(', function() { + visit(node.right, node); + emitter.emit(" as "); + visit(node.left, node); + emitter.emit(" => $___"); + }, ')'); + emitter.emit(' '); + emitter.block('{', function() { visit(node.body, node); }, '}'); } else if (node.type == "UpdateExpression") { if (node.prefix) { - content += node.operator; + emitter.emit(node.operator); } - content += visit(node.argument, node); + visit(node.argument, node); if (!node.prefix) { - content += node.operator; + emitter.emit(node.operator); } } else if (node.type == "SwitchStatement") { - content = "switch (" + visit(node.discriminant, node) + ")"; - content += "{"; - for (var i=0; i < node.cases.length; i++) { - content += visit(node.cases[i], node) + "\n"; - } - content += "}"; + emitter.emit("switch "); + emitter.block('(', function() { node.discriminant.suppressParens = true; visit(node.discriminant, node); }, ')'); + emitter.emit(' '); + emitter.block('{', function() { + for (var i=0; i < node.cases.length; i++) { + visit(node.cases[i], node); emitter.nl(); + } + }, '}'); } else if (node.type == "SwitchCase") { if (node.test) { - content += "case " + visit(node.test, node) + ":\n"; + emitter.emit("case "); + visit(node.test, node); + emitter.emit(":"); } else { - content = "default:\n"; + emitter.emit("default:"); } + emitter.nl(); for (var i=0; i < node.consequent.length; i++) { - content += visit(node.consequent[i], node); + visit(node.consequent[i], node); } } else if (node.type == "BreakStatement") { - content = "break;"; + emitter.emit("break; "); } else if (node.type == "ContinueStatement") { - content = "continue;"; + emitter.emit("continue; "); } else if (node.type == "NewExpression") { // re-use CallExpression for NewExpression's var newNode = utils.clone(node); newNode.type = "CallExpression"; + newNode.suppressParens = true; - return "new " + visit(newNode, node); + emitter.emit('new '); + visit(newNode, node); } else if (node.type == "FunctionExpression") { @@ -533,30 +1070,30 @@ module.exports = function(code) { node.type = "FunctionDeclaration"; node.id = { name: node.id || "" }; - content = visit(node, node.parent); + visit(node, node.parent); // Modules & Export (http://wiki.ecmascript.org/doku.php?id=harmony:modules_examples) } else if (node.type == "ModuleDeclaration") { - content = "namespace " + utils.classize(node.id.value) + ";\n"; - content += visit(node.body, node); + emitter.emit("namespace " + utils.classize(node.id.value) + "; "); + visit(node.body, node); } else if (node.type == "ExportNamedDeclaration") { - content = visit(node.declaration, node); + visit(node.declaration, node); } else if (node.type == "ImportDeclaration") { for (var i=0,length = node.specifiers.length;i 2) { + var result = js2php(fs.readFileSync(process.argv[2], 'utf8'), options); + if (process.argv.length < 4) { + console.log( result ); } else { - console.log( js2php(fs.readFileSync(process.argv[2]).toString()) ); + fs.writeFileSync(process.argv[3], result, 'utf8'); } } else { @@ -17,6 +34,6 @@ if (process.stdin.isTTY) { process.stdin.resume(); process.stdin.on('data', function(data) { code += data; }); process.stdin.on('end', function() { - console.log( js2php(code) ); + console.log( js2php(code, options) ); }); } diff --git a/package-lock.json b/package-lock.json index f00c137..31afa86 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,45 +1,49 @@ { "name": "js2php", - "version": "0.1.2", + "version": "0.1.7", "lockfileVersion": 1, "requires": true, "dependencies": { "JSONStream": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.4.tgz", - "integrity": "sha512-Y7vfi3I5oMOYIr+WxV8NZxDSwcbNgzdKYsTNInmycOq9bUYwGg9ryu57Wg5NLmCjqdFPNUmpMBo3kSJN9tCbXg==", + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", "dev": true, "requires": { - "jsonparse": "1.3.1", - "through": "2.3.8" + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" } }, "acorn": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.2.tgz", - "integrity": "sha512-cJrKCNcr2kv8dlDnbw+JPUGjHZzo4myaxOLmpOX8a+rgX94YeTcTMv/LFJUSByRpc+i4GgVnnhLxvMu/2Y+rqw==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", + "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==", "dev": true }, "acorn-dynamic-import": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz", - "integrity": "sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg==", - "dev": true, - "requires": { - "acorn": "5.7.2" - } + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz", + "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==", + "dev": true }, "acorn-node": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.5.2.tgz", - "integrity": "sha512-krFKvw/d1F17AN3XZbybIUzEY4YEPNiGo05AfP3dBlfVKrMHETKpgjpuZkSF8qDNt9UkQcqj7am8yJLseklCMg==", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.6.2.tgz", + "integrity": "sha512-rIhNEZuNI8ibQcL7ANm/mGyPukIaZsRNX9psFNQURyJW0nu6k8wjSDld20z6v2mDBWqX13pIEnk9gGZJHIlEXg==", "dev": true, "requires": { - "acorn": "5.7.2", - "acorn-dynamic-import": "3.0.0", - "xtend": "4.0.1" + "acorn": "^6.0.2", + "acorn-dynamic-import": "^4.0.0", + "acorn-walk": "^6.1.0", + "xtend": "^4.0.1" } }, + "acorn-walk": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz", + "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==", + "dev": true + }, "array-filter": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", @@ -64,9 +68,9 @@ "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", "dev": true, "requires": { - "bn.js": "4.11.8", - "inherits": "2.0.1", - "minimalistic-assert": "1.0.1" + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" } }, "assert": { @@ -102,7 +106,7 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -118,12 +122,12 @@ "integrity": "sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==", "dev": true, "requires": { - "JSONStream": "1.3.4", - "combine-source-map": "0.8.0", - "defined": "1.0.0", - "safe-buffer": "5.1.2", - "through2": "2.0.3", - "umd": "3.0.3" + "JSONStream": "^1.0.3", + "combine-source-map": "~0.8.0", + "defined": "^1.0.0", + "safe-buffer": "^5.1.1", + "through2": "^2.0.0", + "umd": "^3.0.0" } }, "browser-resolve": { @@ -150,59 +154,59 @@ "dev": true }, "browserify": { - "version": "16.2.2", - "resolved": "https://registry.npmjs.org/browserify/-/browserify-16.2.2.tgz", - "integrity": "sha512-fMES05wq1Oukts6ksGUU2TMVHHp06LyQt0SIwbXIHm7waSrQmNBZePsU0iM/4f94zbvb/wHma+D1YrdzWYnF/A==", - "dev": true, - "requires": { - "JSONStream": "1.3.4", - "assert": "1.4.1", - "browser-pack": "6.1.0", - "browser-resolve": "1.11.3", - "browserify-zlib": "0.2.0", - "buffer": "5.2.1", - "cached-path-relative": "1.0.1", - "concat-stream": "1.6.2", - "console-browserify": "1.1.0", - "constants-browserify": "1.0.0", - "crypto-browserify": "3.12.0", - "defined": "1.0.0", - "deps-sort": "2.0.0", - "domain-browser": "1.2.0", - "duplexer2": "0.1.4", - "events": "2.1.0", - "glob": "7.1.3", - "has": "1.0.3", - "htmlescape": "1.1.1", - "https-browserify": "1.0.0", - "inherits": "2.0.1", - "insert-module-globals": "7.2.0", - "labeled-stream-splicer": "2.0.1", - "mkdirp": "0.5.1", - "module-deps": "6.1.0", - "os-browserify": "0.3.0", - "parents": "1.0.1", - "path-browserify": "0.0.1", - "process": "0.11.10", - "punycode": "1.4.1", - "querystring-es3": "0.2.1", - "read-only-stream": "2.0.0", - "readable-stream": "2.3.6", - "resolve": "1.8.1", - "shasum": "1.0.2", - "shell-quote": "1.6.1", - "stream-browserify": "2.0.1", - "stream-http": "2.8.3", - "string_decoder": "1.1.1", - "subarg": "1.0.0", - "syntax-error": "1.4.0", - "through2": "2.0.3", - "timers-browserify": "1.4.2", + "version": "16.2.3", + "resolved": "https://registry.npmjs.org/browserify/-/browserify-16.2.3.tgz", + "integrity": "sha512-zQt/Gd1+W+IY+h/xX2NYMW4orQWhqSwyV+xsblycTtpOuB27h1fZhhNQuipJ4t79ohw4P4mMem0jp/ZkISQtjQ==", + "dev": true, + "requires": { + "JSONStream": "^1.0.3", + "assert": "^1.4.0", + "browser-pack": "^6.0.1", + "browser-resolve": "^1.11.0", + "browserify-zlib": "~0.2.0", + "buffer": "^5.0.2", + "cached-path-relative": "^1.0.0", + "concat-stream": "^1.6.0", + "console-browserify": "^1.1.0", + "constants-browserify": "~1.0.0", + "crypto-browserify": "^3.0.0", + "defined": "^1.0.0", + "deps-sort": "^2.0.0", + "domain-browser": "^1.2.0", + "duplexer2": "~0.1.2", + "events": "^2.0.0", + "glob": "^7.1.0", + "has": "^1.0.0", + "htmlescape": "^1.1.0", + "https-browserify": "^1.0.0", + "inherits": "~2.0.1", + "insert-module-globals": "^7.0.0", + "labeled-stream-splicer": "^2.0.0", + "mkdirp": "^0.5.0", + "module-deps": "^6.0.0", + "os-browserify": "~0.3.0", + "parents": "^1.0.1", + "path-browserify": "~0.0.0", + "process": "~0.11.0", + "punycode": "^1.3.2", + "querystring-es3": "~0.2.0", + "read-only-stream": "^2.0.0", + "readable-stream": "^2.0.2", + "resolve": "^1.1.4", + "shasum": "^1.0.0", + "shell-quote": "^1.6.1", + "stream-browserify": "^2.0.0", + "stream-http": "^2.0.0", + "string_decoder": "^1.1.1", + "subarg": "^1.0.0", + "syntax-error": "^1.1.1", + "through2": "^2.0.0", + "timers-browserify": "^1.0.1", "tty-browserify": "0.0.1", - "url": "0.11.0", - "util": "0.10.3", - "vm-browserify": "1.1.0", - "xtend": "4.0.1" + "url": "~0.11.0", + "util": "~0.10.1", + "vm-browserify": "^1.0.0", + "xtend": "^4.0.0" } }, "browserify-aes": { @@ -211,12 +215,12 @@ "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, "requires": { - "buffer-xor": "1.0.3", - "cipher-base": "1.0.4", - "create-hash": "1.2.0", - "evp_bytestokey": "1.0.3", - "inherits": "2.0.1", - "safe-buffer": "5.1.2" + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "browserify-cipher": { @@ -225,9 +229,9 @@ "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "dev": true, "requires": { - "browserify-aes": "1.2.0", - "browserify-des": "1.0.2", - "evp_bytestokey": "1.0.3" + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" } }, "browserify-des": { @@ -236,10 +240,10 @@ "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "dev": true, "requires": { - "cipher-base": "1.0.4", - "des.js": "1.0.0", - "inherits": "2.0.1", - "safe-buffer": "5.1.2" + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" } }, "browserify-rsa": { @@ -248,8 +252,8 @@ "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "dev": true, "requires": { - "bn.js": "4.11.8", - "randombytes": "2.0.6" + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" } }, "browserify-sign": { @@ -258,13 +262,13 @@ "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", "dev": true, "requires": { - "bn.js": "4.11.8", - "browserify-rsa": "4.0.1", - "create-hash": "1.2.0", - "create-hmac": "1.1.7", - "elliptic": "6.4.1", - "inherits": "2.0.1", - "parse-asn1": "5.1.1" + "bn.js": "^4.1.1", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.2", + "elliptic": "^6.0.0", + "inherits": "^2.0.1", + "parse-asn1": "^5.0.0" } }, "browserify-zlib": { @@ -273,7 +277,7 @@ "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", "dev": true, "requires": { - "pako": "1.0.6" + "pako": "~1.0.5" } }, "buffer": { @@ -282,8 +286,8 @@ "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", "dev": true, "requires": { - "base64-js": "1.3.0", - "ieee754": "1.1.12" + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" } }, "buffer-from": { @@ -305,9 +309,9 @@ "dev": true }, "cached-path-relative": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.1.tgz", - "integrity": "sha1-0JxLUoAKpMB44t2BqGmqyQ0uVOc=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.2.tgz", + "integrity": "sha512-5r2GqsoEb4qMTTN9J+WzXfjov+hjxT+j3u5K+kIVNIwAd99DLCJE9pBIMP1qVeybV6JiijL385Oz0DcYxfbOIg==", "dev": true }, "cipher-base": { @@ -316,8 +320,8 @@ "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "dev": true, "requires": { - "inherits": "2.0.1", - "safe-buffer": "5.1.2" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "combine-source-map": { @@ -326,10 +330,10 @@ "integrity": "sha1-pY0N8ELBhvz4IqjoAV9UUNLXmos=", "dev": true, "requires": { - "convert-source-map": "1.1.3", - "inline-source-map": "0.6.2", - "lodash.memoize": "3.0.4", - "source-map": "0.5.7" + "convert-source-map": "~1.1.0", + "inline-source-map": "~0.6.0", + "lodash.memoize": "~3.0.3", + "source-map": "~0.5.3" } }, "commander": { @@ -350,10 +354,10 @@ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "dev": true, "requires": { - "buffer-from": "1.1.1", - "inherits": "2.0.3", - "readable-stream": "2.3.6", - "typedarray": "0.0.6" + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" }, "dependencies": { "inherits": { @@ -370,7 +374,7 @@ "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", "dev": true, "requires": { - "date-now": "0.1.4" + "date-now": "^0.1.4" } }, "constants-browserify": { @@ -381,7 +385,7 @@ }, "convert-source-map": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=", "dev": true }, @@ -397,8 +401,8 @@ "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", "dev": true, "requires": { - "bn.js": "4.11.8", - "elliptic": "6.4.1" + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" } }, "create-hash": { @@ -407,11 +411,11 @@ "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "requires": { - "cipher-base": "1.0.4", - "inherits": "2.0.1", - "md5.js": "1.3.4", - "ripemd160": "2.0.2", - "sha.js": "2.4.11" + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" } }, "create-hmac": { @@ -420,12 +424,12 @@ "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, "requires": { - "cipher-base": "1.0.4", - "create-hash": "1.2.0", - "inherits": "2.0.1", - "ripemd160": "2.0.2", - "safe-buffer": "5.1.2", - "sha.js": "2.4.11" + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" } }, "crypto-browserify": { @@ -434,19 +438,25 @@ "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", "dev": true, "requires": { - "browserify-cipher": "1.0.1", - "browserify-sign": "4.0.4", - "create-ecdh": "4.0.3", - "create-hash": "1.2.0", - "create-hmac": "1.1.7", - "diffie-hellman": "5.0.3", - "inherits": "2.0.1", - "pbkdf2": "3.0.16", - "public-encrypt": "4.0.2", - "randombytes": "2.0.6", - "randomfill": "1.0.4" + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" } }, + "dash-ast": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-1.0.0.tgz", + "integrity": "sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA==", + "dev": true + }, "date-now": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", @@ -474,10 +484,10 @@ "integrity": "sha1-CRckkC6EZYJg65EHSMzNGvbiH7U=", "dev": true, "requires": { - "JSONStream": "1.3.4", - "shasum": "1.0.2", - "subarg": "1.0.0", - "through2": "2.0.3" + "JSONStream": "^1.0.3", + "shasum": "^1.0.0", + "subarg": "^1.0.0", + "through2": "^2.0.0" } }, "des.js": { @@ -486,19 +496,19 @@ "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", "dev": true, "requires": { - "inherits": "2.0.1", - "minimalistic-assert": "1.0.1" + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" } }, "detective": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/detective/-/detective-5.1.0.tgz", - "integrity": "sha512-TFHMqfOvxlgrfVzTEkNBSh9SvSNX/HfF4OFI2QFGCyPm02EsyILqnUeb5P6q7JZ3SFNTBL5t2sePRgrN4epUWQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", + "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", "dev": true, "requires": { - "acorn-node": "1.5.2", - "defined": "1.0.0", - "minimist": "1.2.0" + "acorn-node": "^1.6.1", + "defined": "^1.0.0", + "minimist": "^1.1.1" } }, "diff": { @@ -513,9 +523,9 @@ "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, "requires": { - "bn.js": "4.11.8", - "miller-rabin": "4.0.1", - "randombytes": "2.0.6" + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" } }, "domain-browser": { @@ -530,7 +540,7 @@ "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", "dev": true, "requires": { - "readable-stream": "2.3.6" + "readable-stream": "^2.0.2" } }, "elliptic": { @@ -539,13 +549,13 @@ "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", "dev": true, "requires": { - "bn.js": "4.11.8", - "brorand": "1.1.0", - "hash.js": "1.1.5", - "hmac-drbg": "1.0.1", - "inherits": "2.0.1", - "minimalistic-assert": "1.0.1", - "minimalistic-crypto-utils": "1.0.1" + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" } }, "escape-string-regexp": { @@ -571,8 +581,8 @@ "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "dev": true, "requires": { - "md5.js": "1.3.4", - "safe-buffer": "5.1.2" + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" } }, "fs.realpath": { @@ -599,12 +609,12 @@ "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.1", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "growl": { @@ -619,7 +629,7 @@ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, "requires": { - "function-bind": "1.1.1" + "function-bind": "^1.1.1" } }, "has-flag": { @@ -634,18 +644,18 @@ "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", "dev": true, "requires": { - "inherits": "2.0.1", - "safe-buffer": "5.1.2" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "hash.js": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.5.tgz", - "integrity": "sha512-eWI5HG9Np+eHV1KQhisXWwM+4EPPYe5dFX1UZZH7k/E3JzDEazVH+VGlZi6R94ZqImq+A3D1mCEtrFIfg/E7sA==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", "dev": true, "requires": { - "inherits": "2.0.3", - "minimalistic-assert": "1.0.1" + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" }, "dependencies": { "inherits": { @@ -668,9 +678,9 @@ "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", "dev": true, "requires": { - "hash.js": "1.1.5", - "minimalistic-assert": "1.0.1", - "minimalistic-crypto-utils": "1.0.1" + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" } }, "htmlescape": { @@ -686,9 +696,9 @@ "dev": true }, "ieee754": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", - "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", "dev": true }, "inflight": { @@ -697,8 +707,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -713,7 +723,7 @@ "integrity": "sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=", "dev": true, "requires": { - "source-map": "0.5.7" + "source-map": "~0.5.3" } }, "insert-module-globals": { @@ -722,16 +732,16 @@ "integrity": "sha512-VE6NlW+WGn2/AeOMd496AHFYmE7eLKkUY6Ty31k4og5vmA3Fjuwe9v6ifH6Xx/Hz27QvdoMoviw1/pqWRB09Sw==", "dev": true, "requires": { - "JSONStream": "1.3.4", - "acorn-node": "1.5.2", - "combine-source-map": "0.8.0", - "concat-stream": "1.6.2", - "is-buffer": "1.1.6", - "path-is-absolute": "1.0.1", - "process": "0.11.10", - "through2": "2.0.3", - "undeclared-identifiers": "1.1.2", - "xtend": "4.0.1" + "JSONStream": "^1.0.3", + "acorn-node": "^1.5.2", + "combine-source-map": "^0.8.0", + "concat-stream": "^1.6.1", + "is-buffer": "^1.1.0", + "path-is-absolute": "^1.0.1", + "process": "~0.11.0", + "through2": "^2.0.0", + "undeclared-identifiers": "^1.1.2", + "xtend": "^4.0.0" } }, "is-buffer": { @@ -752,7 +762,7 @@ "integrity": "sha1-YRwj6BTbN1Un34URk9tZ3Sryf0U=", "dev": true, "requires": { - "jsonify": "0.0.0" + "jsonify": "~0.0.0" } }, "jsonify": { @@ -773,9 +783,9 @@ "integrity": "sha512-MC94mHZRvJ3LfykJlTUipBqenZz1pacOZEMhhQ8dMGcDHs0SBE5GbsavUXV7YtP3icBW17W0Zy1I0lfASmo9Pg==", "dev": true, "requires": { - "inherits": "2.0.1", - "isarray": "2.0.4", - "stream-splicer": "2.0.0" + "inherits": "^2.0.1", + "isarray": "^2.0.4", + "stream-splicer": "^2.0.0" }, "dependencies": { "isarray": { @@ -793,13 +803,14 @@ "dev": true }, "md5.js": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", - "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "dev": true, "requires": { - "hash-base": "3.0.4", - "inherits": "2.0.1" + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" } }, "miller-rabin": { @@ -808,8 +819,8 @@ "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", "dev": true, "requires": { - "bn.js": "4.11.8", - "brorand": "1.1.0" + "bn.js": "^4.0.0", + "brorand": "^1.0.1" } }, "minimalistic-assert": { @@ -830,12 +841,12 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, @@ -881,37 +892,37 @@ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.1", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } } } }, "module-deps": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.1.0.tgz", - "integrity": "sha512-NPs5N511VD1rrVJihSso/LiBShRbJALYBKzDW91uZYy7BpjnO4bGnZL3HjZ9yKcFdZUWwaYjDz9zxbuP7vKMuQ==", - "dev": true, - "requires": { - "JSONStream": "1.3.4", - "browser-resolve": "1.11.3", - "cached-path-relative": "1.0.1", - "concat-stream": "1.6.2", - "defined": "1.0.0", - "detective": "5.1.0", - "duplexer2": "0.1.4", - "inherits": "2.0.1", - "parents": "1.0.1", - "readable-stream": "2.3.6", - "resolve": "1.8.1", - "stream-combiner2": "1.1.1", - "subarg": "1.0.0", - "through2": "2.0.3", - "xtend": "4.0.1" + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.0.tgz", + "integrity": "sha512-hKPmO06so6bL/ZvqVNVqdTVO8UAYsi3tQWlCa+z9KuWhoN4KDQtb5hcqQQv58qYiDE21wIvnttZEPiDgEbpwbA==", + "dev": true, + "requires": { + "JSONStream": "^1.0.3", + "browser-resolve": "^1.7.0", + "cached-path-relative": "^1.0.0", + "concat-stream": "~1.6.0", + "defined": "^1.0.0", + "detective": "^5.0.2", + "duplexer2": "^0.1.2", + "inherits": "^2.0.1", + "parents": "^1.0.0", + "readable-stream": "^2.0.2", + "resolve": "^1.4.0", + "stream-combiner2": "^1.1.1", + "subarg": "^1.0.0", + "through2": "^2.0.0", + "xtend": "^4.0.0" } }, "ms": { @@ -926,7 +937,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "os-browserify": { @@ -936,9 +947,9 @@ "dev": true }, "pako": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", - "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", + "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==", "dev": true }, "parents": { @@ -947,20 +958,21 @@ "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=", "dev": true, "requires": { - "path-platform": "0.11.15" + "path-platform": "~0.11.15" } }, "parse-asn1": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz", - "integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.4.tgz", + "integrity": "sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==", "dev": true, "requires": { - "asn1.js": "4.10.1", - "browserify-aes": "1.2.0", - "create-hash": "1.2.0", - "evp_bytestokey": "1.0.3", - "pbkdf2": "3.0.16" + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" } }, "path-browserify": { @@ -988,16 +1000,16 @@ "dev": true }, "pbkdf2": { - "version": "3.0.16", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.16.tgz", - "integrity": "sha512-y4CXP3thSxqf7c0qmOF+9UeOTrifiVTIM+u7NWlq+PRsHbr7r7dpCmvzrZxa96JJUNi0Y5w9VqG5ZNeCVMoDcA==", + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", "dev": true, "requires": { - "create-hash": "1.2.0", - "create-hmac": "1.1.7", - "ripemd160": "2.0.2", - "safe-buffer": "5.1.2", - "sha.js": "2.4.11" + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" } }, "process": { @@ -1013,16 +1025,17 @@ "dev": true }, "public-encrypt": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.2.tgz", - "integrity": "sha512-4kJ5Esocg8X3h8YgJsKAuoesBgB7mqH3eowiDzMUPKiRDDE7E/BqqZD1hnTByIaAFiwAw246YEltSq7tdrOH0Q==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", "dev": true, "requires": { - "bn.js": "4.11.8", - "browserify-rsa": "4.0.1", - "create-hash": "1.2.0", - "parse-asn1": "5.1.1", - "randombytes": "2.0.6" + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" } }, "punycode": { @@ -1044,12 +1057,12 @@ "dev": true }, "randombytes": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", - "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "^5.1.0" } }, "randomfill": { @@ -1058,8 +1071,8 @@ "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", "dev": true, "requires": { - "randombytes": "2.0.6", - "safe-buffer": "5.1.2" + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" } }, "read-only-stream": { @@ -1068,7 +1081,7 @@ "integrity": "sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=", "dev": true, "requires": { - "readable-stream": "2.3.6" + "readable-stream": "^2.0.2" } }, "readable-stream": { @@ -1077,13 +1090,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" }, "dependencies": { "inherits": { @@ -1091,16 +1104,25 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } } } }, "resolve": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", - "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.1.tgz", + "integrity": "sha512-KuIe4mf++td/eFb6wkaPbMDnP6kObCaEtIDuHOUED6MNUo4K670KZUHuuvYPZDxNF0WVLw49n06M2m2dXphEzA==", "dev": true, "requires": { - "path-parse": "1.0.6" + "path-parse": "^1.0.6" } }, "ripemd160": { @@ -1109,8 +1131,8 @@ "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "dev": true, "requires": { - "hash-base": "3.0.4", - "inherits": "2.0.1" + "hash-base": "^3.0.0", + "inherits": "^2.0.1" } }, "safe-buffer": { @@ -1125,8 +1147,8 @@ "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "dev": true, "requires": { - "inherits": "2.0.1", - "safe-buffer": "5.1.2" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "shasum": { @@ -1135,8 +1157,8 @@ "integrity": "sha1-5wEjENj0F/TetXEhUOVni4euVl8=", "dev": true, "requires": { - "json-stable-stringify": "0.0.1", - "sha.js": "2.4.11" + "json-stable-stringify": "~0.0.0", + "sha.js": "~2.4.4" } }, "shell-quote": { @@ -1145,10 +1167,10 @@ "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", "dev": true, "requires": { - "array-filter": "0.0.1", - "array-map": "0.0.0", - "array-reduce": "0.0.0", - "jsonify": "0.0.0" + "array-filter": "~0.0.0", + "array-map": "~0.0.0", + "array-reduce": "~0.0.0", + "jsonify": "~0.0.0" } }, "simple-concat": { @@ -1164,13 +1186,13 @@ "dev": true }, "stream-browserify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", - "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", "dev": true, "requires": { - "inherits": "2.0.1", - "readable-stream": "2.3.6" + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" } }, "stream-combiner2": { @@ -1179,8 +1201,8 @@ "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", "dev": true, "requires": { - "duplexer2": "0.1.4", - "readable-stream": "2.3.6" + "duplexer2": "~0.1.0", + "readable-stream": "^2.0.2" } }, "stream-http": { @@ -1189,11 +1211,11 @@ "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", "dev": true, "requires": { - "builtin-status-codes": "3.0.0", - "inherits": "2.0.1", - "readable-stream": "2.3.6", - "to-arraybuffer": "1.0.1", - "xtend": "4.0.1" + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" } }, "stream-splicer": { @@ -1202,17 +1224,17 @@ "integrity": "sha1-G2O+Q4oTPktnHMGTUZdgAXWRDYM=", "dev": true, "requires": { - "inherits": "2.0.1", - "readable-stream": "2.3.6" + "inherits": "^2.0.1", + "readable-stream": "^2.0.2" } }, "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", + "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } }, "subarg": { @@ -1221,7 +1243,7 @@ "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=", "dev": true, "requires": { - "minimist": "1.2.0" + "minimist": "^1.1.0" } }, "supports-color": { @@ -1230,7 +1252,7 @@ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } }, "syntax-error": { @@ -1239,7 +1261,7 @@ "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", "dev": true, "requires": { - "acorn-node": "1.5.2" + "acorn-node": "^1.2.0" } }, "through": { @@ -1249,13 +1271,13 @@ "dev": true }, "through2": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", - "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "dev": true, "requires": { - "readable-stream": "2.3.6", - "xtend": "4.0.1" + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" } }, "timers-browserify": { @@ -1264,7 +1286,7 @@ "integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=", "dev": true, "requires": { - "process": "0.11.10" + "process": "~0.11.0" } }, "to-arraybuffer": { @@ -1292,15 +1314,16 @@ "dev": true }, "undeclared-identifiers": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.2.tgz", - "integrity": "sha512-13EaeocO4edF/3JKime9rD7oB6QI8llAGhgn5fKOPyfkJbRb6NFv9pYV6dFEmpa4uRjKeBqLZP8GpuzqHlKDMQ==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.3.tgz", + "integrity": "sha512-pJOW4nxjlmfwKApE4zvxLScM/njmwj/DiUBv7EabwE4O8kRUy+HIwxQtZLBPll/jx1LJyBcqNfB3/cpv9EZwOw==", "dev": true, "requires": { - "acorn-node": "1.5.2", - "get-assigned-identifiers": "1.2.0", - "simple-concat": "1.0.0", - "xtend": "4.0.1" + "acorn-node": "^1.3.0", + "dash-ast": "^1.0.0", + "get-assigned-identifiers": "^1.2.0", + "simple-concat": "^1.0.0", + "xtend": "^4.0.1" } }, "url": { diff --git a/package.json b/package.json index cf11772..4ec340d 100644 --- a/package.json +++ b/package.json @@ -18,9 +18,9 @@ "transcompiler" ], "devDependencies": { - "browserify": "~16.2.2", - "mocha": "~5.2.0", - "assert": "~1.4.1" + "assert": "~1.4.1", + "browserify": "^16.2.3", + "mocha": "~5.2.0" }, "scripts": { "test": "mocha ./test/suite.js" diff --git a/scope.js b/scope.js index ef5c011..cb5ca78 100644 --- a/scope.js +++ b/scope.js @@ -1,5 +1,7 @@ var utils = require('./utils'); +var tmpCounter = 0; + function Scope(root, parent) { this.node = root; this.parent = parent; @@ -10,18 +12,27 @@ function Scope(root, parent) { this.getters = []; this.setters = []; - this.getDefinition = function(node) { + this.getDefinition = function(node, suppressUsing) { var value = this.definitions[ node.name ]; if (!value && this.parent) { value = this.parent.getDefinition(node); - if (value && this.using.indexOf(node.name) === -1) { + if (value && (!suppressUsing) && this.using.indexOf(node.name) === -1) { this.using.push(node.name); } } return value; - } + }; + + this.getTmpName = function() { + while (true) { + var name = `temp${tmpCounter++}`; + if (this.getDefinition({ name }, true) === undefined) { + return name; + } + } + }; this.register = function(node) { var name = null; diff --git a/test/fixtures/anonymous_function.php b/test/fixtures/anonymous_function.php index c21b456..5830ee3 100644 --- a/test/fixtures/anonymous_function.php +++ b/test/fixtures/anonymous_function.php @@ -1,13 +1,14 @@ { return a * b * c; } var something2 = (a, b = 2, c = 4) => a * b * c; + +var something3 = () => 5; + +var_dump(something3()); diff --git a/test/fixtures/arrow_functions.php b/test/fixtures/arrow_functions.php index 41057e7..7a4f046 100644 --- a/test/fixtures/arrow_functions.php +++ b/test/fixtures/arrow_functions.php @@ -1,9 +1,9 @@ _something = $something; -} -public function toArray($model, $array) { -return $array; -} -public function hello() { -return "Hello world"; -} -public function creating($model) { -Mail::send(array("body" => Module::template('signup-confirmation')->compile(array("base_url" => AppConfig::get("retrieve.email.url"))), "subject" => "Sign-up confirmation", "to" => $model->email, "from" => "somebody@example.com")); -} -public function updating($model) { -if ($model->isDirty('status') && $model->status == 1) { -Mail::send(array("body" => Module::template('signup-approved')->compile(array("BASE_URL" => AppConfig::get("retrieve.email.url"))), "subject" => "Approved!", "to" => $model->email, "from" => "somebody@example.com")); -}} -function __get($_property) { -if ($_property === 'something') { -return "Something: " + $this->_something; -} -} -function __set($_property, $value) { -if ($_property === 'something') { -$this->_something = $value + 10; -} -} +class ClassExample { + + public function __construct( $something ) { + $this->_something = $something; + } + public $_something; + + + public function toArray( $model, $array ) { + return $array; + } + + public function hello() { + return 'Hello world'; + } + + + + + + + + + public function creating( $model ) { + Mail::send( [ + 'body' => Module::template( 'signup-confirmation' )->compile( [ + 'base_url' => AppConfig::get( 'retrieve.email.url' ) + ] + ), + 'subject' => 'Sign-up confirmation', + 'to' => $model->email, + 'from' => 'somebody@example.com' + ] + ); + } + + public function updating( $model ) { + if ( $model->isDirty( 'status' ) && $model->status == 1 ) { + + Mail::send( [ + 'body' => Module::template( 'signup-approved' )->compile( [ + 'BASE_URL' => AppConfig::get( 'retrieve.email.url' ) + ] + ), + 'subject' => 'Approved!', + 'to' => $model->email, + 'from' => 'somebody@example.com' + ] + ); + + } + } + + function __get($_property) { + if ($_property === 'something') { + return 'Something: ' . $this->_something; + } + } + function __set($_property, $value) { + if ($_property === 'something') { + $this->_something = $value + 10; + } + } } -$example = new ClassExample("awesome"); -var_dump(call_user_func_array(array($example, 'hello'), array())); -var_dump($example->hello()); + + + + + + + + + + + + + + + + + + + + + + + + + + + +// Instantiate class and call getter method +$example = new ClassExample( 'awesome' ); +var_dump( call_user_func_array( [ $example, 'hello' ], [] ) ); +var_dump( $example->hello() ); + +$c = ( new ClassExample( 'cool' ) )->hello(); diff --git a/test/fixtures/class_inheritance.php b/test/fixtures/class_inheritance.php index a5e1ed4..ef38d35 100644 --- a/test/fixtures/class_inheritance.php +++ b/test/fixtures/class_inheritance.php @@ -1,29 +1,30 @@ title = $title; -$this->body = $body; -} -public function getDescription() { -return "{$this->title}: {$this->body}"; -} +class Page { + public function __construct( $title, $body ) { + $this->title = $title; + $this->body = $body; + } + public $title; + public $body; + + public function getDescription() { + return "{$this->title}: {$this->body}"; + } } -class Article extends Page -{ -public $author; -public function __construct($title, $body, $author) { -parent::__construct($title, $body); -$this->author = $author; -} -public function getDescription() { -$descrition = $parent->getDescription(); -return "{$description} by {$this->author}"; -} +class Article extends Page { + public function __construct( $title, $body, $author ) { + parent::__construct( $title, $body ); + $this->author = $author; + } + public $author; + + public function getDescription() { + $descrition = $parent->getDescription(); + return "{$description} by {$this->author}"; + } } -$article = new Article("Wonderful article", "Yada Yada Yada", "Bob Loblaw"); -var_dump($article->getDescription()); + +$article = new Article( 'Wonderful article', 'Yada Yada Yada', 'Bob Loblaw' ); +var_dump( $article->getDescription() ); diff --git a/test/fixtures/closures.php b/test/fixtures/closures.php index 989e09a..8b4e4b4 100644 --- a/test/fixtures/closures.php +++ b/test/fixtures/closures.php @@ -1,12 +1,11 @@ "Three"), $items)); -echo(join(", ", $items)); +$items = [ 'One', 'Two', 'Three' ]; + +array_unshift( $items, 'Zero' ); +array_shift( $items ); +$items[] = 'Four'; +array_push( $items, 'Four', 'Five' ); + +var_dump( $items ); +echo( implode( ', ', $items ) ); + +echo( count( $items ) ); +echo( array_search( [ 'name' => 'Three' ], $items ) ); +echo( implode( ', ', $items ) ); +echo( "\n" ); + +$count = array_reduce( $items, function ( $curr, $string ) { + return $curr + strlen( $string ); + }, 0 +) + +; +var_dump( $count ); + +var_dump( is_array( $items ) ); +var_dump( is_array( $count ) ); + +/* This might not work, but it shouldn't crash! */ +$a = array_slice( [ 1, 2, 3 ], 1 ); +var_dump( $a ); diff --git a/test/fixtures/core_date.js b/test/fixtures/core_date.js new file mode 100644 index 0000000..372a35d --- /dev/null +++ b/test/fixtures/core_date.js @@ -0,0 +1,4 @@ +var start = Date.now(); +doSomethingExpensive(); +var end = Date.now(); +var_dump(end-start); diff --git a/test/fixtures/core_date.php b/test/fixtures/core_date.php new file mode 100644 index 0000000..ce182b3 --- /dev/null +++ b/test/fixtures/core_date.php @@ -0,0 +1,5 @@ + 5, "string" => "hey", "nested" => array("objects" => array("here" => "yey")))); -var_dump(json_encode(array("integer" => 5, "string" => "hey", "nested" => array("objects" => array("here" => "yey"))))); +json_encode( [ + 'integer' => 5, + 'string' => 'hey', + 'nested' => [ 'objects' => [ 'here' => 'yey' ] ] + ] +); + + + +; + +var_dump( json_encode( [ + 'integer' => 5, + 'string' => 'hey', + 'nested' => [ 'objects' => [ 'here' => 'yey' ] ] + ] + ) + + + +); diff --git a/test/fixtures/core_math.php b/test/fixtures/core_math.php index 0b87138..fe000b1 100644 --- a/test/fixtures/core_math.php +++ b/test/fixtures/core_math.php @@ -1,4 +1,5 @@ hasOwnProperty( 'foo' ) ); diff --git a/test/fixtures/core_string.js b/test/fixtures/core_string.js index a89628b..6c2d2cf 100644 --- a/test/fixtures/core_string.js +++ b/test/fixtures/core_string.js @@ -29,6 +29,11 @@ echo(strArray[0]); var strArray2 = str.split(''); echo(strArray2[0]); +// shouldn't crash with identifier as argument. +var xyz = 'll'; +var strArray3 = str.split(xyz); +echo(strArray3[0]); + var_dump('testing'.length); var test_length = 'testing_string_variable'; @@ -48,4 +53,14 @@ if (str.match(/endel/)) { var_dump(str); } +var_dump("Strings with funny characters like \n and $foo and {$foo}"); +var_dump('\\\\'); + +function foo() { return "x"; } + +var x = "foo" + foo(); +var y = foo() + 'bar'; +var z = foo() + "bar" + foo(); +var typeOf = node.getAttribute('typeof'); +var_dump(typeOf.match('begin')); diff --git a/test/fixtures/core_string.php b/test/fixtures/core_string.php index 8dff333..5c6dd7d 100644 --- a/test/fixtures/core_string.php +++ b/test/fixtures/core_string.php @@ -1,34 +1,67 @@ getAttribute( 'typeof' ); +var_dump( preg_match( '/begin/', $typeOf ) ); diff --git a/test/fixtures/date.php b/test/fixtures/date.php index cd2c2ce..cc7a9e7 100644 --- a/test/fixtures/date.php +++ b/test/fixtures/date.php @@ -1,3 +1,3 @@ "one"), array("name" => "two"), array("name" => "three")); -foreach ($items as $item => $___){echo($item['name']); -continue;} \ No newline at end of file +$items = [ + [ 'name' => 'one' ], + [ 'name' => 'two' ], + [ 'name' => 'three' ] +]; + +foreach ( $items as $item => $___ ) { + echo( $item[ 'name' ] ); + continue; +} diff --git a/test/fixtures/function.js b/test/fixtures/function.js index 9d08f20..dc34c63 100644 --- a/test/fixtures/function.js +++ b/test/fixtures/function.js @@ -12,6 +12,11 @@ function hello(a, b) { } var_dump(hello.apply(hello, [5,6])) -var_dump(hello(5, 6)) +var_dump(hello(5, 6)); -// var_dump(something(5), sum(1,2)) +var args = [5, 6]; +var_dump(sum.apply(sum, args)); + +var foo = function bar() { }; + +// var_dump(something(5), sum(1,2)); diff --git a/test/fixtures/function.php b/test/fixtures/function.php index 4d3c119..9780737 100644 --- a/test/fixtures/function.php +++ b/test/fixtures/function.php @@ -1,12 +1,23 @@ read()); +echo( $article->read() ); diff --git a/test/fixtures/global_functions.php b/test/fixtures/global_functions.php index c5fd181..86be72b 100644 --- a/test/fixtures/global_functions.php +++ b/test/fixtures/global_functions.php @@ -1,8 +1,10 @@ 0); + +for (i=0, j=2; i5) break; +} diff --git a/test/fixtures/loops.php b/test/fixtures/loops.php index 8e4fece..b585d69 100644 --- a/test/fixtures/loops.php +++ b/test/fixtures/loops.php @@ -1,13 +1,43 @@ 'one', "two" => 'two', "three" => 'three'); -foreach ($obj as $i => $___){var_dump($i, $obj[$i]); -}$j = 10; -while ($j > 0) {$j--; -var_dump($j); -}$xxx = 10; -do {--$xxx; -} while ($xxx > 0); +$items = [ 1, 2, 3, 4, 5 ]; + +for ( $i = 0; $i < count( $items ); $i++ ) { + var_dump( $items[ $i ] ); +} + +for ( $i = 0, $j = 10; $i < $j; $i++ ) { + var_dump( $i ); +} + +$obj = [ + 'one' => 'one', + 'two' => 'two', + 'three' => 'three' +]; + +foreach ( $obj as $i => $___ ) { + var_dump( $i, $obj[ $i ] ); +} + +$j = 10; +while ( $j > 0 ) { + $j--; + var_dump( $j ); +} + +$xxx = 10; + +do { + --$xxx; +} while ( $xxx > 0 ); + +for ( $i = 0, $j = 2; $i < $j; $i++ ) { + echo( $i ); +} +for ( $k = 0, $count = 2; $k < $count; $k++ ) { + echo( $k ); +} +for ( ; true; ) { + $i++; + if ( $i > 5 ) { break; } +} diff --git a/test/fixtures/namespaces.php b/test/fixtures/namespaces.php index ddd5f02..3eb66fa 100644 --- a/test/fixtures/namespaces.php +++ b/test/fixtures/namespaces.php @@ -1,18 +1,17 @@ do_something_else(); +echo( semver::satisfies( 1, 2 ) ); +echo( semver::satisfies( 1, 2 )->something_else() ); +echo( [ 'Foo' => Foo::class, 'Bar' => Bar::class ] ); + +$foo = 3; +$n = new Negotiator( $foo ); diff --git a/test/fixtures/namespaces_use.php b/test/fixtures/namespaces_use.php index b811127..ee3c555 100644 --- a/test/fixtures/namespaces_use.php +++ b/test/fixtures/namespaces_use.php @@ -1,5 +1,6 @@ 'foo', 'bar' => 42 ]; +$temp0 = $x; $foo = $temp0->foo; $bar = $temp0->bar; +$y = 'not foo'; +( ( ( function () use ( &$x ) { $temp1 = $x; $y = $temp1->foo; return null; } ) )() ); +var_dump( "{$foo} {$bar} {$y}" ); diff --git a/test/fixtures/parsoid.js b/test/fixtures/parsoid.js new file mode 100644 index 0000000..5224581 --- /dev/null +++ b/test/fixtures/parsoid.js @@ -0,0 +1,11 @@ +'use strict'; +require('core-update.js'); +const { Bat } = require('some/thing'); + +var bar = Promise.async(function *(x) { + return (yield Bat.bat()); +}); + +class Foo { + constructor() { this.x = 1; } +} diff --git a/test/fixtures/parsoid.php b/test/fixtures/parsoid.php new file mode 100644 index 0000000..9746cbc --- /dev/null +++ b/test/fixtures/parsoid.php @@ -0,0 +1,15 @@ +x = 1; } + public $x; +} diff --git a/test/fixtures/regexp.js b/test/fixtures/regexp.js index 3cc23d4..a9085e4 100644 --- a/test/fixtures/regexp.js +++ b/test/fixtures/regexp.js @@ -20,4 +20,30 @@ var_dump("hey hey hey".replace(/y/g, "llo")); var string = 'hello'; var regex = 'ello'; -var nonliteral = string.match(regex); \ No newline at end of file +var nonliteral = string.match(regex); + +var_dump(/abc\n[/]/.test('def')); +var_dump(/[\n]/.source.slice(1,-1)); + +var_dump("./a/b/c".replace(/\.\//, '')); + +var matches = /[abc]/gi.exec("LA la black sheep"); + +var firstA = unknownValue(); +if (firstA && /^#/.test(firstA.getAttribute('href'))) { + var_dump("whoo"); +} + +// Tricky escape cases. +var x = /abc\n'"\/\\/i.source; // should be "abc\\n'\"\\/\\\\" +var y = /abc\n'"\/\\/i.test("ABC\n'\"/\\"); // should be true +// This only returns one match, but it uses the lastIndex property: +var z1 = /abc\n'"\/\\/ig.exec("abc\n'\"/\\xyzABC\n'\"/\\"); +var z2 = "Qabc\n'\"/\\xyzABC\n'\"/\\Q".split(/abc\n'"\/\\/ig); +// z2 should be [ 'Q', 'xyz', 'Q' ] +var z3 = "Qabc\n'\"/\\xyzABC\n'\"/\\Q".match(/abc\n'"\/\\/ig); +// z3 should be [ 'abc\n\'"/\\', 'ABC\n\'"/\\' ] +var z4 = "Qabc\n'\"/\\xyzABC\n'\"/\\Q".replace(/abc\n'"\/\\/ig, "x"); +// z4 should be 'QxxyzxQ' +var z5 = /^text\/html;/.test("text/html; quality=2"); +// z5 should be true diff --git a/test/fixtures/regexp.php b/test/fixtures/regexp.php index 87e1b57..a8339a3 100644 --- a/test/fixtures/regexp.php +++ b/test/fixtures/regexp.php @@ -1,18 +1,50 @@ getAttribute( 'href' ) ) ) { + var_dump( 'whoo' ); +} + +// Tricky escape cases. +$x = "abc\\n'\"\\/\\\\"; // should be "abc\\n'\"\\/\\\\" +$y = preg_match( "/abc\\n'\"\\/\\\\/", "ABC\n'\"/\\" ); // should be true +// This only returns one match, but it uses the lastIndex property: +$z1 = /*RegExp#exec*/preg_match_all( "/abc\\n'\"\\/\\\\/i", "abc\n'\"/\\xyzABC\n'\"/\\", $FIXME ); +$z2 = preg_split( "/abc\\n'\"\\/\\\\/i", "Qabc\n'\"/\\xyzABC\n'\"/\\Q" ); +// z2 should be [ 'Q', 'xyz', 'Q' ] +$z3 = preg_match_all( "/abc\\n'\"\\/\\\\/i", "Qabc\n'\"/\\xyzABC\n'\"/\\Q", $FIXME ); +// z3 should be [ 'abc\n\'"/\\', 'ABC\n\'"/\\' ] +$z4 = preg_replace( "/abc\\n'\"\\/\\\\/i", 'x', "Qabc\n'\"/\\xyzABC\n'\"/\\Q" ); +// z4 should be 'QxxyzxQ' +$z5 = preg_match( '/^text\/html;/', 'text/html; quality=2' ); +// z5 should be true diff --git a/test/fixtures/rest_spread.js b/test/fixtures/rest_spread.js new file mode 100644 index 0000000..dc28fab --- /dev/null +++ b/test/fixtures/rest_spread.js @@ -0,0 +1,5 @@ +var x = (...args) => args.length; +var y = (z) => x(...z); + +var_dump(x(1, 2, 3, 4)); +var_dump(y([1, 2, 3])); diff --git a/test/fixtures/rest_spread.php b/test/fixtures/rest_spread.php new file mode 100644 index 0000000..bcd0e5c --- /dev/null +++ b/test/fixtures/rest_spread.php @@ -0,0 +1,6 @@ +log($x, $y); -$console->log($z); -var_dump(array("a" => 1, "b-c" => 'c', "d-e-fh" => g(0), "hi" => "hi")); -$obj = array("key" => 'value', "key2" => 'value2'); -unset($obj['key']); -var_dump(isset($something['key2'])); -var_dump(gettype($something) !== NULL); + +$console->log( $x, $y ); +$console->log( $z ); + +var_dump( [ 'a' => 1, 'b-c' => 'c', 'd-e-fh' => g( 0 ), 'hi' => 'hi' ] ); + +$obj = [ 'key' => 'value', 'key2' => 'value2' ]; +unset( $obj[ 'key' ] ); +var_dump( isset( $something[ 'key2' ] ) ); +var_dump( gettype( $something ) !== NULL ); diff --git a/test/fixtures/static_call.php b/test/fixtures/static_call.php index b4dde0d..3aedf24 100644 --- a/test/fixtures/static_call.php +++ b/test/fixtures/static_call.php @@ -1,5 +1,18 @@ json(array("success" => Mail::send(array("body" => Module::template('signup-confirmation')->compile(array("base_url" => AppConfig::get("retrieve.email.url"))), "subject" => "Sign-up confirmation", "to" => $model->email, "from" => "somebody@example.com")))); -} + +Module\Http\Router::get( '/send', function () { + return $this->json( [ + 'success' => Mail::send( [ + 'body' => Module::template( 'signup-confirmation' )->compile( [ + 'base_url' => AppConfig::get( 'retrieve.email.url' ) + ] + ), + 'subject' => 'Sign-up confirmation', + 'to' => $model->email, + 'from' => 'somebody@example.com' + ] + ) + ] + ); + } ); diff --git a/test/fixtures/string_template.js b/test/fixtures/string_template.js index 657cd5d..9dad8e6 100644 --- a/test/fixtures/string_template.js +++ b/test/fixtures/string_template.js @@ -15,3 +15,5 @@ class Item { var item = new Item(); echo(`${str1}, ${str2}, ${n1}, ${n2}, ${ item.method() }, ${ func() }`) + +echo(`funny characters like " and \n should be fine ${ 1 + 2 }`); diff --git a/test/fixtures/string_template.php b/test/fixtures/string_template.php index 01f7d44..4907cc3 100644 --- a/test/fixtures/string_template.php +++ b/test/fixtures/string_template.php @@ -1,18 +1,20 @@ method()}, {$func()}"); + +echo( "{$str1}, {$str2}, {$n1}, {$n2}, {$item->method()}, {$func()}" ); + +echo( "funny characters like \" and \n should be fine {1 + 2}" ); diff --git a/test/generate.js b/test/generate.js index db67f3e..d2bef29 100644 --- a/test/generate.js +++ b/test/generate.js @@ -24,15 +24,19 @@ if (!target) { for(var i=0;i '" + e.message + "'", e.stack); diff --git a/test/suite.js b/test/suite.js index 8492883..681d0b6 100644 --- a/test/suite.js +++ b/test/suite.js @@ -14,9 +14,13 @@ describe('js2php', function(){ (function(i) { it(sources[i][0], function(){ var js_source = fs.readFileSync(sources[i][0]).toString(), - php_source = fs.readFileSync(sources[i][1]).toString().trim(); + php_source = fs.readFileSync(sources[i][1]).toString().trim(), + options = {}; + if (/namespaces_require\.js$/.test(sources[i][0])) { + options.namespace = 'NameTest'; + } - assert.equal(js2php(js_source).trim(), php_source); + assert.equal(js2php(js_source, options).trim(), php_source); }) })(i) } diff --git a/utils.js b/utils.js index 8e198db..7265d71 100644 --- a/utils.js +++ b/utils.js @@ -19,6 +19,14 @@ module.exports = { } }, + stringify: function(string, forceDoubleQuote) { + if (/^[ -&\(-~]*$/.test(string) && !forceDoubleQuote) { + /* can use an efficient single-quoted string */ + return "'" + string.replace(/'|(?:\\(?=[\\']|$))/g, '\\$&') + "'"; + } + return JSON.stringify(string).replace(/\$/g, '\\$'); // double-quoted string + }, + clone: function(obj) { var parent = null, response = null; @@ -37,7 +45,8 @@ module.exports = { }, isString: function(node) { - return node.type == "Literal" && node.raw.match(/^['|"]/); + return (node.type == "Literal" && node.raw.match(/^['|"]/)) || + node.dataType === 'String'; }, isRegExp: function(node) { @@ -47,7 +56,7 @@ module.exports = { value = value.substr(1, node.raw.length-2); } - var isRegExp = value.match(/^\/[^\/]+\/[gimy]?$/); + var isRegExp = value.match(/^\/(?:[^\/]|\\.)+\/[gimy]+?$/); if (isRegExp) { node.raw.value = "'" + value + "'"; @@ -55,5 +64,23 @@ module.exports = { } return isRegExp; - } + }, + + isType: function(node, type) { + return node && + (typeof(type)==='string' ? (type===node.type) : type.test(node.type)); + }, + + isId: function(node, id) { + return module.exports.isType(node, 'Identifier') && + (typeof(id)==='string' ? (id===node.name) : id.test(node.name)); + }, + + // utility function for core library definitions + coreAddHash: function(exports, className) { + Object.keys(exports).forEach(function(name) { + if (/[#.]/.test(name)) { return; } + exports[className + '#' + name] = exports[name]; + }); + }, }