├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── core.js ├── core ├── array.js ├── console.js ├── date.js ├── function.js ├── global.js ├── json.js ├── math.js ├── number.js ├── object.js ├── promise.js ├── regexp.js └── string.js ├── index.js ├── js2php ├── package-lock.json ├── package.json ├── scope.js ├── test ├── fixtures │ ├── anonymous_function.js │ ├── anonymous_function.php │ ├── array_index.js │ ├── array_index.php │ ├── arrow_functions.js │ ├── arrow_functions.php │ ├── assert.js │ ├── assert.php │ ├── class.js │ ├── class.php │ ├── class_inheritance.js │ ├── class_inheritance.php │ ├── closures.js │ ├── closures.php │ ├── concat.js │ ├── concat.php │ ├── conditionals.js │ ├── conditionals.php │ ├── core_array.js │ ├── core_array.php │ ├── core_date.js │ ├── core_date.php │ ├── core_function.js │ ├── core_function.php │ ├── core_json.js │ ├── core_json.php │ ├── core_math.js │ ├── core_math.php │ ├── core_number.js │ ├── core_number.php │ ├── core_object.js │ ├── core_object.php │ ├── core_string.js │ ├── core_string.php │ ├── date.js │ ├── date.php │ ├── exceptions.js │ ├── exceptions.php │ ├── expression.js │ ├── expression.php │ ├── failures.js │ ├── failures.php │ ├── for_of.js │ ├── for_of.php │ ├── function.js │ ├── function.php │ ├── function_super.js │ ├── function_super.php │ ├── global_functions.js │ ├── global_functions.php │ ├── iife.js │ ├── iife.php │ ├── loops.js │ ├── loops.php │ ├── namespaces.js │ ├── namespaces.php │ ├── namespaces_require.js │ ├── namespaces_require.php │ ├── namespaces_use.js │ ├── namespaces_use.php │ ├── object_pattern.js │ ├── object_pattern.php │ ├── parsoid.js │ ├── parsoid.php │ ├── regexp.js │ ├── regexp.php │ ├── rest_spread.js │ ├── rest_spread.php │ ├── simple.js │ ├── simple.php │ ├── static_call.js │ ├── static_call.php │ ├── string_template.js │ └── string_template.php ├── generate.js └── suite.js └── utils.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node 2 | 3 | node: 4 | - 0.10 5 | - 0.11 6 | - 0.12 7 | 8 | before_script: 9 | - npm install 10 | 11 | script: 12 | - npm test 13 | 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Endel Dreyer 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | js2php 2 | === 3 | 4 | [![Build status](https://travis-ci.org/endel/js2php.svg?branch=master)](https://travis-ci.org/endel/js2php) 5 | 6 | JavaScript to PHP source-to-source transpiler. [Online demo](http://endel.github.io/js2php) 7 | 8 | **This is an experiment. Please do not use it.** 9 | 10 | Installation 11 | --- 12 | 13 | - Install [nodejs](http://nodejs.org/) 14 | - Install js2php globally: `npm install -g js2php` 15 | 16 | Usage 17 | --- 18 | 19 | Convert a single JavaScript file into PHP: 20 | 21 | ``` 22 | js2php examples/simple.js > simple.php 23 | ``` 24 | 25 | Since `js2php` outputs the PHP code to stdout, you may run it right after 26 | conversion: 27 | 28 | ``` 29 | js2php examples/class.js | php 30 | ``` 31 | 32 | Features 33 | --- 34 | 35 | What does it converts? 36 | 37 | - Classes (ES6) 38 | - Getters and Setters (ES6) 39 | - Namespaces (ES6) 40 | - Loops (while / for / do-while / for-of / for-in) 41 | - Arrow functions (ES6) 42 | - Template strings (ES6) 43 | - Functions and closures 44 | - Conditionals 45 | - [Core JavaScript](core) 46 | - Array 47 | - Array.prototype.unshift 48 | - Array.prototype.shift 49 | - Array.prototype.reverse 50 | - Array.prototype.push 51 | - Array.prototype.pop 52 | - Array.prototype.join 53 | - Array.prototype.splice 54 | - Array.prototype.indexOf 55 | - Array.prototype.length 56 | - JSON 57 | - JSON.parse 58 | - JSON.stringify 59 | - Math 60 | - Math.E 61 | - Math.LN2 62 | - Math.LN10 63 | - Math.LOG2E 64 | - Math.LOG10E 65 | - Math.PI 66 | - Math.SQRT2 67 | - Math.SQRT1_2 68 | - Math.abs 69 | - Math.acos 70 | - Math.acosh 71 | - Math.asin 72 | - Math.asinh 73 | - Math.atan 74 | - Math.atanh 75 | - Math.atan2 76 | - Math.cbrt 77 | - Math.ceil 78 | - Math.clz32 79 | - Math.cos 80 | - Math.cosh 81 | - Math.exp 82 | - Math.expm1 83 | - Math.floor 84 | - Math.hypot 85 | - Math.log 86 | - Math.log1p 87 | - Math.log10 88 | - Math.max 89 | - Math.min 90 | - Math.pow 91 | - Math.random 92 | - Math.round 93 | - Math.sin 94 | - Math.sinh 95 | - Math.sqrt 96 | - Math.tan 97 | - Math.tanh 98 | - Number 99 | - Number.isInteger 100 | - Number.isFinite 101 | - String 102 | - String.prototype.replace 103 | - String.prototype.trim 104 | - String.prototype.trimRight 105 | - String.prototype.trimLeft 106 | - String.prototype.toUpperCase 107 | - String.prototype.toLowerCase 108 | - String.prototype.split 109 | - String.prototype.substr 110 | - String.prototype.match 111 | - Function 112 | - Function.prototype.apply 113 | - Function.prototype.call 114 | - Date 115 | - Date.now 116 | 117 | Testing 118 | --- 119 | 120 | Tests are simple input (js) / output (php) comparisions. 121 | 122 | 1. Create your source `.js` file at `test/fixtures/js_feature.js` 123 | 2. Convert your `.js` to `.php` manually: `node test/generate.js js_feature.js` 124 | 3. Run `npm test` 125 | 126 | License 127 | --- 128 | 129 | MIT 130 | -------------------------------------------------------------------------------- /core.js: -------------------------------------------------------------------------------- 1 | var utils = require('./utils'), 2 | scope = require('./scope'), 3 | _global = require('./core/global'), 4 | _array = require('./core/array'), 5 | _console = require('./core/console'), 6 | _date = require('./core/date'), 7 | _function = require('./core/function'), 8 | _json = require('./core/json'), 9 | _object = require('./core/object'), 10 | _promise = require('./core/promise'), 11 | _regexp = require('./core/regexp'), 12 | _string = require('./core/string'), 13 | _math = require('./core/math'), 14 | _number = require('./core/number'); 15 | 16 | module.exports = { 17 | 18 | evaluate: function(node) { 19 | var handler = undefined; 20 | var get = function(obj, name) { 21 | if (obj.hasOwnProperty(name)) { return obj[name]; } 22 | return undefined; 23 | }; 24 | 25 | if (utils.isType(node.object, 'MemberExpression')) { 26 | var newNode = module.exports.evaluate(node.object); 27 | if (newNode !== node.object) { 28 | node.object = newNode; 29 | newNode.parent = node; 30 | } 31 | } 32 | 33 | // Handle Array.prototype.slice.call(...) 34 | if (utils.isId(node.property, 'call') && 35 | utils.isType(node.object, 'MemberExpression') && 36 | utils.isType(node.object.object, 'MemberExpression') && 37 | utils.isId(node.object.object.object, /^(Array)$/) && 38 | utils.isId(node.object.object.property, 'prototype')) { 39 | var type = node.object.object.object.name; 40 | var method = node.object.property.name; 41 | var longName = type + '#' + method; 42 | handler = get(_array, longName); 43 | if (handler) { 44 | // move the 1st argument to be the reciever 45 | var args = utils.clone(node.parent.arguments); 46 | var thisArg = args.shift(); 47 | node = { 48 | type: 'CallExpression', 49 | callee: { 50 | type: 'MemberExpression', 51 | object: thisArg, 52 | property: node.object.property, 53 | isCallee: true, 54 | }, 55 | arguments: args, 56 | parent: node.parent, 57 | }; 58 | node.parent.arguments = false; 59 | } 60 | } 61 | 62 | if (utils.isType(node.object, 'Literal')) { 63 | var method = node.property.name; 64 | if (!(utils.isType(node.parent, 'CallExpression') && node === node.parent.callee)) { 65 | method = '.' + method; 66 | } 67 | handler = node.object.regex ? get(_regexp, method) : get(_string, method); 68 | } else if (utils.isId(node.object, /^(Array|Date|JSON|Math|Object|Promise|console)$/)) { 69 | var longName = node.object.name + '.' + node.property.name; 70 | handler = get(_array, longName) || get(_date, longName) || get(_json, longName) || get(_math, longName) || get(_object, longName) || get(_promise, longName) || get(_console, longName); 71 | } else if (utils.isType(node.property, 'Identifier')) { 72 | var method = node.property.name; 73 | if (!(utils.isType(node.parent, 'CallExpression') && node === node.parent.callee)) { 74 | method = '.' + method; 75 | } 76 | // _array should be before _string here so we pick up the correct 77 | // multitype version of #length and #indexOf 78 | 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); 79 | } else if (node.callee) { 80 | handler = get(_global, node.callee.name); 81 | } 82 | 83 | if (handler) { 84 | node = handler(node); 85 | node.scope = scope.create(node); 86 | } 87 | 88 | return node; 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /core/array.js: -------------------------------------------------------------------------------- 1 | var utils = require('../utils'), 2 | scope = require('../scope'); 3 | string = require('./string'); 4 | 5 | module.exports = { 6 | 'Array.isArray': function(node) { 7 | var args = utils.clone(node.parent.arguments); 8 | node.parent.arguments = false; 9 | return { 10 | type: 'CallExpression', 11 | callee: { 12 | type: 'Identifier', 13 | name: 'is_array', 14 | }, 15 | arguments: args, 16 | }; 17 | }, 18 | 19 | unshift: function(node) { 20 | var args = utils.clone(node.parent.arguments); 21 | node.parent.arguments = false; 22 | if (args.length === 1) { args[0].suppressParens = true; } 23 | args.unshift(node.parent.callee.object); 24 | scope.get(node).getDefinition(node.parent.callee.object); 25 | 26 | return { 27 | type: 'CallExpression', 28 | callee: { 29 | type: 'Identifier', 30 | name: 'array_unshift', 31 | }, 32 | arguments: args, 33 | }; 34 | }, 35 | 36 | shift: function(node) { 37 | node.parent.arguments = false; 38 | scope.get(node).getDefinition(node.parent.callee.object); 39 | return { 40 | type: 'CallExpression', 41 | callee: { 42 | type: 'Identifier', 43 | name: 'array_shift', 44 | }, 45 | arguments: [ node.parent.callee.object ] 46 | }; 47 | }, 48 | 49 | reverse: function(node) { 50 | node.parent.arguments = false; 51 | scope.get(node).getDefinition(node.parent.callee.object); 52 | return { 53 | type: 'CallExpression', 54 | callee: { 55 | type: 'Identifier', 56 | name: 'array_reverse', 57 | }, 58 | arguments: [ node.parent.callee.object ] 59 | }; 60 | }, 61 | 62 | push: function(node) { 63 | var args = utils.clone(node.parent.arguments); 64 | node.parent.arguments = false; 65 | scope.get(node).getDefinition(node.parent.callee.object); 66 | if (args.length === 1) { args[0].suppressParens = true; } 67 | args.unshift(node.parent.callee.object); 68 | 69 | return { 70 | type: 'CallExpression', 71 | callee: { 72 | type: 'Identifier', 73 | name: 'array_push', 74 | }, 75 | arguments: args, 76 | }; 77 | }, 78 | 79 | pop: function(node) { 80 | node.parent.arguments = false; 81 | scope.get(node).getDefinition(node.parent.callee.object); 82 | return { 83 | type: 'CallExpression', 84 | callee: { 85 | type: 'Identifier', 86 | name: 'array_pop', 87 | }, 88 | arguments: [ node.parent.callee.object ] 89 | }; 90 | }, 91 | 92 | join: function(node) { 93 | var args = utils.clone(node.parent.arguments); 94 | node.parent.arguments = false; 95 | scope.get(node).getDefinition(node.parent.callee.object); 96 | args[0].suppressParens = true; 97 | 98 | return { 99 | type: 'CallExpression', 100 | callee: { 101 | type: 'Identifier', 102 | name: 'implode', 103 | }, 104 | arguments: [ args[0], node.parent.callee.object ] 105 | }; 106 | }, 107 | 108 | map: function(node) { 109 | var args = utils.clone(node.parent.arguments); 110 | node.parent.arguments = false; 111 | scope.get(node).getDefinition(node.parent.callee.object); 112 | args[0].suppressParens = true; 113 | 114 | return { 115 | type: 'CallExpression', 116 | callee: { 117 | type: 'Identifier', 118 | name: 'array_map', 119 | }, 120 | arguments: [ node.parent.callee.object, args[0] ] 121 | }; 122 | }, 123 | 124 | reduce: function(node) { 125 | var args = utils.clone(node.parent.arguments); 126 | node.parent.arguments = false; 127 | scope.get(node).getDefinition(node.parent.callee.object); 128 | if (args.length === 1) { 129 | args[0].suppressParens = true; 130 | } 131 | args.unshift(node.parent.callee.object); 132 | 133 | return { 134 | type: 'CallExpression', 135 | callee: { 136 | type: 'Identifier', 137 | name: 'array_reduce', 138 | }, 139 | arguments: args, 140 | }; 141 | }, 142 | 143 | slice: function(node) { 144 | var args = utils.clone(node.parent.arguments); 145 | if (node.parent.arguments.length > 1) { 146 | // Second argument to array_slice is very different from Array#slice 147 | // unless it is negative. 148 | if (args[1].type === 'UnaryExpression' && args[1].operator==='-' && 149 | args[1].argument.type==='Literal') { 150 | /* this is okay */ 151 | } else { 152 | args[1].trailingComments = [{ type: 'Block', value: 'CHECK THIS'}]; 153 | } 154 | } else if (node.parent.arguments.length === 0) { 155 | args.unshift({ type: 'Literal', value: 0, raw: '0' }); 156 | } else { 157 | args[0].suppressParens = true; 158 | } 159 | args.unshift(node.parent.callee.object); 160 | node.parent.arguments = false; 161 | scope.get(node).getDefinition(node.parent.callee.object); 162 | 163 | return { 164 | type: 'CallExpression', 165 | callee: { 166 | type: 'Identifier', 167 | name: 'array_slice', 168 | }, 169 | arguments: args 170 | }; 171 | }, 172 | 173 | splice: function(node) { 174 | var args = utils.clone(node.parent.arguments); 175 | args.unshift(node.parent.callee.object); 176 | node.parent.arguments = false; 177 | scope.get(node).getDefinition(node.parent.callee.object); 178 | 179 | return { 180 | type: 'CallExpression', 181 | callee: { 182 | type: 'Identifier', 183 | name: 'array_splice', 184 | }, 185 | arguments: args 186 | }; 187 | }, 188 | 189 | indexOf: function(node) { 190 | var method = "array_search", 191 | args = utils.clone(node.parent.arguments); 192 | 193 | node.parent.arguments = false; 194 | scope.get(node).getDefinition(node.parent.callee.object); 195 | args[0].suppressParens = true; 196 | 197 | var targetDefinition = scope.get(node).getDefinition(node.parent.callee.object); 198 | if (utils.isString(node.parent.callee.object) || (targetDefinition && targetDefinition.dataType == "String")) { 199 | method = "strpos"; 200 | args = [ node.parent.callee.object, args[0] ]; 201 | 202 | } else { 203 | args = [ args[0], node.parent.callee.object ]; 204 | } 205 | 206 | return { 207 | type: 'CallExpression', 208 | callee: { 209 | type: 'Identifier', 210 | name: method, 211 | }, 212 | arguments: args 213 | }; 214 | 215 | }, 216 | 217 | '.length': function(node) { 218 | var method, 219 | object = (node.parent.callee && node.parent.callee.object) || node.object, 220 | isString = utils.isString(object); 221 | 222 | var targetDefinition = scope.get(node).getDefinition(object); 223 | 224 | if (!isString && targetDefinition) { 225 | if (utils.isId(targetDefinition, "string")) { 226 | isString = true; 227 | } else if (targetDefinition.dataType == "String") { 228 | isString = true; 229 | } else if(targetDefinition.type == "Identifier" && targetDefinition.parent.type == "AssignmentExpression") { 230 | isString = utils.isString(targetDefinition.parent.right); 231 | } 232 | } 233 | 234 | if (isString || (targetDefinition && targetDefinition.dataType == "String")) { 235 | method = "strlen"; 236 | } else { 237 | method = "count"; 238 | } 239 | 240 | return { 241 | type: 'CallExpression', 242 | callee: { 243 | type: 'Identifier', 244 | name: method, 245 | }, 246 | arguments: [ object ] 247 | }; 248 | }, 249 | 250 | }; 251 | 252 | utils.coreAddHash(module.exports, 'Array'); 253 | -------------------------------------------------------------------------------- /core/console.js: -------------------------------------------------------------------------------- 1 | var utils = require('../utils'); 2 | 3 | module.exports = { 4 | 'console.assert': function(node) { 5 | return { 6 | type: 'MemberExpression', 7 | object: { 8 | type: 'Identifier', 9 | name: 'Assert', 10 | }, 11 | property: { 12 | type: 'Identifier', 13 | name: 'invariant', 14 | } 15 | }; 16 | } 17 | }; 18 | 19 | utils.coreAddHash(module.exports, 'console'); 20 | -------------------------------------------------------------------------------- /core/date.js: -------------------------------------------------------------------------------- 1 | var utils = require('../utils'); 2 | 3 | module.exports = { 4 | 5 | 'Date.now': function(node) { 6 | var args = utils.clone(node.parent.arguments); 7 | node.parent.arguments = false; 8 | 9 | return { 10 | type: 'CallExpression', 11 | callee: { 12 | type: 'Identifier', 13 | name: 'time', 14 | }, 15 | arguments: [] 16 | }; 17 | } 18 | 19 | }; 20 | 21 | utils.coreAddHash(module.exports, 'Date'); 22 | -------------------------------------------------------------------------------- /core/function.js: -------------------------------------------------------------------------------- 1 | var utils = require('../utils'); 2 | 3 | function apply(node, isCall) { 4 | var method, arguments = []; 5 | 6 | if (node.object.property) { 7 | node.object.property.type = "Literal" 8 | node.object.property.raw = "'"+node.object.property.name+"'"; 9 | 10 | arguments.push({ 11 | type: "ArrayExpression", 12 | elements: [ node.object.object, node.object.property ] 13 | }) 14 | } else { 15 | node.object.type = "Literal" 16 | node.object.raw = "'"+node.object.name+"'"; 17 | arguments.push(node.object); 18 | } 19 | 20 | // remove first argument, which overrides the this 21 | node.parent.arguments.shift(); 22 | 23 | if (isCall) { 24 | // .call use call_user_func 25 | method = "call_user_func"; 26 | arguments = arguments.concat(node.parent.arguments); 27 | } else { 28 | // .apply use call_user_func_array 29 | method = "call_user_func_array"; 30 | if (node.parent.arguments[0]) { 31 | arguments.push(node.parent.arguments[0]); 32 | } else { 33 | arguments.push({ 34 | type: "ArrayExpression", 35 | elements: [], 36 | }); 37 | } 38 | } 39 | 40 | node.parent.arguments = false; 41 | 42 | return { 43 | type: 'CallExpression', 44 | callee: { 45 | type: 'Identifier', 46 | name: method, 47 | }, 48 | arguments: arguments 49 | }; 50 | } 51 | 52 | module.exports = { 53 | 54 | call: function(node) { 55 | return apply(node, true); 56 | }, 57 | 58 | apply: function(node, isCall) { 59 | return apply(node, false) 60 | }, 61 | 62 | }; 63 | 64 | utils.coreAddHash(module.exports, 'Function'); 65 | -------------------------------------------------------------------------------- /core/global.js: -------------------------------------------------------------------------------- 1 | var utils = require('../utils'); 2 | 3 | module.exports = { 4 | 5 | parseInt: function(node) { 6 | var newNode = utils.clone(node); 7 | newNode.callee.name = "intval"; 8 | return newNode; 9 | }, 10 | 11 | parseFloat: function(node) { 12 | var newNode = utils.clone(node); 13 | newNode.callee.name = "floatval"; 14 | return newNode; 15 | } 16 | 17 | }; 18 | -------------------------------------------------------------------------------- /core/json.js: -------------------------------------------------------------------------------- 1 | var utils = require('../utils'); 2 | 3 | function isJSONClass(node) { 4 | return node.object.name == "JSON"; 5 | } 6 | 7 | module.exports = { 8 | 9 | 'JSON.stringify': function(node) { 10 | var args = utils.clone(node.parent.arguments); 11 | node.parent.arguments = false; 12 | 13 | return { 14 | type: 'CallExpression', 15 | callee: { 16 | type: 'Identifier', 17 | name: 'json_encode', 18 | }, 19 | arguments: args 20 | }; 21 | }, 22 | 23 | 'JSON.parse': function(node) { 24 | var args = utils.clone(node.parent.arguments); 25 | node.parent.arguments = false; 26 | 27 | return { 28 | type: 'CallExpression', 29 | callee: { 30 | type: 'Identifier', 31 | name: 'json_decode', 32 | }, 33 | arguments: args, 34 | forceSkip: true 35 | }; 36 | }, 37 | 38 | }; 39 | 40 | utils.coreAddHash(module.exports, 'JSON'); 41 | -------------------------------------------------------------------------------- /core/math.js: -------------------------------------------------------------------------------- 1 | var utils = require('../utils'); 2 | 3 | function isMathClass(node) { 4 | return node.object.name == "Math"; 5 | } 6 | 7 | function constant(node, name) { 8 | if (isMathClass(node)) { 9 | return { type: 'Identifier', name: name, static: true }; 10 | } else { 11 | return node; 12 | } 13 | } 14 | 15 | function method(node, name) { 16 | if (isMathClass(node) && node.parent.type === 'CallExpression') { 17 | var args = utils.clone(node.parent.arguments); 18 | node.parent.arguments = false; 19 | return { type: 'CallExpression', callee: { type: 'Identifier', name: name, }, arguments: args }; 20 | } else { 21 | return node; 22 | } 23 | } 24 | 25 | module.exports = { 26 | 27 | // constants 28 | 'Math.E': function(node) { return constant(node, 'M_E'); }, 29 | 'Math.LN2': function(node) { return constant(node, 'M_LN2'); }, 30 | 'Math.LN10': function(node) { return constant(node, 'M_LN10'); }, 31 | 'Math.LOG2E': function(node) { return constant(node, 'M_LOG2E'); }, 32 | 'Math.LOG10E': function(node) { return constant(node, 'M_LOG10E'); }, 33 | 'Math.PI': function(node) { return constant(node, 'M_PI'); }, 34 | 'Math.SQRT2': function(node) { return constant(node, 'M_SQRT2'); }, 35 | 'Math.SQRT1_2': function(node) { return constant(node, 'M_SQRT1_2'); }, 36 | 37 | // methods 38 | 'Math.abs': function(node) { return method(node, 'abs'); }, 39 | 'Math.acos': function(node) { return method(node, 'acos'); }, 40 | 'Math.acosh': function(node) { return method(node, 'acosh'); }, 41 | 'Math.asin': function(node) { return method(node, 'asin'); }, 42 | 'Math.asinh': function(node) { return method(node, 'asinh'); }, 43 | 'Math.atan': function(node) { return method(node, 'atan'); }, 44 | 'Math.atanh': function(node) { return method(node, 'atanh'); }, 45 | 'Math.atan2': function(node) { return method(node, 'atan2'); }, 46 | 'Math.cbrt': function(node) { return method(node, 'cbrt'); }, 47 | 'Math.ceil': function(node) { return method(node, 'ceil'); }, 48 | 'Math.clz32': function(node) { return method(node, 'clz32'); }, 49 | 'Math.cos': function(node) { return method(node, 'cos'); }, 50 | 'Math.cosh': function(node) { return method(node, 'cosh'); }, 51 | 'Math.exp': function(node) { return method(node, 'exp'); }, 52 | 'Math.expm1': function(node) { return method(node, 'expm1'); }, 53 | 'Math.floor': function(node) { return method(node, 'floor'); }, 54 | // fround: function(node) { return method(node, 'fround'); }, 55 | 'Math.hypot': function(node) { return method(node, 'hypot'); }, 56 | // imul: function(node) { return method(node, 'imul'); }, 57 | 'Math.log': function(node) { return method(node, 'log'); }, 58 | 'Math.log1p': function(node) { return method(node, 'log1p'); }, 59 | 'Math.log10': function(node) { return method(node, 'log10'); }, 60 | // log2: function(node) { return method(node, 'log2'); }, 61 | 'Math.max': function(node) { return method(node, 'max'); }, 62 | 'Math.min': function(node) { return method(node, 'min'); }, 63 | 'Math.pow': function(node) { return method(node, 'pow'); }, 64 | 'Math.random': function(node) { return method(node, 'rand'); }, 65 | 'Math.round': function(node) { return method(node, 'round'); }, 66 | // sign: function(node) { return method(node, 'sign'); }, 67 | 'Math.sin': function(node) { return method(node, 'sin'); }, 68 | 'Math.sinh': function(node) { return method(node, 'sinh'); }, 69 | 'Math.sqrt': function(node) { return method(node, 'sqrt'); }, 70 | 'Math.tan': function(node) { return method(node, 'tan'); }, 71 | 'Math.tanh': function(node) { return method(node, 'tanh'); }, 72 | // trunc: function(node) { return method(node, 'trunc'); }, 73 | 74 | 75 | }; 76 | 77 | utils.coreAddHash(module.exports, 'Math'); 78 | -------------------------------------------------------------------------------- /core/number.js: -------------------------------------------------------------------------------- 1 | var utils = require('../utils'); 2 | 3 | function isNumberClass(node) { 4 | return node.object.name == "Number"; 5 | } 6 | 7 | function constant(node, name) { 8 | if (isNumberClass(node)) { 9 | return { type: 'Identifier', name: name, static: true }; 10 | } else { 11 | return node; 12 | } 13 | } 14 | 15 | function method(node, name) { 16 | if (isNumberClass(node)) { 17 | var args = utils.clone(node.parent.arguments); 18 | node.parent.arguments = false; 19 | return { type: 'CallExpression', callee: { type: 'Identifier', name: name, }, arguments: args }; 20 | } else { 21 | return node; 22 | } 23 | } 24 | 25 | module.exports = { 26 | 27 | isInteger: function(node) { return method(node, 'is_int'); }, 28 | isFinite: function(node) { return method(node, 'is_finite'); }, 29 | 30 | }; 31 | 32 | utils.coreAddHash(module.exports, 'Number'); 33 | -------------------------------------------------------------------------------- /core/object.js: -------------------------------------------------------------------------------- 1 | var utils = require('../utils'); 2 | 3 | module.exports = { 4 | 'Object.create': function(node) { 5 | var args = utils.clone(node.parent.arguments); 6 | if (args.length === 1 && args[0].type === 'Literal' && args[0].value === null) { 7 | node.parent.arguments = false; 8 | return { 9 | type: 'ObjectExpression', 10 | properties: [], 11 | }; 12 | }; 13 | return node; 14 | } 15 | }; 16 | 17 | utils.coreAddHash(module.exports, 'Object'); 18 | -------------------------------------------------------------------------------- /core/promise.js: -------------------------------------------------------------------------------- 1 | var utils = require('../utils'); 2 | 3 | module.exports = { 4 | 'Promise.async': function(node) { 5 | var args = utils.clone(node.parent.arguments); 6 | if (args.length === 1) { 7 | node.parent.arguments = false; 8 | args[0].suppressParens = true; 9 | args[0].leadingComments = args[0].leadingComments || []; 10 | args[0].leadingComments.push({ type: 'Block', value: ' async ' }); 11 | return args[0]; 12 | }; 13 | return node; 14 | } 15 | }; 16 | 17 | utils.coreAddHash(module.exports, 'Promise'); 18 | -------------------------------------------------------------------------------- /core/regexp.js: -------------------------------------------------------------------------------- 1 | var utils = require('../utils'), 2 | scope = require('../scope'); 3 | 4 | module.exports = { 5 | exec: function(node) { 6 | var args = utils.clone(node.parent.arguments); 7 | if (utils.isType(node.parent.callee.object, "Literal") && 8 | node.parent.callee.object.regex) { 9 | node.parent.arguments = false; 10 | args[0].suppressParens = true; 11 | var regexpData = node.parent.callee.object.raw 12 | .match(/^\/((?:[^\/]|\\.)+)\/([gimy]+)?$/); 13 | var pattern = (regexpData && regexpData[1]); 14 | var flags = (regexpData && regexpData[2]) || ""; 15 | var isGroup = flags.indexOf('g') >= 0; 16 | var lit = node.parent.callee.object; 17 | if (isGroup) { flags = flags.replace(/g/g, ''); } 18 | lit.value = '/' + pattern + '/' + flags; 19 | lit.raw = utils.stringify(lit.value); 20 | lit.regex = undefined; 21 | return { 22 | type: 'CallExpression', 23 | callee: { 24 | type: 'Identifier', 25 | name: isGroup ? 'preg_match_all' : 'preg_match', 26 | }, 27 | arguments: [ node.parent.callee.object, args[0], { 28 | type: 'Identifier', 29 | name: 'FIXME', 30 | }], 31 | leadingComments: [{ type: 'Block', value: 'RegExp#exec' }], 32 | }; 33 | } else { 34 | return node; 35 | } 36 | }, 37 | 38 | '.source': function(node) { 39 | if (utils.isType(node.object, "Literal") && node.object.regex) { 40 | node.object.value = node.object.regex.pattern; 41 | node.object.raw = utils.stringify(node.object.value); 42 | node.object.regex = undefined; 43 | return node.object; 44 | } else { 45 | return node; 46 | } 47 | }, 48 | 49 | test: function(node) { 50 | var args = utils.clone(node.parent.arguments); 51 | node.parent.arguments = false; 52 | scope.get(node).getDefinition(node.parent.callee.object); 53 | args[0].suppressParens = true; 54 | if (utils.isType(node.parent.callee.object, "Literal") && 55 | node.parent.callee.object.regex) { 56 | var lit = node.parent.callee.object; 57 | if (lit.value.source) { 58 | lit.value = '/' + lit.value.source + '/'; 59 | } else { 60 | lit.value = lit.raw; 61 | } 62 | lit.raw = utils.stringify(lit.value); 63 | lit.regex = undefined; 64 | return { 65 | type: 'CallExpression', 66 | callee: { 67 | type: 'Identifier', 68 | name: 'preg_match', 69 | }, 70 | arguments: [ node.parent.callee.object, args[0] ], 71 | }; 72 | } else { 73 | return { 74 | type: 'CallExpression', 75 | callee: { 76 | type: 'Identifier', 77 | name: 'preg_match', 78 | }, 79 | arguments: [ node.parent.callee.object, args[0] ], 80 | }; 81 | } 82 | }, 83 | }; 84 | 85 | utils.coreAddHash(module.exports, 'RegExp'); 86 | -------------------------------------------------------------------------------- /core/string.js: -------------------------------------------------------------------------------- 1 | var utils = require('../utils'), 2 | scope = require('../scope'); 3 | 4 | module.exports = { 5 | 6 | // 7 | // string methods 8 | // 9 | indexOf: function(node) { 10 | var args = utils.clone(node.parent.arguments); 11 | node.parent.arguments = false; 12 | scope.get(node).getDefinition(node.parent.callee.object); 13 | if (args.length === 1) { args[0].suppressParens = true; } 14 | args.unshift(node.parent.callee.object); 15 | 16 | return { 17 | type: 'CallExpression', 18 | callee: { 19 | type: 'Identifier', 20 | name: 'strpos', 21 | }, 22 | arguments: args 23 | }; 24 | }, 25 | 26 | '.length': function(node) { 27 | var object = (node.parent.callee && node.parent.callee.object) || node.object; 28 | return { 29 | type: 'CallExpression', 30 | callee: { 31 | type: 'Identifier', 32 | name: 'strlen', 33 | }, 34 | arguments: [object], 35 | }; 36 | }, 37 | 38 | replace: function(node) { 39 | var method = "str_replace"; 40 | var args = utils.clone(node.parent.arguments); 41 | args.push(node.parent.callee.object) 42 | node.parent.arguments = false; 43 | scope.get(node).getDefinition(node.parent.callee.object); 44 | 45 | if(args[0].type === 'Literal'){ 46 | var regexpData = args[0].raw.match(/^\/((?:[^\/]|\\.)+)\/([gimy]+)?$/), 47 | regex = regexpData && regexpData[1], 48 | flags = regexpData && regexpData[2] || "", 49 | isGroup = flags.indexOf('g') >= 0; 50 | 51 | // check for RegExp for preg_replace 52 | if (regexpData) { 53 | method = "preg_replace"; 54 | args[0].value = "/" + regex + "/" + flags.replace("g", ""); 55 | args[0].raw = utils.stringify(args[0].value); 56 | args[0].type = "Literal"; 57 | args[0].regex = false; 58 | 59 | // fill '$limit' param with only 1 replacement 60 | // http://php.net/manual/en/function.preg-replace.php 61 | if (!isGroup) { 62 | args.push({ type: 'Literal', value: 1, raw: '1' }); 63 | } 64 | } 65 | } 66 | 67 | return { 68 | type: 'CallExpression', 69 | callee: { 70 | type: 'Identifier', 71 | name: method, 72 | }, 73 | arguments: args 74 | }; 75 | }, 76 | 77 | slice: function(node) { 78 | var args = utils.clone(node.parent.arguments); 79 | if (node.parent.arguments.length > 1) { 80 | // Second argument to substr is very different from String#slice 81 | // unless it is negative. 82 | if (args[1].type === 'UnaryExpression' && args[1].operator==='-' && 83 | args[1].argument.type==='Literal') { 84 | /* this is okay */ 85 | } else { 86 | args[1].trailingComments = [{ type: 'Block', value: 'CHECK THIS'}]; 87 | } 88 | } else { 89 | args[0].suppressParens = true; 90 | } 91 | args.unshift(node.parent.callee.object); 92 | node.parent.arguments = false; 93 | scope.get(node).getDefinition(node.parent.callee.object); 94 | 95 | return { 96 | type: 'CallExpression', 97 | callee: { 98 | type: 'Identifier', 99 | name: 'substr', 100 | }, 101 | arguments: args 102 | }; 103 | }, 104 | 105 | substr: function(node) { 106 | // This method is deprecated/discouraged in JS, but maps best to the PHP 107 | // function. 108 | var args = utils.clone(node.parent.arguments); 109 | if (node.parent.arguments.length === 1) { 110 | args[0].suppressParens = true; 111 | } 112 | args.unshift(node.parent.callee.object); 113 | node.parent.arguments = false; 114 | scope.get(node).getDefinition(node.parent.callee.object); 115 | 116 | return { 117 | type: 'CallExpression', 118 | callee: { 119 | type: 'Identifier', 120 | name: 'substr', 121 | }, 122 | arguments: args 123 | }; 124 | }, 125 | 126 | substring: function(node) { 127 | var args = utils.clone(node.parent.arguments); 128 | if (node.parent.arguments.length > 1) { 129 | // Second argument to substr is very different from String#substring 130 | // (And String#substring is almost-but-not-quite-like String#slice) 131 | args[1].trailingComments = [{ type: 'Block', value: 'CHECK THIS'}]; 132 | } else { 133 | args[0].suppressParens = true; 134 | } 135 | args.unshift(node.parent.callee.object); 136 | node.parent.arguments = false; 137 | scope.get(node).getDefinition(node.parent.callee.object); 138 | 139 | return { 140 | type: 'CallExpression', 141 | callee: { 142 | type: 'Identifier', 143 | name: 'substr', 144 | }, 145 | arguments: args 146 | }; 147 | }, 148 | 149 | trim: function(node) { 150 | node.parent.arguments = false; 151 | scope.get(node).getDefinition(node.parent.callee.object); 152 | 153 | return { 154 | type: 'CallExpression', 155 | callee: { 156 | type: 'Identifier', 157 | name: 'trim', 158 | }, 159 | arguments: [ node.parent.callee.object ] 160 | }; 161 | }, 162 | 163 | trimRight: function(node) { 164 | node.parent.arguments = false; 165 | scope.get(node).getDefinition(node.parent.callee.object); 166 | 167 | return { 168 | type: 'CallExpression', 169 | callee: { 170 | type: 'Identifier', 171 | name: 'rtrim', 172 | }, 173 | arguments: [ node.parent.callee.object ] 174 | }; 175 | }, 176 | 177 | trimLeft: function(node) { 178 | node.parent.arguments = false; 179 | scope.get(node).getDefinition(node.parent.callee.object); 180 | 181 | return { 182 | type: 'CallExpression', 183 | callee: { 184 | type: 'Identifier', 185 | name: 'ltrim', 186 | }, 187 | arguments: [ node.parent.callee.object ] 188 | }; 189 | }, 190 | 191 | toUpperCase: function(node) { 192 | node.parent.arguments = false; 193 | scope.get(node).getDefinition(node.parent.callee.object); 194 | 195 | return { 196 | type: 'CallExpression', 197 | callee: { 198 | type: 'Identifier', 199 | name: 'strtoupper', 200 | }, 201 | arguments: [ node.parent.callee.object ] 202 | }; 203 | }, 204 | 205 | toLowerCase: function(node) { 206 | node.parent.arguments = false; 207 | scope.get(node).getDefinition(node.parent.callee.object); 208 | 209 | return { 210 | type: 'CallExpression', 211 | callee: { 212 | type: 'Identifier', 213 | name: 'strtolower', 214 | }, 215 | arguments: [ node.parent.callee.object ] 216 | }; 217 | }, 218 | 219 | split: function(node) { 220 | var method = "explode"; 221 | var args = utils.clone(node.parent.arguments); 222 | args.push(node.parent.callee.object); 223 | node.parent.arguments = false; 224 | scope.get(node).getDefinition(node.parent.callee.object); 225 | 226 | var regexpData = args[0].type==='Literal' && 227 | args[0].raw.match(/^\/((?:[^\/]|\\.)+)\/([gimy]+)?$/), 228 | regex = regexpData && regexpData[1], 229 | flags = regexpData && regexpData[2] || ""; 230 | 231 | // check for RegExp for preg_replace 232 | if (regexpData) { 233 | method = "preg_split"; 234 | args[0].value = "/" + regex + "/" + flags.replace("g", ""); 235 | args[0].raw = utils.stringify(args[0].value); 236 | args[0].type = "Literal"; 237 | args[0].regex = false; 238 | if (args.length === 2) { 239 | args[0].suppressParens = true; 240 | } 241 | } 242 | // If splitting with a blank delimiter, use str_split. 243 | else if (args[0].value === '') { 244 | method = "str_split"; 245 | args = [args[1]]; 246 | } else if (args.length == 2) { 247 | args[0].suppressParens = true; 248 | } 249 | 250 | return { 251 | type: 'CallExpression', 252 | callee: { 253 | type: 'Identifier', 254 | name: method, 255 | }, 256 | arguments: args 257 | }; 258 | }, 259 | 260 | substr: function(node) { 261 | var args = utils.clone(node.parent.arguments); 262 | node.parent.arguments = false; 263 | scope.get(node).getDefinition(node.parent.callee.object); 264 | if (args.length === 1) { args[0].suppressParens = true; } 265 | args.unshift(node.parent.callee.object); 266 | 267 | return { 268 | type: 'CallExpression', 269 | callee: { 270 | type: 'Identifier', 271 | name: 'substr', 272 | }, 273 | arguments: args 274 | }; 275 | }, 276 | 277 | match: function(node) { 278 | var args = utils.clone(node.parent.arguments); 279 | args[0].suppressParens = true; 280 | args.push(node.parent.callee.object); 281 | 282 | if(args[0].type === 'Literal') { 283 | 284 | var regexpData = args[0].regex && 285 | args[0].raw.match(/^\/((?:[^\/]|\\.)+)\/([gimy]+)?$/), 286 | pattern = regexpData && regexpData[1], 287 | flags = regexpData && regexpData[2] || "", 288 | isGroup = flags.indexOf('g') >= 0; 289 | 290 | // String#match can be called with a raw string as well. 291 | if ((!args[0].regex) && typeof args[0].value === 'string') { 292 | var r = new RegExp(args[0].value); 293 | pattern = r.source; 294 | flags = ''; 295 | isGroup = false; 296 | } 297 | // remove unsupported /g from regexp, to use preg_match_all 298 | if (isGroup) { flags = flags.replace(/g/g, ''); } 299 | args[0].value = '/' + pattern + '/' + flags; 300 | args[0].raw = utils.stringify(args[0].value); 301 | args[0].type = "Literal"; 302 | args[0].regex = undefined; 303 | } 304 | 305 | node.parent.arguments = false; 306 | scope.get(node).getDefinition(node.parent.callee.object); 307 | if (isGroup) { 308 | // results come back in this out-argument 309 | args.push({ type: 'Identifier', name: 'FIXME' }); 310 | } 311 | 312 | return { 313 | type: 'CallExpression', 314 | callee: { 315 | type: 'Identifier', 316 | name: (isGroup) ? 'preg_match_all' : 'preg_match', 317 | }, 318 | arguments: args 319 | }; 320 | 321 | }, 322 | 323 | }; 324 | 325 | utils.coreAddHash(module.exports, 'String'); 326 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var core = require('./core'), 2 | scope = require('./scope'), 3 | utils = require('./utils'), 4 | espree = require('espree'); 5 | 6 | module.exports = function(code, options) { 7 | options = options || {}; 8 | if (options.braced) { 9 | // special option to handle code inside braced regions only 10 | var nest = 0, quote = null, outside = '', inside = ''; 11 | var noptions = Object.assign({}, options, { 12 | braced: false, watermark: false, noOpenTag: true, indent: 1, 13 | }); 14 | if (options.watermark) { outside += `/* ${options.watermark} */\n`; } 15 | code.split( 16 | // /([{}]|\/\*(?:(?!\*\/).)*\*\/|\/\/[^\n]*(?:\n|$)|"[^"]*"|'[^']'|\[[^\]]*\])/mg 17 | /([{}'"\[\]]|\/\*|\*\/|\/\/|\n)/g 18 | ).forEach(function(chunk) { 19 | var isStartQuote = (nest === 0) && 20 | (chunk==='"' || chunk==="'" || chunk==='[' || chunk==='/*' || chunk==='//'); 21 | if (quote || isStartQuote) { 22 | var trailingBackslash = outside.endsWith('\\'); 23 | outside += chunk; 24 | if (chunk === quote && !trailingBackslash) { quote = null; } 25 | else if (!quote) { 26 | switch (chunk) { 27 | case '/*' : quote = '*/'; break; 28 | case '//': quote = '\n'; break; 29 | case '[': quote = ']'; break; 30 | default: quote = chunk; break; 31 | } 32 | } 33 | return; 34 | } 35 | if (chunk==='}') { nest--; } 36 | if (nest <= 0) { 37 | if (inside) { 38 | outside += module.exports(inside, noptions); 39 | inside = ''; 40 | } 41 | outside += chunk; 42 | nest = 0; 43 | } else { 44 | inside += chunk; 45 | } 46 | if (chunk==='{') { nest++; } 47 | }); 48 | if (inside) { outside += module.exports(inside, noptions); } 49 | return outside; 50 | } 51 | var useConciseArrays = (options.conciseArrays === false) ? false : true; 52 | var ast = espree.parse(code, { 53 | loc : true, 54 | range : true, 55 | tokens : true, 56 | comment : true, 57 | attachComment: true, 58 | ecmaFeatures: { 59 | arrowFunctions: true, // enable parsing of arrow functions 60 | blockBindings: true, // enable parsing of let/const 61 | destructuring: true, // enable parsing of destructured arrays and objects 62 | regexYFlag: true, // enable parsing of regular expression y flag 63 | regexUFlag: true, // enable parsing of regular expression u flag 64 | templateStrings: true, // enable parsing of template strings 65 | binaryLiterals: true, // enable parsing of binary literals 66 | octalLiterals: true, // enable parsing of ES6 octal literals 67 | unicodeCodePointEscapes: true, // enable parsing unicode code point escape sequences 68 | defaultParams: true, // enable parsing of default parameters 69 | restParams: true, // enable parsing of rest parameters 70 | forOf: true, // enable parsing of for-of statement 71 | objectLiteralComputedProperties: true, // enable parsing computed object literal properties 72 | objectLiteralShorthandMethods: true, // enable parsing of shorthand object literal methods 73 | objectLiteralShorthandProperties: true, // enable parsing of shorthand object literal properties 74 | objectLiteralDuplicateProperties: true, // Allow duplicate object literal properties (except '__proto__') 75 | generators: true, // enable parsing of generators/yield 76 | spread: true, // enable parsing spread operator 77 | superInFunctions: true, // enable super in functions 78 | classes: true, // enable parsing classes 79 | newTarget: false, // enable parsing of new.target 80 | modules: true, // enable parsing of modules 81 | jsx: true, // enable React JSX parsing 82 | globalReturn: true, // enable return in global scope 83 | experimentalObjectRestSpread: true // allow experimental object rest/spread 84 | } 85 | }); 86 | var tokenStartMap = Object.create(null), tokenEndMap = Object.create(null); 87 | var locToKey = function(loc) { 88 | return loc.line + '-' + loc.column; 89 | }; 90 | (function() { 91 | var lines = code.split(/\n/g); 92 | // slideFwd and slideBck skip over whitespace 93 | var slideFwd = function(loc) { 94 | loc = {line: loc.line, column: loc.column}; 95 | while (loc.line <= lines.length) { 96 | var l = lines[loc.line - 1]; 97 | var c = l[loc.column]; 98 | if (!/[ \t\r\n]/.test(c)) break; 99 | loc.column++; 100 | if (loc.column >= l.length) { loc.column = 0; loc.line++; } 101 | } 102 | return loc; 103 | }; 104 | var slideBck = function(loc) { 105 | loc = {line: loc.line, column: loc.column}; 106 | while (loc.line >= 1) { 107 | var l = lines[loc.line - 1]; 108 | var c = l[loc.column - 1]; 109 | if (!/[ \t\r\n]/.test(c)) break; 110 | loc.column--; 111 | if (loc.column < 0) { 112 | loc.line--; 113 | loc.column = lines[loc.line - 1].length - 1; 114 | } 115 | } 116 | return loc; 117 | }; 118 | ast.tokens.forEach(function(t) { 119 | tokenStartMap[locToKey(slideBck(t.loc.start))] = t; 120 | tokenEndMap[locToKey(slideFwd(t.loc.end))] = t; 121 | }); 122 | })(); 123 | 124 | var rootScope = scope.create(ast, scope.KIND_ROOT); 125 | function Emitter() { 126 | this.buffer = ''; 127 | this.line = 1; 128 | this.insertionPoints = []; 129 | this.indentLevel = 0; 130 | } 131 | Emitter.prototype.toString = function() { return this.buffer; }; 132 | Emitter.prototype.emit = function(str) { 133 | this.buffer += str; 134 | }; 135 | Emitter.prototype.nl = function() { 136 | this.buffer = this.buffer.replace(/[ \t]+$/, '') + '\n'; 137 | for (var i = 0; i < this.indentLevel; i++) { 138 | this.buffer += '\t'; 139 | } 140 | this.line++; 141 | } 142 | Emitter.prototype.block = function(open, f, close) { 143 | var firstline = this.line; 144 | this.emit(open); this.emit(' '); 145 | var checkpoint = this.buffer.length; 146 | this.incrIndent(); 147 | f(); 148 | if (this.line > firstline) { 149 | this.ensureNl(); 150 | } else if (this.buffer.length !== checkpoint) { 151 | this.emit(' '); 152 | } else { 153 | // no content in block => no space 154 | this.buffer = this.buffer.replace(/[\t ]+$/, ''); 155 | } 156 | this.decrIndent(); 157 | this.emit(close); 158 | }; 159 | Emitter.prototype.incrIndent = function() { 160 | this.indentLevel++; 161 | if (/\t$/.test(this.buffer)) { this.emit('\t'); } 162 | } 163 | Emitter.prototype.decrIndent = function() { 164 | this.indentLevel--; 165 | if (/\t$/.test(this.buffer)) { 166 | this.buffer = this.buffer.slice(0, this.buffer.length - 1); 167 | } 168 | } 169 | Emitter.prototype.locStart = function(node) { 170 | if (node.leadingComments && node.leadingComments.length) { 171 | node.leadingComments.forEach(function(c) { 172 | this.emitComment(c); 173 | }, this); 174 | } 175 | if (node.type === 'Program') { return; } 176 | if (node && node.loc) { 177 | while (node.loc.start.line > this.line) { 178 | this.nl(); 179 | } 180 | this.line = node.loc.start.line; 181 | } 182 | // Hack for preserving parentheses from the original 183 | if (!(node && node.suppressParens)) { 184 | var startT = node && node.loc && tokenEndMap[locToKey(node.loc.start)]; 185 | var endT = node && node.loc && tokenStartMap[locToKey(node.loc.end)]; 186 | if ( 187 | node.forceParens || 188 | (utils.isType(startT, 'Punctuator') && startT.value === '(' && 189 | utils.isType(endT, 'Punctuator') && endT.value === ')') 190 | ) { 191 | this.emit('( '); 192 | } 193 | } 194 | }; 195 | Emitter.prototype.locEnd = function(node) { 196 | // Hack for preserving parentheses from the original 197 | if (!(node && node.suppressParens)) { 198 | var startT = node && node.loc && tokenEndMap[locToKey(node.loc.start)]; 199 | var endT = node && node.loc && tokenStartMap[locToKey(node.loc.end)]; 200 | if (node.forceParens || 201 | (utils.isType(startT, 'Punctuator') && startT.value === '(' && 202 | utils.isType(endT, 'Punctuator') && endT.value === ')') 203 | ) { 204 | if (!this.endsInNl()) this.emit(' '); 205 | this.emit(')'); 206 | } 207 | } 208 | if (node && node.loc) { 209 | while (node.loc.end.line > this.line) { 210 | this.nl(); 211 | } 212 | this.line = node.loc.end.line; 213 | } 214 | if (node.trailingComments && node.trailingComments.length) { 215 | node.trailingComments.forEach(function(c) { 216 | this.emitComment(c); 217 | }, this); 218 | } 219 | }; 220 | Emitter.prototype.emitComment = function(c) { 221 | if (c.emitted) { return; } 222 | this.locStart(c); 223 | if (c.type==='Block') { 224 | this.emit('/*'); 225 | c.value.split(/\n/).forEach(function(l, idx) { 226 | if (idx > 0) { this.nl(); } 227 | this.emit(l.replace(/^\t+/, '')); 228 | }, this); 229 | this.emit('*/'); 230 | } else { 231 | this.emit('//' + c.value); this.nl(); 232 | } 233 | c.emitted = true; 234 | }; 235 | Emitter.prototype.endsInNl = function() { 236 | return /\n[ \t]*$/.test(this.buffer); 237 | }; 238 | Emitter.prototype.isSemiLast = function() { 239 | return this.buffer.match(/;\n?[ ]*$/); 240 | } 241 | Emitter.prototype.ensureSemi = function() { 242 | if (!emitter.isSemiLast()) { this.emit('; '); } 243 | }; 244 | Emitter.prototype.ensureNl = function() { 245 | if (!this.endsInNl()) { 246 | this.nl(); 247 | } 248 | }; 249 | Emitter.prototype.replaceSemiWithComma = function() { 250 | this.buffer = this.buffer.replace(/;([ \t]*)$/, ', $1'); 251 | }; 252 | Emitter.prototype.pushInsertionPoint = function() { 253 | this.insertionPoints.push(this.buffer.length); 254 | } 255 | Emitter.prototype.popInsertionPoint = function() { 256 | this.insertionPoints.pop(); 257 | } 258 | Emitter.prototype.insertAt = function(depth, str) { 259 | var idx = this.insertionPoints.length - depth - 1; 260 | var at = this.insertionPoints[idx]; 261 | this.buffer = this.buffer.slice(0, at) + str + this.buffer.slice(at); 262 | while (++idx < this.insertionPoints.length) { 263 | this.insertionPoints[idx] += str.length; 264 | } 265 | } 266 | var emitter = new Emitter(); 267 | if (options.indent) { emitter.indentLevel = options.indent; } 268 | 269 | function handleImport(parent, node) { 270 | node.declarations.forEach(function(d) { 271 | if (d.type !== 'VariableDeclarator') { return; } 272 | scope.get(parent).register(d); 273 | d.isImport = true; 274 | // the RHS is require('..some string..') but we're going to ignore that 275 | if (d.id.type === 'ObjectPattern') { 276 | emitter.locStart(d); 277 | d.id.properties.forEach(function(p, idx) { 278 | scope.get(parent).register({ 279 | type: 'VariableDeclarator', 280 | id: { type: 'Identifier', name: p.value.name }, 281 | isImport: true, 282 | }); 283 | if (idx > 0) { emitter.nl(); } 284 | var name = utils.classize(p.key.name); 285 | if (options.namespace) { name = options.namespace + "\\" + name; } 286 | emitter.emit("use " + name); 287 | if (p.key.name !== p.value.name || options.namespace) { 288 | emitter.emit(" as " + utils.classize(p.value.name)); 289 | } 290 | emitter.emit(";"); 291 | }); 292 | emitter.locEnd(d); 293 | } else if (d.id.type === 'Identifier') { 294 | var name = d.id.name; 295 | emitter.locStart(d); 296 | if (options.namespace) { 297 | emitter.emit(`use ${options.namespace}\\${name} as ${name};`); 298 | } else { 299 | emitter.emit(`use ${name};`); 300 | } 301 | emitter.locEnd(d); 302 | } 303 | }); 304 | } 305 | 306 | function visit(node, parent) { 307 | var semicolon = false; 308 | 309 | // set parent node 310 | if (parent) { node.parent = parent; } 311 | if (!node.suppressLoc) { emitter.locStart(node); } 312 | 313 | if (utils.isType(node, /^(Program|BlockStatement|ClassBody)$/)) { 314 | // Skip strictness declaration 315 | if (utils.isType(node.body[0], 'ExpressionStatement') && 316 | utils.isType(node.body[0].expression, 'Literal') && 317 | node.body[0].expression.raw.match(/^["']use strict["']$/)) { 318 | emitter.locStart(node.body[0]); // flush leading comment 319 | node.body.shift(); 320 | } 321 | if (node.type === 'Program') { 322 | if (options.namespace && !options.noOpenTag) { 323 | // Add optional namespace. 324 | emitter.emit(`namespace ${options.namespace};`); 325 | emitter.nl(); 326 | } 327 | 328 | // skip core update require 329 | while (utils.isType(node.body[0], 'ExpressionStatement') && 330 | utils.isType(node.body[0].expression, 'CallExpression') && 331 | utils.isId(node.body[0].expression.callee, 'require')) { 332 | node.body.shift(); // discard this 333 | } 334 | 335 | // Look for require declarations 336 | while (utils.isType(node.body[0], 'VariableDeclaration') && 337 | utils.isType(node.body[0].declarations[0], 'VariableDeclarator') && 338 | utils.isType(node.body[0].declarations[0].init, 'CallExpression') && 339 | utils.isId(node.body[0].declarations[0].init.callee, 'require')) { 340 | handleImport(node, node.body.shift()); 341 | } 342 | } 343 | 344 | for (var i=0,length = node.body.length;i 0 && 756 | !utils.isType(node.parent, /^(Program|MethodDefinition)$/)) { 757 | emitter.insertAt(1, "use ( " + using.map(function(identifier) { 758 | return "&$" + identifier; 759 | }).join(', ') + " ) "); 760 | } 761 | 762 | // workaround when scope doesn't allow to have the `use` keyword. 763 | if (node.parent.type === "Program") { 764 | emitter.insertAt(0, using.map(function(identifier) { 765 | return `\n\tglobal $${identifier};`; 766 | }).join('')); 767 | } 768 | 769 | if (node.expression) { 770 | // x => x * 2 771 | emitter.insertAt(0, 'return '); 772 | emitter.emit(';'); 773 | } 774 | }, '}'); 775 | emitter.popInsertionPoint(); 776 | emitter.popInsertionPoint(); 777 | 778 | } else if (node.type == "ObjectExpression") { 779 | emitter.block(useConciseArrays ? '[' : 'array(', function() { 780 | for (var i=0; i < node.properties.length; i++) { 781 | visit(node.properties[i], node); 782 | if ((i+1) < node.properties.length) { emitter.emit(', '); } 783 | } 784 | }, useConciseArrays ? ']' : ')'); 785 | 786 | } else if (node.type == "ArrayExpression") { 787 | emitter.block(useConciseArrays ? '[' : 'array(', function() { 788 | for (var i=0; i < node.elements.length; i++) { 789 | visit(node.elements[i], node); 790 | if ((i+1) < node.elements.length) { emitter.emit(', '); } 791 | } 792 | }, useConciseArrays ? ']' : ')'); 793 | 794 | } else if (node.type == "Property") { 795 | var property = (node.key.type == 'Identifier') ? node.key.name : node.key.value; 796 | if (typeof(property)==='string') { property = utils.stringify(property); } 797 | emitter.emit(String(property) + ' => '); 798 | visit(node.value, node); 799 | 800 | } else if (node.type == "ReturnStatement") { 801 | semicolon = true; 802 | emitter.emit('return'); 803 | 804 | if (node.argument) { 805 | emitter.emit(' '); 806 | visit(node.argument, node); 807 | } 808 | 809 | } else if (node.type == "ClassDeclaration") { 810 | emitter.emit("class " + node.id.name + " "); 811 | 812 | if (node.superClass) { 813 | emitter.emit("extends " + node.superClass.name + " "); 814 | } 815 | 816 | var s = scope.create(node); 817 | emitter.emit('{'); emitter.incrIndent(); 818 | visit(node.body, node); 819 | 820 | if (s.getters.length > 0) { 821 | emitter.emit("function __get($_property) "); 822 | emitter.block('{', function() { 823 | for (var i=0;i 0) { 836 | emitter.emit("function __set($_property, $value) "); 837 | emitter.block('{', function() { 838 | for (var i=0;i $___"); 1011 | }, ')'); 1012 | emitter.emit(' '); 1013 | emitter.block('{', function() { visit(node.body, node); }, '}'); 1014 | 1015 | } else if (node.type == "UpdateExpression") { 1016 | 1017 | if (node.prefix) { 1018 | emitter.emit(node.operator); 1019 | } 1020 | 1021 | visit(node.argument, node); 1022 | 1023 | if (!node.prefix) { 1024 | emitter.emit(node.operator); 1025 | } 1026 | 1027 | } else if (node.type == "SwitchStatement") { 1028 | emitter.emit("switch "); 1029 | emitter.block('(', function() { node.discriminant.suppressParens = true; visit(node.discriminant, node); }, ')'); 1030 | emitter.emit(' '); 1031 | emitter.block('{', function() { 1032 | for (var i=0; i < node.cases.length; i++) { 1033 | visit(node.cases[i], node); emitter.nl(); 1034 | } 1035 | }, '}'); 1036 | 1037 | } else if (node.type == "SwitchCase") { 1038 | 1039 | if (node.test) { 1040 | emitter.emit("case "); 1041 | visit(node.test, node); 1042 | emitter.emit(":"); 1043 | } else { 1044 | emitter.emit("default:"); 1045 | } 1046 | emitter.nl(); 1047 | 1048 | for (var i=0; i < node.consequent.length; i++) { 1049 | visit(node.consequent[i], node); 1050 | } 1051 | 1052 | } else if (node.type == "BreakStatement") { 1053 | emitter.emit("break; "); 1054 | 1055 | } else if (node.type == "ContinueStatement") { 1056 | emitter.emit("continue; "); 1057 | 1058 | } else if (node.type == "NewExpression") { 1059 | // re-use CallExpression for NewExpression's 1060 | var newNode = utils.clone(node); 1061 | newNode.type = "CallExpression"; 1062 | newNode.suppressParens = true; 1063 | 1064 | emitter.emit('new '); 1065 | visit(newNode, node); 1066 | 1067 | } else if (node.type == "FunctionExpression") { 1068 | 1069 | // Re-use FunctionDeclaration structure for method definitions 1070 | node.type = "FunctionDeclaration"; 1071 | node.id = { name: node.id || "" }; 1072 | 1073 | visit(node, node.parent); 1074 | 1075 | 1076 | // Modules & Export (http://wiki.ecmascript.org/doku.php?id=harmony:modules_examples) 1077 | } else if (node.type == "ModuleDeclaration") { 1078 | emitter.emit("namespace " + utils.classize(node.id.value) + "; "); 1079 | visit(node.body, node); 1080 | 1081 | } else if (node.type == "ExportNamedDeclaration") { 1082 | visit(node.declaration, node); 1083 | 1084 | } else if (node.type == "ImportDeclaration") { 1085 | for (var i=0,length = node.specifiers.length;i 2) { 25 | var result = js2php(fs.readFileSync(process.argv[2], 'utf8'), options); 26 | if (process.argv.length < 4) { 27 | console.log( result ); 28 | } else { 29 | fs.writeFileSync(process.argv[3], result, 'utf8'); 30 | } 31 | 32 | } else { 33 | var code = ""; 34 | process.stdin.resume(); 35 | process.stdin.on('data', function(data) { code += data; }); 36 | process.stdin.on('end', function() { 37 | console.log( js2php(code, options) ); 38 | }); 39 | } 40 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js2php", 3 | "version": "0.1.2", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "JSONStream": { 8 | "version": "1.3.4", 9 | "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.4.tgz", 10 | "integrity": "sha512-Y7vfi3I5oMOYIr+WxV8NZxDSwcbNgzdKYsTNInmycOq9bUYwGg9ryu57Wg5NLmCjqdFPNUmpMBo3kSJN9tCbXg==", 11 | "dev": true, 12 | "requires": { 13 | "jsonparse": "1.3.1", 14 | "through": "2.3.8" 15 | } 16 | }, 17 | "acorn": { 18 | "version": "5.7.2", 19 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.2.tgz", 20 | "integrity": "sha512-cJrKCNcr2kv8dlDnbw+JPUGjHZzo4myaxOLmpOX8a+rgX94YeTcTMv/LFJUSByRpc+i4GgVnnhLxvMu/2Y+rqw==", 21 | "dev": true 22 | }, 23 | "acorn-dynamic-import": { 24 | "version": "3.0.0", 25 | "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz", 26 | "integrity": "sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg==", 27 | "dev": true, 28 | "requires": { 29 | "acorn": "5.7.2" 30 | } 31 | }, 32 | "acorn-node": { 33 | "version": "1.5.2", 34 | "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.5.2.tgz", 35 | "integrity": "sha512-krFKvw/d1F17AN3XZbybIUzEY4YEPNiGo05AfP3dBlfVKrMHETKpgjpuZkSF8qDNt9UkQcqj7am8yJLseklCMg==", 36 | "dev": true, 37 | "requires": { 38 | "acorn": "5.7.2", 39 | "acorn-dynamic-import": "3.0.0", 40 | "xtend": "4.0.1" 41 | } 42 | }, 43 | "array-filter": { 44 | "version": "0.0.1", 45 | "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", 46 | "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=", 47 | "dev": true 48 | }, 49 | "array-map": { 50 | "version": "0.0.0", 51 | "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", 52 | "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=", 53 | "dev": true 54 | }, 55 | "array-reduce": { 56 | "version": "0.0.0", 57 | "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", 58 | "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=", 59 | "dev": true 60 | }, 61 | "asn1.js": { 62 | "version": "4.10.1", 63 | "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", 64 | "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", 65 | "dev": true, 66 | "requires": { 67 | "bn.js": "4.11.8", 68 | "inherits": "2.0.1", 69 | "minimalistic-assert": "1.0.1" 70 | } 71 | }, 72 | "assert": { 73 | "version": "1.4.1", 74 | "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", 75 | "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", 76 | "dev": true, 77 | "requires": { 78 | "util": "0.10.3" 79 | } 80 | }, 81 | "balanced-match": { 82 | "version": "1.0.0", 83 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 84 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 85 | "dev": true 86 | }, 87 | "base64-js": { 88 | "version": "1.3.0", 89 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", 90 | "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", 91 | "dev": true 92 | }, 93 | "bn.js": { 94 | "version": "4.11.8", 95 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", 96 | "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", 97 | "dev": true 98 | }, 99 | "brace-expansion": { 100 | "version": "1.1.11", 101 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 102 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 103 | "dev": true, 104 | "requires": { 105 | "balanced-match": "1.0.0", 106 | "concat-map": "0.0.1" 107 | } 108 | }, 109 | "brorand": { 110 | "version": "1.1.0", 111 | "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", 112 | "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", 113 | "dev": true 114 | }, 115 | "browser-pack": { 116 | "version": "6.1.0", 117 | "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz", 118 | "integrity": "sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==", 119 | "dev": true, 120 | "requires": { 121 | "JSONStream": "1.3.4", 122 | "combine-source-map": "0.8.0", 123 | "defined": "1.0.0", 124 | "safe-buffer": "5.1.2", 125 | "through2": "2.0.3", 126 | "umd": "3.0.3" 127 | } 128 | }, 129 | "browser-resolve": { 130 | "version": "1.11.3", 131 | "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", 132 | "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", 133 | "dev": true, 134 | "requires": { 135 | "resolve": "1.1.7" 136 | }, 137 | "dependencies": { 138 | "resolve": { 139 | "version": "1.1.7", 140 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", 141 | "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", 142 | "dev": true 143 | } 144 | } 145 | }, 146 | "browser-stdout": { 147 | "version": "1.3.1", 148 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 149 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 150 | "dev": true 151 | }, 152 | "browserify": { 153 | "version": "16.2.2", 154 | "resolved": "https://registry.npmjs.org/browserify/-/browserify-16.2.2.tgz", 155 | "integrity": "sha512-fMES05wq1Oukts6ksGUU2TMVHHp06LyQt0SIwbXIHm7waSrQmNBZePsU0iM/4f94zbvb/wHma+D1YrdzWYnF/A==", 156 | "dev": true, 157 | "requires": { 158 | "JSONStream": "1.3.4", 159 | "assert": "1.4.1", 160 | "browser-pack": "6.1.0", 161 | "browser-resolve": "1.11.3", 162 | "browserify-zlib": "0.2.0", 163 | "buffer": "5.2.1", 164 | "cached-path-relative": "1.0.1", 165 | "concat-stream": "1.6.2", 166 | "console-browserify": "1.1.0", 167 | "constants-browserify": "1.0.0", 168 | "crypto-browserify": "3.12.0", 169 | "defined": "1.0.0", 170 | "deps-sort": "2.0.0", 171 | "domain-browser": "1.2.0", 172 | "duplexer2": "0.1.4", 173 | "events": "2.1.0", 174 | "glob": "7.1.3", 175 | "has": "1.0.3", 176 | "htmlescape": "1.1.1", 177 | "https-browserify": "1.0.0", 178 | "inherits": "2.0.1", 179 | "insert-module-globals": "7.2.0", 180 | "labeled-stream-splicer": "2.0.1", 181 | "mkdirp": "0.5.1", 182 | "module-deps": "6.1.0", 183 | "os-browserify": "0.3.0", 184 | "parents": "1.0.1", 185 | "path-browserify": "0.0.1", 186 | "process": "0.11.10", 187 | "punycode": "1.4.1", 188 | "querystring-es3": "0.2.1", 189 | "read-only-stream": "2.0.0", 190 | "readable-stream": "2.3.6", 191 | "resolve": "1.8.1", 192 | "shasum": "1.0.2", 193 | "shell-quote": "1.6.1", 194 | "stream-browserify": "2.0.1", 195 | "stream-http": "2.8.3", 196 | "string_decoder": "1.1.1", 197 | "subarg": "1.0.0", 198 | "syntax-error": "1.4.0", 199 | "through2": "2.0.3", 200 | "timers-browserify": "1.4.2", 201 | "tty-browserify": "0.0.1", 202 | "url": "0.11.0", 203 | "util": "0.10.3", 204 | "vm-browserify": "1.1.0", 205 | "xtend": "4.0.1" 206 | } 207 | }, 208 | "browserify-aes": { 209 | "version": "1.2.0", 210 | "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", 211 | "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", 212 | "dev": true, 213 | "requires": { 214 | "buffer-xor": "1.0.3", 215 | "cipher-base": "1.0.4", 216 | "create-hash": "1.2.0", 217 | "evp_bytestokey": "1.0.3", 218 | "inherits": "2.0.1", 219 | "safe-buffer": "5.1.2" 220 | } 221 | }, 222 | "browserify-cipher": { 223 | "version": "1.0.1", 224 | "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", 225 | "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", 226 | "dev": true, 227 | "requires": { 228 | "browserify-aes": "1.2.0", 229 | "browserify-des": "1.0.2", 230 | "evp_bytestokey": "1.0.3" 231 | } 232 | }, 233 | "browserify-des": { 234 | "version": "1.0.2", 235 | "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", 236 | "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", 237 | "dev": true, 238 | "requires": { 239 | "cipher-base": "1.0.4", 240 | "des.js": "1.0.0", 241 | "inherits": "2.0.1", 242 | "safe-buffer": "5.1.2" 243 | } 244 | }, 245 | "browserify-rsa": { 246 | "version": "4.0.1", 247 | "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", 248 | "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", 249 | "dev": true, 250 | "requires": { 251 | "bn.js": "4.11.8", 252 | "randombytes": "2.0.6" 253 | } 254 | }, 255 | "browserify-sign": { 256 | "version": "4.0.4", 257 | "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", 258 | "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", 259 | "dev": true, 260 | "requires": { 261 | "bn.js": "4.11.8", 262 | "browserify-rsa": "4.0.1", 263 | "create-hash": "1.2.0", 264 | "create-hmac": "1.1.7", 265 | "elliptic": "6.4.1", 266 | "inherits": "2.0.1", 267 | "parse-asn1": "5.1.1" 268 | } 269 | }, 270 | "browserify-zlib": { 271 | "version": "0.2.0", 272 | "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", 273 | "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", 274 | "dev": true, 275 | "requires": { 276 | "pako": "1.0.6" 277 | } 278 | }, 279 | "buffer": { 280 | "version": "5.2.1", 281 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", 282 | "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", 283 | "dev": true, 284 | "requires": { 285 | "base64-js": "1.3.0", 286 | "ieee754": "1.1.12" 287 | } 288 | }, 289 | "buffer-from": { 290 | "version": "1.1.1", 291 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 292 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", 293 | "dev": true 294 | }, 295 | "buffer-xor": { 296 | "version": "1.0.3", 297 | "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", 298 | "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", 299 | "dev": true 300 | }, 301 | "builtin-status-codes": { 302 | "version": "3.0.0", 303 | "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", 304 | "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", 305 | "dev": true 306 | }, 307 | "cached-path-relative": { 308 | "version": "1.0.1", 309 | "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.1.tgz", 310 | "integrity": "sha1-0JxLUoAKpMB44t2BqGmqyQ0uVOc=", 311 | "dev": true 312 | }, 313 | "cipher-base": { 314 | "version": "1.0.4", 315 | "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", 316 | "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", 317 | "dev": true, 318 | "requires": { 319 | "inherits": "2.0.1", 320 | "safe-buffer": "5.1.2" 321 | } 322 | }, 323 | "combine-source-map": { 324 | "version": "0.8.0", 325 | "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz", 326 | "integrity": "sha1-pY0N8ELBhvz4IqjoAV9UUNLXmos=", 327 | "dev": true, 328 | "requires": { 329 | "convert-source-map": "1.1.3", 330 | "inline-source-map": "0.6.2", 331 | "lodash.memoize": "3.0.4", 332 | "source-map": "0.5.7" 333 | } 334 | }, 335 | "commander": { 336 | "version": "2.15.1", 337 | "resolved": "http://registry.npmjs.org/commander/-/commander-2.15.1.tgz", 338 | "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", 339 | "dev": true 340 | }, 341 | "concat-map": { 342 | "version": "0.0.1", 343 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 344 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 345 | "dev": true 346 | }, 347 | "concat-stream": { 348 | "version": "1.6.2", 349 | "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", 350 | "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", 351 | "dev": true, 352 | "requires": { 353 | "buffer-from": "1.1.1", 354 | "inherits": "2.0.3", 355 | "readable-stream": "2.3.6", 356 | "typedarray": "0.0.6" 357 | }, 358 | "dependencies": { 359 | "inherits": { 360 | "version": "2.0.3", 361 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 362 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 363 | "dev": true 364 | } 365 | } 366 | }, 367 | "console-browserify": { 368 | "version": "1.1.0", 369 | "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", 370 | "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", 371 | "dev": true, 372 | "requires": { 373 | "date-now": "0.1.4" 374 | } 375 | }, 376 | "constants-browserify": { 377 | "version": "1.0.0", 378 | "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", 379 | "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", 380 | "dev": true 381 | }, 382 | "convert-source-map": { 383 | "version": "1.1.3", 384 | "resolved": "http://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", 385 | "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=", 386 | "dev": true 387 | }, 388 | "core-util-is": { 389 | "version": "1.0.2", 390 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 391 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", 392 | "dev": true 393 | }, 394 | "create-ecdh": { 395 | "version": "4.0.3", 396 | "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", 397 | "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", 398 | "dev": true, 399 | "requires": { 400 | "bn.js": "4.11.8", 401 | "elliptic": "6.4.1" 402 | } 403 | }, 404 | "create-hash": { 405 | "version": "1.2.0", 406 | "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", 407 | "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", 408 | "dev": true, 409 | "requires": { 410 | "cipher-base": "1.0.4", 411 | "inherits": "2.0.1", 412 | "md5.js": "1.3.4", 413 | "ripemd160": "2.0.2", 414 | "sha.js": "2.4.11" 415 | } 416 | }, 417 | "create-hmac": { 418 | "version": "1.1.7", 419 | "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", 420 | "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", 421 | "dev": true, 422 | "requires": { 423 | "cipher-base": "1.0.4", 424 | "create-hash": "1.2.0", 425 | "inherits": "2.0.1", 426 | "ripemd160": "2.0.2", 427 | "safe-buffer": "5.1.2", 428 | "sha.js": "2.4.11" 429 | } 430 | }, 431 | "crypto-browserify": { 432 | "version": "3.12.0", 433 | "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", 434 | "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", 435 | "dev": true, 436 | "requires": { 437 | "browserify-cipher": "1.0.1", 438 | "browserify-sign": "4.0.4", 439 | "create-ecdh": "4.0.3", 440 | "create-hash": "1.2.0", 441 | "create-hmac": "1.1.7", 442 | "diffie-hellman": "5.0.3", 443 | "inherits": "2.0.1", 444 | "pbkdf2": "3.0.16", 445 | "public-encrypt": "4.0.2", 446 | "randombytes": "2.0.6", 447 | "randomfill": "1.0.4" 448 | } 449 | }, 450 | "date-now": { 451 | "version": "0.1.4", 452 | "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", 453 | "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", 454 | "dev": true 455 | }, 456 | "debug": { 457 | "version": "3.1.0", 458 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 459 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 460 | "dev": true, 461 | "requires": { 462 | "ms": "2.0.0" 463 | } 464 | }, 465 | "defined": { 466 | "version": "1.0.0", 467 | "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", 468 | "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", 469 | "dev": true 470 | }, 471 | "deps-sort": { 472 | "version": "2.0.0", 473 | "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.0.tgz", 474 | "integrity": "sha1-CRckkC6EZYJg65EHSMzNGvbiH7U=", 475 | "dev": true, 476 | "requires": { 477 | "JSONStream": "1.3.4", 478 | "shasum": "1.0.2", 479 | "subarg": "1.0.0", 480 | "through2": "2.0.3" 481 | } 482 | }, 483 | "des.js": { 484 | "version": "1.0.0", 485 | "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", 486 | "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", 487 | "dev": true, 488 | "requires": { 489 | "inherits": "2.0.1", 490 | "minimalistic-assert": "1.0.1" 491 | } 492 | }, 493 | "detective": { 494 | "version": "5.1.0", 495 | "resolved": "https://registry.npmjs.org/detective/-/detective-5.1.0.tgz", 496 | "integrity": "sha512-TFHMqfOvxlgrfVzTEkNBSh9SvSNX/HfF4OFI2QFGCyPm02EsyILqnUeb5P6q7JZ3SFNTBL5t2sePRgrN4epUWQ==", 497 | "dev": true, 498 | "requires": { 499 | "acorn-node": "1.5.2", 500 | "defined": "1.0.0", 501 | "minimist": "1.2.0" 502 | } 503 | }, 504 | "diff": { 505 | "version": "3.5.0", 506 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", 507 | "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", 508 | "dev": true 509 | }, 510 | "diffie-hellman": { 511 | "version": "5.0.3", 512 | "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", 513 | "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", 514 | "dev": true, 515 | "requires": { 516 | "bn.js": "4.11.8", 517 | "miller-rabin": "4.0.1", 518 | "randombytes": "2.0.6" 519 | } 520 | }, 521 | "domain-browser": { 522 | "version": "1.2.0", 523 | "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", 524 | "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", 525 | "dev": true 526 | }, 527 | "duplexer2": { 528 | "version": "0.1.4", 529 | "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", 530 | "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", 531 | "dev": true, 532 | "requires": { 533 | "readable-stream": "2.3.6" 534 | } 535 | }, 536 | "elliptic": { 537 | "version": "6.4.1", 538 | "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", 539 | "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", 540 | "dev": true, 541 | "requires": { 542 | "bn.js": "4.11.8", 543 | "brorand": "1.1.0", 544 | "hash.js": "1.1.5", 545 | "hmac-drbg": "1.0.1", 546 | "inherits": "2.0.1", 547 | "minimalistic-assert": "1.0.1", 548 | "minimalistic-crypto-utils": "1.0.1" 549 | } 550 | }, 551 | "escape-string-regexp": { 552 | "version": "1.0.5", 553 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 554 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 555 | "dev": true 556 | }, 557 | "espree": { 558 | "version": "2.2.5", 559 | "resolved": "https://registry.npmjs.org/espree/-/espree-2.2.5.tgz", 560 | "integrity": "sha1-32kbkxCIlAKuspzAZnCMVmkLhUs=" 561 | }, 562 | "events": { 563 | "version": "2.1.0", 564 | "resolved": "https://registry.npmjs.org/events/-/events-2.1.0.tgz", 565 | "integrity": "sha512-3Zmiobend8P9DjmKAty0Era4jV8oJ0yGYe2nJJAxgymF9+N8F2m0hhZiMoWtcfepExzNKZumFU3ksdQbInGWCg==", 566 | "dev": true 567 | }, 568 | "evp_bytestokey": { 569 | "version": "1.0.3", 570 | "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", 571 | "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", 572 | "dev": true, 573 | "requires": { 574 | "md5.js": "1.3.4", 575 | "safe-buffer": "5.1.2" 576 | } 577 | }, 578 | "fs.realpath": { 579 | "version": "1.0.0", 580 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 581 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 582 | "dev": true 583 | }, 584 | "function-bind": { 585 | "version": "1.1.1", 586 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 587 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 588 | "dev": true 589 | }, 590 | "get-assigned-identifiers": { 591 | "version": "1.2.0", 592 | "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz", 593 | "integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==", 594 | "dev": true 595 | }, 596 | "glob": { 597 | "version": "7.1.3", 598 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", 599 | "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", 600 | "dev": true, 601 | "requires": { 602 | "fs.realpath": "1.0.0", 603 | "inflight": "1.0.6", 604 | "inherits": "2.0.1", 605 | "minimatch": "3.0.4", 606 | "once": "1.4.0", 607 | "path-is-absolute": "1.0.1" 608 | } 609 | }, 610 | "growl": { 611 | "version": "1.10.5", 612 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", 613 | "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", 614 | "dev": true 615 | }, 616 | "has": { 617 | "version": "1.0.3", 618 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 619 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 620 | "dev": true, 621 | "requires": { 622 | "function-bind": "1.1.1" 623 | } 624 | }, 625 | "has-flag": { 626 | "version": "3.0.0", 627 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 628 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 629 | "dev": true 630 | }, 631 | "hash-base": { 632 | "version": "3.0.4", 633 | "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", 634 | "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", 635 | "dev": true, 636 | "requires": { 637 | "inherits": "2.0.1", 638 | "safe-buffer": "5.1.2" 639 | } 640 | }, 641 | "hash.js": { 642 | "version": "1.1.5", 643 | "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.5.tgz", 644 | "integrity": "sha512-eWI5HG9Np+eHV1KQhisXWwM+4EPPYe5dFX1UZZH7k/E3JzDEazVH+VGlZi6R94ZqImq+A3D1mCEtrFIfg/E7sA==", 645 | "dev": true, 646 | "requires": { 647 | "inherits": "2.0.3", 648 | "minimalistic-assert": "1.0.1" 649 | }, 650 | "dependencies": { 651 | "inherits": { 652 | "version": "2.0.3", 653 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 654 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 655 | "dev": true 656 | } 657 | } 658 | }, 659 | "he": { 660 | "version": "1.1.1", 661 | "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", 662 | "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", 663 | "dev": true 664 | }, 665 | "hmac-drbg": { 666 | "version": "1.0.1", 667 | "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", 668 | "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", 669 | "dev": true, 670 | "requires": { 671 | "hash.js": "1.1.5", 672 | "minimalistic-assert": "1.0.1", 673 | "minimalistic-crypto-utils": "1.0.1" 674 | } 675 | }, 676 | "htmlescape": { 677 | "version": "1.1.1", 678 | "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", 679 | "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=", 680 | "dev": true 681 | }, 682 | "https-browserify": { 683 | "version": "1.0.0", 684 | "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", 685 | "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", 686 | "dev": true 687 | }, 688 | "ieee754": { 689 | "version": "1.1.12", 690 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", 691 | "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==", 692 | "dev": true 693 | }, 694 | "inflight": { 695 | "version": "1.0.6", 696 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 697 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 698 | "dev": true, 699 | "requires": { 700 | "once": "1.4.0", 701 | "wrappy": "1.0.2" 702 | } 703 | }, 704 | "inherits": { 705 | "version": "2.0.1", 706 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", 707 | "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", 708 | "dev": true 709 | }, 710 | "inline-source-map": { 711 | "version": "0.6.2", 712 | "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz", 713 | "integrity": "sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=", 714 | "dev": true, 715 | "requires": { 716 | "source-map": "0.5.7" 717 | } 718 | }, 719 | "insert-module-globals": { 720 | "version": "7.2.0", 721 | "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.2.0.tgz", 722 | "integrity": "sha512-VE6NlW+WGn2/AeOMd496AHFYmE7eLKkUY6Ty31k4og5vmA3Fjuwe9v6ifH6Xx/Hz27QvdoMoviw1/pqWRB09Sw==", 723 | "dev": true, 724 | "requires": { 725 | "JSONStream": "1.3.4", 726 | "acorn-node": "1.5.2", 727 | "combine-source-map": "0.8.0", 728 | "concat-stream": "1.6.2", 729 | "is-buffer": "1.1.6", 730 | "path-is-absolute": "1.0.1", 731 | "process": "0.11.10", 732 | "through2": "2.0.3", 733 | "undeclared-identifiers": "1.1.2", 734 | "xtend": "4.0.1" 735 | } 736 | }, 737 | "is-buffer": { 738 | "version": "1.1.6", 739 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", 740 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", 741 | "dev": true 742 | }, 743 | "isarray": { 744 | "version": "1.0.0", 745 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 746 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", 747 | "dev": true 748 | }, 749 | "json-stable-stringify": { 750 | "version": "0.0.1", 751 | "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz", 752 | "integrity": "sha1-YRwj6BTbN1Un34URk9tZ3Sryf0U=", 753 | "dev": true, 754 | "requires": { 755 | "jsonify": "0.0.0" 756 | } 757 | }, 758 | "jsonify": { 759 | "version": "0.0.0", 760 | "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", 761 | "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", 762 | "dev": true 763 | }, 764 | "jsonparse": { 765 | "version": "1.3.1", 766 | "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", 767 | "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", 768 | "dev": true 769 | }, 770 | "labeled-stream-splicer": { 771 | "version": "2.0.1", 772 | "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.1.tgz", 773 | "integrity": "sha512-MC94mHZRvJ3LfykJlTUipBqenZz1pacOZEMhhQ8dMGcDHs0SBE5GbsavUXV7YtP3icBW17W0Zy1I0lfASmo9Pg==", 774 | "dev": true, 775 | "requires": { 776 | "inherits": "2.0.1", 777 | "isarray": "2.0.4", 778 | "stream-splicer": "2.0.0" 779 | }, 780 | "dependencies": { 781 | "isarray": { 782 | "version": "2.0.4", 783 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.4.tgz", 784 | "integrity": "sha512-GMxXOiUirWg1xTKRipM0Ek07rX+ubx4nNVElTJdNLYmNO/2YrDkgJGw9CljXn+r4EWiDQg/8lsRdHyg2PJuUaA==", 785 | "dev": true 786 | } 787 | } 788 | }, 789 | "lodash.memoize": { 790 | "version": "3.0.4", 791 | "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", 792 | "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=", 793 | "dev": true 794 | }, 795 | "md5.js": { 796 | "version": "1.3.4", 797 | "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", 798 | "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", 799 | "dev": true, 800 | "requires": { 801 | "hash-base": "3.0.4", 802 | "inherits": "2.0.1" 803 | } 804 | }, 805 | "miller-rabin": { 806 | "version": "4.0.1", 807 | "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", 808 | "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", 809 | "dev": true, 810 | "requires": { 811 | "bn.js": "4.11.8", 812 | "brorand": "1.1.0" 813 | } 814 | }, 815 | "minimalistic-assert": { 816 | "version": "1.0.1", 817 | "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", 818 | "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", 819 | "dev": true 820 | }, 821 | "minimalistic-crypto-utils": { 822 | "version": "1.0.1", 823 | "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", 824 | "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", 825 | "dev": true 826 | }, 827 | "minimatch": { 828 | "version": "3.0.4", 829 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 830 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 831 | "dev": true, 832 | "requires": { 833 | "brace-expansion": "1.1.11" 834 | } 835 | }, 836 | "minimist": { 837 | "version": "1.2.0", 838 | "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 839 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", 840 | "dev": true 841 | }, 842 | "mkdirp": { 843 | "version": "0.5.1", 844 | "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 845 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 846 | "dev": true, 847 | "requires": { 848 | "minimist": "0.0.8" 849 | }, 850 | "dependencies": { 851 | "minimist": { 852 | "version": "0.0.8", 853 | "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 854 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 855 | "dev": true 856 | } 857 | } 858 | }, 859 | "mocha": { 860 | "version": "5.2.0", 861 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", 862 | "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", 863 | "dev": true, 864 | "requires": { 865 | "browser-stdout": "1.3.1", 866 | "commander": "2.15.1", 867 | "debug": "3.1.0", 868 | "diff": "3.5.0", 869 | "escape-string-regexp": "1.0.5", 870 | "glob": "7.1.2", 871 | "growl": "1.10.5", 872 | "he": "1.1.1", 873 | "minimatch": "3.0.4", 874 | "mkdirp": "0.5.1", 875 | "supports-color": "5.4.0" 876 | }, 877 | "dependencies": { 878 | "glob": { 879 | "version": "7.1.2", 880 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", 881 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", 882 | "dev": true, 883 | "requires": { 884 | "fs.realpath": "1.0.0", 885 | "inflight": "1.0.6", 886 | "inherits": "2.0.1", 887 | "minimatch": "3.0.4", 888 | "once": "1.4.0", 889 | "path-is-absolute": "1.0.1" 890 | } 891 | } 892 | } 893 | }, 894 | "module-deps": { 895 | "version": "6.1.0", 896 | "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.1.0.tgz", 897 | "integrity": "sha512-NPs5N511VD1rrVJihSso/LiBShRbJALYBKzDW91uZYy7BpjnO4bGnZL3HjZ9yKcFdZUWwaYjDz9zxbuP7vKMuQ==", 898 | "dev": true, 899 | "requires": { 900 | "JSONStream": "1.3.4", 901 | "browser-resolve": "1.11.3", 902 | "cached-path-relative": "1.0.1", 903 | "concat-stream": "1.6.2", 904 | "defined": "1.0.0", 905 | "detective": "5.1.0", 906 | "duplexer2": "0.1.4", 907 | "inherits": "2.0.1", 908 | "parents": "1.0.1", 909 | "readable-stream": "2.3.6", 910 | "resolve": "1.8.1", 911 | "stream-combiner2": "1.1.1", 912 | "subarg": "1.0.0", 913 | "through2": "2.0.3", 914 | "xtend": "4.0.1" 915 | } 916 | }, 917 | "ms": { 918 | "version": "2.0.0", 919 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 920 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 921 | "dev": true 922 | }, 923 | "once": { 924 | "version": "1.4.0", 925 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 926 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 927 | "dev": true, 928 | "requires": { 929 | "wrappy": "1.0.2" 930 | } 931 | }, 932 | "os-browserify": { 933 | "version": "0.3.0", 934 | "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", 935 | "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", 936 | "dev": true 937 | }, 938 | "pako": { 939 | "version": "1.0.6", 940 | "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", 941 | "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==", 942 | "dev": true 943 | }, 944 | "parents": { 945 | "version": "1.0.1", 946 | "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", 947 | "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=", 948 | "dev": true, 949 | "requires": { 950 | "path-platform": "0.11.15" 951 | } 952 | }, 953 | "parse-asn1": { 954 | "version": "5.1.1", 955 | "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz", 956 | "integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==", 957 | "dev": true, 958 | "requires": { 959 | "asn1.js": "4.10.1", 960 | "browserify-aes": "1.2.0", 961 | "create-hash": "1.2.0", 962 | "evp_bytestokey": "1.0.3", 963 | "pbkdf2": "3.0.16" 964 | } 965 | }, 966 | "path-browserify": { 967 | "version": "0.0.1", 968 | "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", 969 | "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", 970 | "dev": true 971 | }, 972 | "path-is-absolute": { 973 | "version": "1.0.1", 974 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 975 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 976 | "dev": true 977 | }, 978 | "path-parse": { 979 | "version": "1.0.6", 980 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 981 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", 982 | "dev": true 983 | }, 984 | "path-platform": { 985 | "version": "0.11.15", 986 | "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", 987 | "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=", 988 | "dev": true 989 | }, 990 | "pbkdf2": { 991 | "version": "3.0.16", 992 | "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.16.tgz", 993 | "integrity": "sha512-y4CXP3thSxqf7c0qmOF+9UeOTrifiVTIM+u7NWlq+PRsHbr7r7dpCmvzrZxa96JJUNi0Y5w9VqG5ZNeCVMoDcA==", 994 | "dev": true, 995 | "requires": { 996 | "create-hash": "1.2.0", 997 | "create-hmac": "1.1.7", 998 | "ripemd160": "2.0.2", 999 | "safe-buffer": "5.1.2", 1000 | "sha.js": "2.4.11" 1001 | } 1002 | }, 1003 | "process": { 1004 | "version": "0.11.10", 1005 | "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", 1006 | "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", 1007 | "dev": true 1008 | }, 1009 | "process-nextick-args": { 1010 | "version": "2.0.0", 1011 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", 1012 | "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", 1013 | "dev": true 1014 | }, 1015 | "public-encrypt": { 1016 | "version": "4.0.2", 1017 | "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.2.tgz", 1018 | "integrity": "sha512-4kJ5Esocg8X3h8YgJsKAuoesBgB7mqH3eowiDzMUPKiRDDE7E/BqqZD1hnTByIaAFiwAw246YEltSq7tdrOH0Q==", 1019 | "dev": true, 1020 | "requires": { 1021 | "bn.js": "4.11.8", 1022 | "browserify-rsa": "4.0.1", 1023 | "create-hash": "1.2.0", 1024 | "parse-asn1": "5.1.1", 1025 | "randombytes": "2.0.6" 1026 | } 1027 | }, 1028 | "punycode": { 1029 | "version": "1.4.1", 1030 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", 1031 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", 1032 | "dev": true 1033 | }, 1034 | "querystring": { 1035 | "version": "0.2.0", 1036 | "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", 1037 | "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", 1038 | "dev": true 1039 | }, 1040 | "querystring-es3": { 1041 | "version": "0.2.1", 1042 | "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", 1043 | "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", 1044 | "dev": true 1045 | }, 1046 | "randombytes": { 1047 | "version": "2.0.6", 1048 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", 1049 | "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", 1050 | "dev": true, 1051 | "requires": { 1052 | "safe-buffer": "5.1.2" 1053 | } 1054 | }, 1055 | "randomfill": { 1056 | "version": "1.0.4", 1057 | "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", 1058 | "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", 1059 | "dev": true, 1060 | "requires": { 1061 | "randombytes": "2.0.6", 1062 | "safe-buffer": "5.1.2" 1063 | } 1064 | }, 1065 | "read-only-stream": { 1066 | "version": "2.0.0", 1067 | "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", 1068 | "integrity": "sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=", 1069 | "dev": true, 1070 | "requires": { 1071 | "readable-stream": "2.3.6" 1072 | } 1073 | }, 1074 | "readable-stream": { 1075 | "version": "2.3.6", 1076 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", 1077 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", 1078 | "dev": true, 1079 | "requires": { 1080 | "core-util-is": "1.0.2", 1081 | "inherits": "2.0.3", 1082 | "isarray": "1.0.0", 1083 | "process-nextick-args": "2.0.0", 1084 | "safe-buffer": "5.1.2", 1085 | "string_decoder": "1.1.1", 1086 | "util-deprecate": "1.0.2" 1087 | }, 1088 | "dependencies": { 1089 | "inherits": { 1090 | "version": "2.0.3", 1091 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 1092 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 1093 | "dev": true 1094 | } 1095 | } 1096 | }, 1097 | "resolve": { 1098 | "version": "1.8.1", 1099 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", 1100 | "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", 1101 | "dev": true, 1102 | "requires": { 1103 | "path-parse": "1.0.6" 1104 | } 1105 | }, 1106 | "ripemd160": { 1107 | "version": "2.0.2", 1108 | "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", 1109 | "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", 1110 | "dev": true, 1111 | "requires": { 1112 | "hash-base": "3.0.4", 1113 | "inherits": "2.0.1" 1114 | } 1115 | }, 1116 | "safe-buffer": { 1117 | "version": "5.1.2", 1118 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1119 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 1120 | "dev": true 1121 | }, 1122 | "sha.js": { 1123 | "version": "2.4.11", 1124 | "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", 1125 | "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", 1126 | "dev": true, 1127 | "requires": { 1128 | "inherits": "2.0.1", 1129 | "safe-buffer": "5.1.2" 1130 | } 1131 | }, 1132 | "shasum": { 1133 | "version": "1.0.2", 1134 | "resolved": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz", 1135 | "integrity": "sha1-5wEjENj0F/TetXEhUOVni4euVl8=", 1136 | "dev": true, 1137 | "requires": { 1138 | "json-stable-stringify": "0.0.1", 1139 | "sha.js": "2.4.11" 1140 | } 1141 | }, 1142 | "shell-quote": { 1143 | "version": "1.6.1", 1144 | "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", 1145 | "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", 1146 | "dev": true, 1147 | "requires": { 1148 | "array-filter": "0.0.1", 1149 | "array-map": "0.0.0", 1150 | "array-reduce": "0.0.0", 1151 | "jsonify": "0.0.0" 1152 | } 1153 | }, 1154 | "simple-concat": { 1155 | "version": "1.0.0", 1156 | "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz", 1157 | "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=", 1158 | "dev": true 1159 | }, 1160 | "source-map": { 1161 | "version": "0.5.7", 1162 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", 1163 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", 1164 | "dev": true 1165 | }, 1166 | "stream-browserify": { 1167 | "version": "2.0.1", 1168 | "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", 1169 | "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", 1170 | "dev": true, 1171 | "requires": { 1172 | "inherits": "2.0.1", 1173 | "readable-stream": "2.3.6" 1174 | } 1175 | }, 1176 | "stream-combiner2": { 1177 | "version": "1.1.1", 1178 | "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", 1179 | "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", 1180 | "dev": true, 1181 | "requires": { 1182 | "duplexer2": "0.1.4", 1183 | "readable-stream": "2.3.6" 1184 | } 1185 | }, 1186 | "stream-http": { 1187 | "version": "2.8.3", 1188 | "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", 1189 | "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", 1190 | "dev": true, 1191 | "requires": { 1192 | "builtin-status-codes": "3.0.0", 1193 | "inherits": "2.0.1", 1194 | "readable-stream": "2.3.6", 1195 | "to-arraybuffer": "1.0.1", 1196 | "xtend": "4.0.1" 1197 | } 1198 | }, 1199 | "stream-splicer": { 1200 | "version": "2.0.0", 1201 | "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.0.tgz", 1202 | "integrity": "sha1-G2O+Q4oTPktnHMGTUZdgAXWRDYM=", 1203 | "dev": true, 1204 | "requires": { 1205 | "inherits": "2.0.1", 1206 | "readable-stream": "2.3.6" 1207 | } 1208 | }, 1209 | "string_decoder": { 1210 | "version": "1.1.1", 1211 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 1212 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 1213 | "dev": true, 1214 | "requires": { 1215 | "safe-buffer": "5.1.2" 1216 | } 1217 | }, 1218 | "subarg": { 1219 | "version": "1.0.0", 1220 | "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", 1221 | "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=", 1222 | "dev": true, 1223 | "requires": { 1224 | "minimist": "1.2.0" 1225 | } 1226 | }, 1227 | "supports-color": { 1228 | "version": "5.4.0", 1229 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", 1230 | "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", 1231 | "dev": true, 1232 | "requires": { 1233 | "has-flag": "3.0.0" 1234 | } 1235 | }, 1236 | "syntax-error": { 1237 | "version": "1.4.0", 1238 | "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", 1239 | "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", 1240 | "dev": true, 1241 | "requires": { 1242 | "acorn-node": "1.5.2" 1243 | } 1244 | }, 1245 | "through": { 1246 | "version": "2.3.8", 1247 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 1248 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", 1249 | "dev": true 1250 | }, 1251 | "through2": { 1252 | "version": "2.0.3", 1253 | "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", 1254 | "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", 1255 | "dev": true, 1256 | "requires": { 1257 | "readable-stream": "2.3.6", 1258 | "xtend": "4.0.1" 1259 | } 1260 | }, 1261 | "timers-browserify": { 1262 | "version": "1.4.2", 1263 | "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", 1264 | "integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=", 1265 | "dev": true, 1266 | "requires": { 1267 | "process": "0.11.10" 1268 | } 1269 | }, 1270 | "to-arraybuffer": { 1271 | "version": "1.0.1", 1272 | "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", 1273 | "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", 1274 | "dev": true 1275 | }, 1276 | "tty-browserify": { 1277 | "version": "0.0.1", 1278 | "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", 1279 | "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", 1280 | "dev": true 1281 | }, 1282 | "typedarray": { 1283 | "version": "0.0.6", 1284 | "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", 1285 | "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", 1286 | "dev": true 1287 | }, 1288 | "umd": { 1289 | "version": "3.0.3", 1290 | "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz", 1291 | "integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==", 1292 | "dev": true 1293 | }, 1294 | "undeclared-identifiers": { 1295 | "version": "1.1.2", 1296 | "resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.2.tgz", 1297 | "integrity": "sha512-13EaeocO4edF/3JKime9rD7oB6QI8llAGhgn5fKOPyfkJbRb6NFv9pYV6dFEmpa4uRjKeBqLZP8GpuzqHlKDMQ==", 1298 | "dev": true, 1299 | "requires": { 1300 | "acorn-node": "1.5.2", 1301 | "get-assigned-identifiers": "1.2.0", 1302 | "simple-concat": "1.0.0", 1303 | "xtend": "4.0.1" 1304 | } 1305 | }, 1306 | "url": { 1307 | "version": "0.11.0", 1308 | "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", 1309 | "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", 1310 | "dev": true, 1311 | "requires": { 1312 | "punycode": "1.3.2", 1313 | "querystring": "0.2.0" 1314 | }, 1315 | "dependencies": { 1316 | "punycode": { 1317 | "version": "1.3.2", 1318 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", 1319 | "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", 1320 | "dev": true 1321 | } 1322 | } 1323 | }, 1324 | "util": { 1325 | "version": "0.10.3", 1326 | "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", 1327 | "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", 1328 | "dev": true, 1329 | "requires": { 1330 | "inherits": "2.0.1" 1331 | } 1332 | }, 1333 | "util-deprecate": { 1334 | "version": "1.0.2", 1335 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1336 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", 1337 | "dev": true 1338 | }, 1339 | "vm-browserify": { 1340 | "version": "1.1.0", 1341 | "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.0.tgz", 1342 | "integrity": "sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==", 1343 | "dev": true 1344 | }, 1345 | "wrappy": { 1346 | "version": "1.0.2", 1347 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1348 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1349 | "dev": true 1350 | }, 1351 | "xtend": { 1352 | "version": "4.0.1", 1353 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", 1354 | "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", 1355 | "dev": true 1356 | } 1357 | } 1358 | } 1359 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js2php", 3 | "version": "0.1.7", 4 | "description": "JavaScript to PHP transpiler.", 5 | "main": "index.js", 6 | "bin": "js2php", 7 | "dependencies": { 8 | "espree": "~2.2.3" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/endel/js2php.git" 13 | }, 14 | "keywords": [ 15 | "javascript", 16 | "php", 17 | "transpiler", 18 | "transcompiler" 19 | ], 20 | "devDependencies": { 21 | "browserify": "~16.2.2", 22 | "mocha": "~5.2.0", 23 | "assert": "~1.4.1" 24 | }, 25 | "scripts": { 26 | "test": "mocha ./test/suite.js" 27 | }, 28 | "author": "Endel Dreyer", 29 | "license": "MIT" 30 | } 31 | -------------------------------------------------------------------------------- /scope.js: -------------------------------------------------------------------------------- 1 | var utils = require('./utils'); 2 | 3 | var tmpCounter = 0; 4 | 5 | function Scope(root, parent) { 6 | this.node = root; 7 | this.parent = parent; 8 | 9 | this.definitions = {}; 10 | this.using = []; 11 | 12 | this.getters = []; 13 | this.setters = []; 14 | 15 | this.getDefinition = function(node, suppressUsing) { 16 | var value = this.definitions[ node.name ]; 17 | 18 | if (!value && this.parent) { 19 | value = this.parent.getDefinition(node); 20 | if (value && (!suppressUsing) && this.using.indexOf(node.name) === -1) { 21 | this.using.push(node.name); 22 | } 23 | } 24 | 25 | return value; 26 | }; 27 | 28 | this.getTmpName = function() { 29 | while (true) { 30 | var name = `temp${tmpCounter++}`; 31 | if (this.getDefinition({ name }, true) === undefined) { 32 | return name; 33 | } 34 | } 35 | }; 36 | 37 | this.register = function(node) { 38 | var name = null; 39 | 40 | if (node.type == 'VariableDeclarator') { 41 | var dataType = null; 42 | name = node.id.name; 43 | 44 | if (node.init && utils.isString(node.init)) { 45 | dataType = "String"; 46 | } 47 | 48 | node.dataType = dataType; 49 | 50 | } else if (node.type == 'Identifier') { 51 | name = node.name; 52 | } else if (node.type === 'MemberExpression'&& node.object.type === 'ThisExpression' && node.property.type === 'Identifier') { 53 | name = node.property.name 54 | } else if (node.type == 'MethodDefinition') { 55 | if (node.kind == "get") { 56 | var getter = utils.clone(node); 57 | getter.kind = null; 58 | this.getters.push(getter); 59 | } else if (node.kind == "set") { 60 | var setter = utils.clone(node); 61 | setter.kind = null; 62 | this.setters.push(setter); 63 | } 64 | 65 | } 66 | 67 | this.definitions[name] = node; 68 | } 69 | 70 | } 71 | 72 | module.exports = { 73 | KIND_ROOT : 0, 74 | KIND_NODE : 1, 75 | 76 | get: function(node) { 77 | if (node.scope) { 78 | return node.scope; 79 | } else { 80 | return this.get(node.parent); 81 | } 82 | }, 83 | 84 | create: function(node) { 85 | return node.scope = new Scope(node, node.parent && this.get(node.parent)); 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /test/fixtures/anonymous_function.js: -------------------------------------------------------------------------------- 1 | var inline = (function(i){ 2 | return i; 3 | })(5); 4 | var_dump(inline); 5 | 6 | var assignment; 7 | assignment = (function() { 8 | var _results = [1,2,3,4,5]; 9 | return _results; 10 | })(); 11 | var_dump(assignment); 12 | -------------------------------------------------------------------------------- /test/fixtures/anonymous_function.php: -------------------------------------------------------------------------------- 1 | { 2 | return a * b * c; 3 | } 4 | var something2 = (a, b = 2, c = 4) => a * b * c; 5 | 6 | var something3 = () => 5; 7 | 8 | var_dump(something3()); 9 | -------------------------------------------------------------------------------- /test/fixtures/arrow_functions.php: -------------------------------------------------------------------------------- 1 | _something = $something; 6 | } 7 | public $_something; 8 | 9 | 10 | public function toArray( $model, $array ) { 11 | return $array; 12 | } 13 | 14 | public function hello() { 15 | return 'Hello world'; 16 | } 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | public function creating( $model ) { 27 | Mail::send( [ 28 | 'body' => Module::template( 'signup-confirmation' )->compile( [ 29 | 'base_url' => AppConfig::get( 'retrieve.email.url' ) 30 | ] 31 | ), 32 | 'subject' => 'Sign-up confirmation', 33 | 'to' => $model->email, 34 | 'from' => 'somebody@example.com' 35 | ] 36 | ); 37 | } 38 | 39 | public function updating( $model ) { 40 | if ( $model->isDirty( 'status' ) && $model->status == 1 ) { 41 | 42 | Mail::send( [ 43 | 'body' => Module::template( 'signup-approved' )->compile( [ 44 | 'BASE_URL' => AppConfig::get( 'retrieve.email.url' ) 45 | ] 46 | ), 47 | 'subject' => 'Approved!', 48 | 'to' => $model->email, 49 | 'from' => 'somebody@example.com' 50 | ] 51 | ); 52 | 53 | } 54 | } 55 | 56 | function __get($_property) { 57 | if ($_property === 'something') { 58 | return 'Something: ' . $this->_something; 59 | } 60 | } 61 | function __set($_property, $value) { 62 | if ($_property === 'something') { 63 | $this->_something = $value + 10; 64 | } 65 | } 66 | } 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | // Instantiate class and call getter method 95 | $example = new ClassExample( 'awesome' ); 96 | var_dump( call_user_func_array( [ $example, 'hello' ], [] ) ); 97 | var_dump( $example->hello() ); 98 | 99 | $c = ( new ClassExample( 'cool' ) )->hello(); 100 | -------------------------------------------------------------------------------- /test/fixtures/class_inheritance.js: -------------------------------------------------------------------------------- 1 | class Page { 2 | constructor(title, body) { 3 | this.title = title 4 | this.body = body 5 | } 6 | 7 | getDescription() { 8 | return `${this.title}: ${this.body}` 9 | } 10 | } 11 | class Article extends Page { 12 | constructor(title, body, author) { 13 | super(title, body) 14 | this.author = author 15 | } 16 | 17 | getDescription() { 18 | let descrition = parent.getDescription() 19 | return `${description} by ${this.author}` 20 | } 21 | } 22 | 23 | var article = new Article("Wonderful article", "Yada Yada Yada", "Bob Loblaw"); 24 | var_dump(article.getDescription()); 25 | -------------------------------------------------------------------------------- /test/fixtures/class_inheritance.php: -------------------------------------------------------------------------------- 1 | title = $title; 5 | $this->body = $body; 6 | } 7 | public $title; 8 | public $body; 9 | 10 | 11 | public function getDescription() { 12 | return "{$this->title}: {$this->body}"; 13 | } 14 | } 15 | class Article extends Page { 16 | public function __construct( $title, $body, $author ) { 17 | parent::__construct( $title, $body ); 18 | $this->author = $author; 19 | } 20 | public $author; 21 | 22 | 23 | public function getDescription() { 24 | $descrition = $parent->getDescription(); 25 | return "{$description} by {$this->author}"; 26 | } 27 | } 28 | 29 | $article = new Article( 'Wonderful article', 'Yada Yada Yada', 'Bob Loblaw' ); 30 | var_dump( $article->getDescription() ); 31 | -------------------------------------------------------------------------------- /test/fixtures/closures.js: -------------------------------------------------------------------------------- 1 | d = 10; 2 | var closure = function(a) { 3 | var c = 1; 4 | return function(b) { 5 | return a + b + c + d; 6 | } 7 | } 8 | 9 | calling = closure(5); 10 | var_dump(calling(4) == 20); 11 | -------------------------------------------------------------------------------- /test/fixtures/closures.php: -------------------------------------------------------------------------------- 1 | 'Three' ], $items ) ); 14 | echo( implode( ', ', $items ) ); 15 | echo( "\n" ); 16 | 17 | $count = array_reduce( $items, function ( $curr, $string ) { 18 | return $curr + strlen( $string ); 19 | }, 0 20 | ) 21 | 22 | ; 23 | var_dump( $count ); 24 | 25 | var_dump( is_array( $items ) ); 26 | var_dump( is_array( $count ) ); 27 | 28 | /* This might not work, but it shouldn't crash! */ 29 | $a = array_slice( [ 1, 2, 3 ], 1 ); 30 | var_dump( $a ); 31 | -------------------------------------------------------------------------------- /test/fixtures/core_date.js: -------------------------------------------------------------------------------- 1 | var start = Date.now(); 2 | doSomethingExpensive(); 3 | var end = Date.now(); 4 | var_dump(end-start); 5 | -------------------------------------------------------------------------------- /test/fixtures/core_date.php: -------------------------------------------------------------------------------- 1 | 5, 4 | 'string' => 'hey', 5 | 'nested' => [ 'objects' => [ 'here' => 'yey' ] ] 6 | ] 7 | ); 8 | 9 | 10 | 11 | ; 12 | 13 | var_dump( json_encode( [ 14 | 'integer' => 5, 15 | 'string' => 'hey', 16 | 'nested' => [ 'objects' => [ 'here' => 'yey' ] ] 17 | ] 18 | ) 19 | 20 | 21 | 22 | ); 23 | -------------------------------------------------------------------------------- /test/fixtures/core_math.js: -------------------------------------------------------------------------------- 1 | var_dump(Math.E); 2 | var_dump(Math.round(5.55557)); 3 | 4 | var_dump( Math.sin(5 + 8 * Math.sqrt(200)) * Math.PI ) 5 | -------------------------------------------------------------------------------- /test/fixtures/core_math.php: -------------------------------------------------------------------------------- 1 | hasOwnProperty( 'foo' ) ); 9 | -------------------------------------------------------------------------------- /test/fixtures/core_string.js: -------------------------------------------------------------------------------- 1 | var str = "Hello"; 2 | echo(" trimmed ".trim().trim().substr(1).trim().trim().trim()); 3 | 4 | var_dump("hello".replace("lo", "ium").toUpperCase()) 5 | 6 | var_dump("something".toUpperCase()) 7 | var_dump("something".indexOf("meth")) 8 | 9 | echo(" trimmed".trimLeft()); 10 | echo("trimmed ".trimRight()); 11 | 12 | echo(str.toUpperCase().substr(1)); 13 | echo(str.toLowerCase()); 14 | echo(str.substr(1)); 15 | 16 | // output 'say Goodnight' 17 | var replace_stuff = 'say Hello'; 18 | echo(replace_stuff.replace(str, 'Goodnight')); 19 | 20 | // output 'Hello Hello 21 | var replace_stuff2 = 'say Hello'; 22 | echo(replace_stuff2.replace('say', str)); 23 | 24 | // test explode 25 | var strArray = str.split('ll'); 26 | echo(strArray[0]); 27 | 28 | // test str_split 29 | var strArray2 = str.split(''); 30 | echo(strArray2[0]); 31 | 32 | // shouldn't crash with identifier as argument. 33 | var xyz = 'll'; 34 | var strArray3 = str.split(xyz); 35 | echo(strArray3[0]); 36 | 37 | var_dump('testing'.length); 38 | 39 | var test_length = 'testing_string_variable'; 40 | var_dump(test_length.length); 41 | 42 | function lengthTest1(string) { 43 | var_dump(string.length); 44 | } 45 | function lengthTest2(string) { 46 | var_dump(string.length); 47 | } 48 | lengthTest1('hmm'); 49 | var temp = 'hmmm'; 50 | lengthTest2(temp); 51 | 52 | if (str.match(/endel/)) { 53 | var_dump(str); 54 | } 55 | 56 | var_dump("Strings with funny characters like \n and $foo and {$foo}"); 57 | var_dump('\\\\'); 58 | 59 | function foo() { return "x"; } 60 | 61 | var x = "foo" + foo(); 62 | var y = foo() + 'bar'; 63 | var z = foo() + "bar" + foo(); 64 | 65 | var typeOf = node.getAttribute('typeof'); 66 | var_dump(typeOf.match('begin')); 67 | -------------------------------------------------------------------------------- /test/fixtures/core_string.php: -------------------------------------------------------------------------------- 1 | getAttribute( 'typeof' ); 67 | var_dump( preg_match( '/begin/', $typeOf ) ); 68 | -------------------------------------------------------------------------------- /test/fixtures/date.js: -------------------------------------------------------------------------------- 1 | var now = Date.now(); 2 | echo(now); 3 | -------------------------------------------------------------------------------- /test/fixtures/date.php: -------------------------------------------------------------------------------- 1 | 'one' ], 4 | [ 'name' => 'two' ], 5 | [ 'name' => 'three' ] 6 | ]; 7 | 8 | foreach ( $items as $item => $___ ) { 9 | echo( $item[ 'name' ] ); 10 | continue; 11 | } 12 | -------------------------------------------------------------------------------- /test/fixtures/function.js: -------------------------------------------------------------------------------- 1 | 2 | function something(x, y = "something", z = 5) { 3 | var_dump(x, y, z); 4 | } 5 | 6 | function sum(a, b) { 7 | return a + b; 8 | } 9 | 10 | function hello(a, b) { 11 | return "hello!"; 12 | } 13 | 14 | var_dump(hello.apply(hello, [5,6])) 15 | var_dump(hello(5, 6)); 16 | 17 | var args = [5, 6]; 18 | var_dump(sum.apply(sum, args)); 19 | 20 | var foo = function bar() { }; 21 | 22 | // var_dump(something(5), sum(1,2)); 23 | -------------------------------------------------------------------------------- /test/fixtures/function.php: -------------------------------------------------------------------------------- 1 | read() ); 16 | -------------------------------------------------------------------------------- /test/fixtures/global_functions.js: -------------------------------------------------------------------------------- 1 | var integer = parseInt("50"); 2 | var float = parseFloat("50.50"); 3 | 4 | var_dump(integer); 5 | var_dump(float); 6 | 7 | var temp = '50.50'; 8 | var_dump(parseInt(temp)); 9 | var_dump(parseFloat(temp)); -------------------------------------------------------------------------------- /test/fixtures/global_functions.php: -------------------------------------------------------------------------------- 1 | { 2 | var_dump(arg1); 3 | ((arg2) => { 4 | var_dump(arg2); 5 | })("world!"); 6 | })("Hello"); -------------------------------------------------------------------------------- /test/fixtures/iife.php: -------------------------------------------------------------------------------- 1 | 0) { 23 | j-- 24 | var_dump(j) 25 | } 26 | 27 | var xxx = 10; 28 | 29 | do { 30 | --xxx; 31 | } while (xxx > 0); 32 | 33 | for (i=0, j=2; i5) break; 42 | } 43 | -------------------------------------------------------------------------------- /test/fixtures/loops.php: -------------------------------------------------------------------------------- 1 | 'one', 14 | 'two' => 'two', 15 | 'three' => 'three' 16 | ]; 17 | 18 | foreach ( $obj as $i => $___ ) { 19 | var_dump( $i, $obj[ $i ] ); 20 | } 21 | 22 | $j = 10; 23 | while ( $j > 0 ) { 24 | $j--; 25 | var_dump( $j ); 26 | } 27 | 28 | $xxx = 10; 29 | 30 | do { 31 | --$xxx; 32 | } while ( $xxx > 0 ); 33 | 34 | for ( $i = 0, $j = 2; $i < $j; $i++ ) { 35 | echo( $i ); 36 | } 37 | for ( $k = 0, $count = 2; $k < $count; $k++ ) { 38 | echo( $k ); 39 | } 40 | for ( ; true; ) { 41 | $i++; 42 | if ( $i > 5 ) { break; } 43 | } 44 | -------------------------------------------------------------------------------- /test/fixtures/namespaces.js: -------------------------------------------------------------------------------- 1 | export class Formula { 2 | constructor() { 3 | } 4 | 5 | static do_something() { 6 | var_dump("Something!") 7 | } 8 | } 9 | 10 | export class Hello { 11 | } 12 | 13 | export function sum(x, y) { 14 | return x + y; 15 | } 16 | export var pi = 3.141593; 17 | -------------------------------------------------------------------------------- /test/fixtures/namespaces.php: -------------------------------------------------------------------------------- 1 | do_something_else(); 15 | echo( semver::satisfies( 1, 2 ) ); 16 | echo( semver::satisfies( 1, 2 )->something_else() ); 17 | echo( [ 'Foo' => Foo::class, 'Bar' => Bar::class ] ); 18 | 19 | $foo = 3; 20 | $n = new Negotiator( $foo ); 21 | -------------------------------------------------------------------------------- /test/fixtures/namespaces_use.js: -------------------------------------------------------------------------------- 1 | import {Formula as Formula1, Hello} from 'ns'; 2 | Formula1.do_something(); 3 | Hello.do_something(); 4 | -------------------------------------------------------------------------------- /test/fixtures/namespaces_use.php: -------------------------------------------------------------------------------- 1 | 'foo', 'bar' => 42 ]; 3 | $temp0 = $x; $foo = $temp0->foo; $bar = $temp0->bar; 4 | $y = 'not foo'; 5 | ( ( ( function () use ( &$x ) { $temp1 = $x; $y = $temp1->foo; return null; } ) )() ); 6 | var_dump( "{$foo} {$bar} {$y}" ); 7 | -------------------------------------------------------------------------------- /test/fixtures/parsoid.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | require('core-update.js'); 3 | const { Bat } = require('some/thing'); 4 | 5 | var bar = Promise.async(function *(x) { 6 | return (yield Bat.bat()); 7 | }); 8 | 9 | class Foo { 10 | constructor() { this.x = 1; } 11 | } 12 | -------------------------------------------------------------------------------- /test/fixtures/parsoid.php: -------------------------------------------------------------------------------- 1 | x = 1; } 14 | public $x; 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/regexp.js: -------------------------------------------------------------------------------- 1 | var one = "Hello".match(/llo/); 2 | var_dump(one); 3 | 4 | var two = "Hello".match(/llo/g); 5 | var_dump(two); 6 | 7 | var splitted = "one, two, three".split(","); 8 | var_dump(splitted); 9 | 10 | var splitted = "one, two, three".split(/,/); 11 | var_dump(splitted); 12 | 13 | var g_splitted = "one, two, three".split(/,/g); 14 | var_dump(g_splitted); 15 | 16 | var_dump("hey".replace("y", "llo")); 17 | var_dump("hey".replace(/y/, "llo")); 18 | var_dump("hey hey hey".replace(/y/, "llo")); 19 | var_dump("hey hey hey".replace(/y/g, "llo")); 20 | 21 | var string = 'hello'; 22 | var regex = 'ello'; 23 | var nonliteral = string.match(regex); 24 | 25 | var_dump(/abc\n[/]/.test('def')); 26 | var_dump(/[\n]/.source.slice(1,-1)); 27 | 28 | var_dump("./a/b/c".replace(/\.\//, '')); 29 | 30 | var matches = /[abc]/gi.exec("LA la black sheep"); 31 | 32 | var firstA = unknownValue(); 33 | if (firstA && /^#/.test(firstA.getAttribute('href'))) { 34 | var_dump("whoo"); 35 | } 36 | 37 | // Tricky escape cases. 38 | var x = /abc\n'"\/\\/i.source; // should be "abc\\n'\"\\/\\\\" 39 | var y = /abc\n'"\/\\/i.test("ABC\n'\"/\\"); // should be true 40 | // This only returns one match, but it uses the lastIndex property: 41 | var z1 = /abc\n'"\/\\/ig.exec("abc\n'\"/\\xyzABC\n'\"/\\"); 42 | var z2 = "Qabc\n'\"/\\xyzABC\n'\"/\\Q".split(/abc\n'"\/\\/ig); 43 | // z2 should be [ 'Q', 'xyz', 'Q' ] 44 | var z3 = "Qabc\n'\"/\\xyzABC\n'\"/\\Q".match(/abc\n'"\/\\/ig); 45 | // z3 should be [ 'abc\n\'"/\\', 'ABC\n\'"/\\' ] 46 | var z4 = "Qabc\n'\"/\\xyzABC\n'\"/\\Q".replace(/abc\n'"\/\\/ig, "x"); 47 | // z4 should be 'QxxyzxQ' 48 | var z5 = /^text\/html;/.test("text/html; quality=2"); 49 | // z5 should be true 50 | -------------------------------------------------------------------------------- /test/fixtures/regexp.php: -------------------------------------------------------------------------------- 1 | getAttribute( 'href' ) ) ) { 35 | var_dump( 'whoo' ); 36 | } 37 | 38 | // Tricky escape cases. 39 | $x = "abc\\n'\"\\/\\\\"; // should be "abc\\n'\"\\/\\\\" 40 | $y = preg_match( "/abc\\n'\"\\/\\\\/", "ABC\n'\"/\\" ); // should be true 41 | // This only returns one match, but it uses the lastIndex property: 42 | $z1 = /*RegExp#exec*/preg_match_all( "/abc\\n'\"\\/\\\\/i", "abc\n'\"/\\xyzABC\n'\"/\\", $FIXME ); 43 | $z2 = preg_split( "/abc\\n'\"\\/\\\\/i", "Qabc\n'\"/\\xyzABC\n'\"/\\Q" ); 44 | // z2 should be [ 'Q', 'xyz', 'Q' ] 45 | $z3 = preg_match_all( "/abc\\n'\"\\/\\\\/i", "Qabc\n'\"/\\xyzABC\n'\"/\\Q", $FIXME ); 46 | // z3 should be [ 'abc\n\'"/\\', 'ABC\n\'"/\\' ] 47 | $z4 = preg_replace( "/abc\\n'\"\\/\\\\/i", 'x', "Qabc\n'\"/\\xyzABC\n'\"/\\Q" ); 48 | // z4 should be 'QxxyzxQ' 49 | $z5 = preg_match( '/^text\/html;/', 'text/html; quality=2' ); 50 | // z5 should be true 51 | -------------------------------------------------------------------------------- /test/fixtures/rest_spread.js: -------------------------------------------------------------------------------- 1 | var x = (...args) => args.length; 2 | var y = (z) => x(...z); 3 | 4 | var_dump(x(1, 2, 3, 4)); 5 | var_dump(y([1, 2, 3])); 6 | -------------------------------------------------------------------------------- /test/fixtures/rest_spread.php: -------------------------------------------------------------------------------- 1 | log( $x, $y ); 7 | $console->log( $z ); 8 | 9 | var_dump( [ 'a' => 1, 'b-c' => 'c', 'd-e-fh' => g( 0 ), 'hi' => 'hi' ] ); 10 | 11 | $obj = [ 'key' => 'value', 'key2' => 'value2' ]; 12 | unset( $obj[ 'key' ] ); 13 | var_dump( isset( $something[ 'key2' ] ) ); 14 | var_dump( gettype( $something ) !== NULL ); 15 | -------------------------------------------------------------------------------- /test/fixtures/static_call.js: -------------------------------------------------------------------------------- 1 | 2 | Module.Http.Router.get('/send', function() { 3 | return this.json({ 4 | success: Mail.send({ 5 | body: Module.template('signup-confirmation').compile({ 6 | base_url: AppConfig.get("retrieve.email.url") 7 | }), 8 | subject: "Sign-up confirmation", 9 | to: model.email, 10 | from: "somebody@example.com" 11 | }) 12 | }) 13 | }); 14 | -------------------------------------------------------------------------------- /test/fixtures/static_call.php: -------------------------------------------------------------------------------- 1 | json( [ 5 | 'success' => Mail::send( [ 6 | 'body' => Module::template( 'signup-confirmation' )->compile( [ 7 | 'base_url' => AppConfig::get( 'retrieve.email.url' ) 8 | ] 9 | ), 10 | 'subject' => 'Sign-up confirmation', 11 | 'to' => $model->email, 12 | 'from' => 'somebody@example.com' 13 | ] 14 | ) 15 | ] 16 | ); 17 | } 18 | ); 19 | -------------------------------------------------------------------------------- /test/fixtures/string_template.js: -------------------------------------------------------------------------------- 1 | var str1 = "one" 2 | , str2 = "two" 3 | , n1 = Math.PI 4 | , n2 = 50 5 | , func = () => { 6 | return "from function" 7 | } 8 | 9 | 10 | class Item { 11 | method () { 12 | return "from method"; 13 | } 14 | } 15 | var item = new Item(); 16 | 17 | echo(`${str1}, ${str2}, ${n1}, ${n2}, ${ item.method() }, ${ func() }`) 18 | 19 | echo(`funny characters like " and \n should be fine ${ 1 + 2 }`); 20 | -------------------------------------------------------------------------------- /test/fixtures/string_template.php: -------------------------------------------------------------------------------- 1 | method()}, {$func()}" ); 19 | 20 | echo( "funny characters like \" and \n should be fine {1 + 2}" ); 21 | -------------------------------------------------------------------------------- /test/generate.js: -------------------------------------------------------------------------------- 1 | // 2 | // Generate PHP from JS fixture files 3 | // 4 | var js2php = require('../index.js'), 5 | fs = require('fs'), 6 | fixturePath = './test/fixtures/', 7 | fixtures = fs.readdirSync(fixturePath), 8 | target = process.argv[2]; 9 | 10 | if (!target) { 11 | console.log("Usage:"); 12 | console.log(""); 13 | console.log("Generate PHP for all fixtures files:"); 14 | console.log("\tnode test/generate.js all"); 15 | console.log(""); 16 | console.log("Generate PHP for single fixture file:"); 17 | console.log("\tnode test/generate.js js_feature.js"); 18 | 19 | } else if (target.toLowerCase().trim() == "all") { 20 | target = /\.js$/; 21 | } else { 22 | target = new RegExp(target + "$"); 23 | } 24 | 25 | for(var i=0;i '" + e.message + "'", e.stack); 43 | } 44 | } 45 | } 46 | 47 | -------------------------------------------------------------------------------- /test/suite.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"), 2 | fs = require('fs'), 3 | js2php = require('../index.js'), 4 | fixturesPath = './test/fixtures/', 5 | fixtures = fs.readdirSync(fixturesPath).filter(function(file) { return !file.match(/~$/) }), 6 | sources = []; 7 | 8 | for(var i=0;i