├── .github ├── dependabot.yml └── workflows │ └── ci.yml ├── .gitignore ├── .npmignore ├── CHANGELOG.md ├── LICENSE ├── build.js ├── cli.js ├── example ├── out │ ├── flat.html │ ├── flat.js │ ├── standard.html │ └── standard.js ├── package.json ├── readme.md └── src │ ├── app.js │ └── view.js ├── index.js ├── lib ├── createModuleFactory.js └── exposedRequire.js ├── package.json ├── plugin.js ├── private_modules └── identifierfy │ ├── LICENSE │ ├── README.md │ ├── index.js │ └── package.json ├── readme.md └── test ├── bare-module ├── app.js ├── expected.js └── wrapped.js ├── colliding-unused ├── app.js ├── expected.js └── other.js ├── comment ├── app.js ├── expected.js └── other.js ├── dedupe ├── a │ ├── index.js │ └── xyz.js ├── app.js ├── b │ ├── index.js │ └── xyz.js └── expected.js ├── dep-order ├── app.js ├── expected.js ├── one.js ├── three.js └── two.js ├── destructure ├── app.js ├── expected.js └── greeting.js ├── dynamic-require ├── app.js └── expected.js ├── eager-cycles ├── a.js ├── app.js ├── b.js ├── c.js ├── d.js ├── e.js └── expected.js ├── exports-name ├── app.js ├── class.js ├── expected.js ├── fn.js └── var.js ├── expose.js ├── expose ├── anotherLocalModule.js ├── externalModule.js ├── externalSeparator.js ├── index.js └── localModule.js ├── globals ├── app.js ├── expected.js ├── fn.js └── other.js ├── input-source-map ├── .babelrc ├── app.js ├── dep.js ├── expected.js └── options.json ├── lazy-cycles ├── a.js ├── app.js ├── b.js └── expected.js ├── lazy-expose ├── a.js ├── app.js └── b.js ├── lazy-order ├── a.js ├── app.js ├── b.js ├── c.js ├── d.js └── expected.js ├── module-parent ├── app.js ├── child.js └── expected.js ├── order.js ├── parent-cycle ├── app.js └── router.js ├── plugin.js ├── remove-decl ├── a.js ├── app.js └── expected.js ├── self.js ├── set-exports ├── app.js ├── both.js ├── expected.js ├── exports-only.js ├── free-module.js ├── module-exports.js └── quoted.js ├── shorthand ├── app.js ├── expected.js └── importedModule.js ├── simplify ├── app.js ├── asi.js ├── expected.js ├── hello.js └── world.js ├── source-map ├── app.js ├── b.js ├── expected.js └── options.json ├── standalone ├── a.js ├── app.js ├── b.js ├── expected.js └── options.json ├── test.js ├── typeof-require ├── app.js └── expected.js └── variable ├── app.js ├── expected.js └── param.js /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "04:00" 8 | open-pull-requests-limit: 10 9 | ignore: 10 | - dependency-name: nanohtml 11 | versions: 12 | - "> 1.6.1" 13 | - dependency-name: uglify-js 14 | versions: 15 | - "> 3.6.0" 16 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Node CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | 9 | strategy: 10 | matrix: 11 | node-version: 12 | - 4.x 13 | - 6.x 14 | - 8.x 15 | - 9.x 16 | - 10.x 17 | - 11.x 18 | - 12.x 19 | - 13.x 20 | - 14.x 21 | - 15.x 22 | - 16.x 23 | - 17.x 24 | - 18.x 25 | - 19.x 26 | - 20.x 27 | - 21.x 28 | - 22.x 29 | 30 | steps: 31 | - uses: actions/checkout@v4 32 | - name: Use Node.js ${{ matrix.node-version }} 33 | uses: actions/setup-node@v4 34 | with: 35 | node-version: ${{ matrix.node-version }} 36 | - name: Install dependencies 37 | run: npm install 38 | - name: Run tests 39 | run: npm test 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | test/self.*.expected.js 3 | test/self.*.actual.js 4 | actual.js 5 | package-lock.json 6 | /_*.js 7 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test/self.*.expected.js 2 | test/self.*.actual.js 3 | actual.js 4 | example/node_modules 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # browser-pack-flat change log 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | This project adheres to [Semantic Versioning](http://semver.org/). 6 | 7 | ## 3.5.0 8 | * Expose `ecmaVersion` option. (@ralphtheninja) 9 | 10 | ## 3.4.2 11 | * Fix lazy exposed modules. (#41) 12 | 13 | ## 3.4.1 14 | * Inline result of `typeof require`, which is used by some UMD headers. (#38) 15 | 16 | ## 3.4.0 17 | * Sort dependencies by source order location, now execution order should be much more consistent between Node.js and browser-pack-flat 18 | * Prevent inlining conditional and lazy `require()` calls: 19 | ```js 20 | // this no longer evaluates 'a' if condition is false 21 | if (condition) require('a') 22 | 23 | // this now evaluates 'b' first, then console.log(), and then 'c' once lazy() is called, 24 | // instead of evaluating 'b' and 'c' before entering the module 25 | function lazy () { require('c') } 26 | require('b') 27 | console.log() 28 | lazy() 29 | 30 | // NOTE this *will* still cause out-of-order evaluation! 'b' will be evaluated before 31 | // console.log() is called. 32 | console.log() 33 | require('b') 34 | ``` 35 | 36 | ## 3.3.0 37 | * Start changelog. 38 | * Add `iife: false` option to remove the outer `(function(){})` wrapper if you don't need it (@brechtcs) 39 | * Add `sourceType` option to not crash on `import` statements. (@brechtcs) 40 | Don't use this unless you are certain that you have a good use case for it. 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Renée Kooi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /build.js: -------------------------------------------------------------------------------- 1 | var minify = require('uglify-js').minify 2 | var fs = require('fs') 3 | 4 | var createModuleFactory = minify(require('./lib/createModuleFactory').toString()).code 5 | var exposedRequire = minify(require('./lib/exposedRequire').toString()).code 6 | 7 | fs.writeFileSync('./_createModuleFactory.js', createModuleFactory) 8 | fs.writeFileSync('./_exposedRequire.js', exposedRequire) 9 | -------------------------------------------------------------------------------- /cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var pack = require('./') 4 | 5 | process.stdin 6 | .pipe(pack()) 7 | .pipe(process.stdout) 8 | -------------------------------------------------------------------------------- /example/out/flat.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | browser-pack-flat 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /example/out/flat.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | assert.notEqual = notEqual 3 | assert.notOk = notOk 4 | assert.equal = equal 5 | assert.ok = assert 6 | 7 | var _$assert_3 = assert 8 | 9 | function equal (a, b, m) { 10 | assert(a == b, m) // eslint-disable-line eqeqeq 11 | } 12 | 13 | function notEqual (a, b, m) { 14 | assert(a != b, m) // eslint-disable-line eqeqeq 15 | } 16 | 17 | function notOk (t, m) { 18 | assert(!t, m) 19 | } 20 | 21 | function assert (t, m) { 22 | if (!t) throw new Error(m || 'AssertionError') 23 | } 24 | 25 | var _$events_10 = [ 26 | // attribute events (can be set with attributes) 27 | 'onclick', 28 | 'ondblclick', 29 | 'onmousedown', 30 | 'onmouseup', 31 | 'onmouseover', 32 | 'onmousemove', 33 | 'onmouseout', 34 | 'onmouseenter', 35 | 'onmouseleave', 36 | 'ontouchcancel', 37 | 'ontouchend', 38 | 'ontouchmove', 39 | 'ontouchstart', 40 | 'ondragstart', 41 | 'ondrag', 42 | 'ondragenter', 43 | 'ondragleave', 44 | 'ondragover', 45 | 'ondrop', 46 | 'ondragend', 47 | 'onkeydown', 48 | 'onkeypress', 49 | 'onkeyup', 50 | 'onunload', 51 | 'onabort', 52 | 'onerror', 53 | 'onresize', 54 | 'onscroll', 55 | 'onselect', 56 | 'onchange', 57 | 'onsubmit', 58 | 'onreset', 59 | 'onfocus', 60 | 'onblur', 61 | 'oninput', 62 | // other common events 63 | 'oncontextmenu', 64 | 'onfocusin', 65 | 'onfocusout' 66 | ] 67 | 68 | /* removed: var _$events_10 = require('./events') */; 69 | var eventsLength = _$events_10.length 70 | 71 | var ELEMENT_NODE = 1 72 | var TEXT_NODE = 3 73 | var COMMENT_NODE = 8 74 | 75 | var _$morph_11 = morph 76 | 77 | // diff elements and apply the resulting patch to the old node 78 | // (obj, obj) -> null 79 | function morph (newNode, oldNode) { 80 | var nodeType = newNode.nodeType 81 | var nodeName = newNode.nodeName 82 | 83 | if (nodeType === ELEMENT_NODE) { 84 | copyAttrs(newNode, oldNode) 85 | } 86 | 87 | if (nodeType === TEXT_NODE || nodeType === COMMENT_NODE) { 88 | if (oldNode.nodeValue !== newNode.nodeValue) { 89 | oldNode.nodeValue = newNode.nodeValue 90 | } 91 | } 92 | 93 | // Some DOM nodes are weird 94 | // https://github.com/patrick-steele-idem/morphdom/blob/master/src/specialElHandlers.js 95 | if (nodeName === 'INPUT') updateInput(newNode, oldNode) 96 | else if (nodeName === 'OPTION') updateOption(newNode, oldNode) 97 | else if (nodeName === 'TEXTAREA') updateTextarea(newNode, oldNode) 98 | 99 | copyEvents(newNode, oldNode) 100 | } 101 | 102 | function copyAttrs (newNode, oldNode) { 103 | var oldAttrs = oldNode.attributes 104 | var newAttrs = newNode.attributes 105 | var attrNamespaceURI = null 106 | var attrValue = null 107 | var fromValue = null 108 | var attrName = null 109 | var attr = null 110 | 111 | for (var i = newAttrs.length - 1; i >= 0; --i) { 112 | attr = newAttrs[i] 113 | attrName = attr.name 114 | attrNamespaceURI = attr.namespaceURI 115 | attrValue = attr.value 116 | if (attrNamespaceURI) { 117 | attrName = attr.localName || attrName 118 | fromValue = oldNode.getAttributeNS(attrNamespaceURI, attrName) 119 | if (fromValue !== attrValue) { 120 | oldNode.setAttributeNS(attrNamespaceURI, attrName, attrValue) 121 | } 122 | } else { 123 | if (!oldNode.hasAttribute(attrName)) { 124 | oldNode.setAttribute(attrName, attrValue) 125 | } else { 126 | fromValue = oldNode.getAttribute(attrName) 127 | if (fromValue !== attrValue) { 128 | // apparently values are always cast to strings, ah well 129 | if (attrValue === 'null' || attrValue === 'undefined') { 130 | oldNode.removeAttribute(attrName) 131 | } else { 132 | oldNode.setAttribute(attrName, attrValue) 133 | } 134 | } 135 | } 136 | } 137 | } 138 | 139 | // Remove any extra attributes found on the original DOM element that 140 | // weren't found on the target element. 141 | for (var j = oldAttrs.length - 1; j >= 0; --j) { 142 | attr = oldAttrs[j] 143 | if (attr.specified !== false) { 144 | attrName = attr.name 145 | attrNamespaceURI = attr.namespaceURI 146 | 147 | if (attrNamespaceURI) { 148 | attrName = attr.localName || attrName 149 | if (!newNode.hasAttributeNS(attrNamespaceURI, attrName)) { 150 | oldNode.removeAttributeNS(attrNamespaceURI, attrName) 151 | } 152 | } else { 153 | if (!newNode.hasAttributeNS(null, attrName)) { 154 | oldNode.removeAttribute(attrName) 155 | } 156 | } 157 | } 158 | } 159 | } 160 | 161 | function copyEvents (newNode, oldNode) { 162 | for (var i = 0; i < eventsLength; i++) { 163 | var ev = _$events_10[i] 164 | if (newNode[ev]) { // if new element has a whitelisted attribute 165 | oldNode[ev] = newNode[ev] // update existing element 166 | } else if (oldNode[ev]) { // if existing element has it and new one doesnt 167 | oldNode[ev] = undefined // remove it from existing element 168 | } 169 | } 170 | } 171 | 172 | function updateOption (newNode, oldNode) { 173 | updateAttribute(newNode, oldNode, 'selected') 174 | } 175 | 176 | // The "value" attribute is special for the element since it sets the 177 | // initial value. Changing the "value" attribute without changing the "value" 178 | // property will have no effect since it is only used to the set the initial 179 | // value. Similar for the "checked" attribute, and "disabled". 180 | function updateInput (newNode, oldNode) { 181 | var newValue = newNode.value 182 | var oldValue = oldNode.value 183 | 184 | updateAttribute(newNode, oldNode, 'checked') 185 | updateAttribute(newNode, oldNode, 'disabled') 186 | 187 | if (newValue !== oldValue) { 188 | oldNode.setAttribute('value', newValue) 189 | oldNode.value = newValue 190 | } 191 | 192 | if (newValue === 'null') { 193 | oldNode.value = '' 194 | oldNode.removeAttribute('value') 195 | } 196 | 197 | if (!newNode.hasAttributeNS(null, 'value')) { 198 | oldNode.removeAttribute('value') 199 | } else if (oldNode.type === 'range') { 200 | // this is so elements like slider move their UI thingy 201 | oldNode.value = newValue 202 | } 203 | } 204 | 205 | function updateTextarea (newNode, oldNode) { 206 | var newValue = newNode.value 207 | if (newValue !== oldNode.value) { 208 | oldNode.value = newValue 209 | } 210 | 211 | if (oldNode.firstChild && oldNode.firstChild.nodeValue !== newValue) { 212 | // Needed for IE. Apparently IE sets the placeholder as the 213 | // node value and vise versa. This ignores an empty update. 214 | if (newValue === '' && oldNode.firstChild.nodeValue === oldNode.placeholder) { 215 | return 216 | } 217 | 218 | oldNode.firstChild.nodeValue = newValue 219 | } 220 | } 221 | 222 | function updateAttribute (newNode, oldNode, name) { 223 | if (newNode[name] !== oldNode[name]) { 224 | oldNode[name] = newNode[name] 225 | if (newNode[name]) { 226 | oldNode.setAttribute(name, '') 227 | } else { 228 | oldNode.removeAttribute(name) 229 | } 230 | } 231 | } 232 | 233 | /* removed: var _$assert_3 = require('assert') */; 234 | /* removed: var _$morph_11 = require('./lib/morph') */; 235 | 236 | var __TEXT_NODE_9 = 3 237 | // var DEBUG = false 238 | 239 | var _$nanomorph_9 = nanomorph 240 | 241 | // Morph one tree into another tree 242 | // 243 | // no parent 244 | // -> same: diff and walk children 245 | // -> not same: replace and return 246 | // old node doesn't exist 247 | // -> insert new node 248 | // new node doesn't exist 249 | // -> delete old node 250 | // nodes are not the same 251 | // -> diff nodes and apply patch to old node 252 | // nodes are the same 253 | // -> walk all child nodes and append to old node 254 | function nanomorph (oldTree, newTree) { 255 | // if (DEBUG) { 256 | // console.log( 257 | // 'nanomorph\nold\n %s\nnew\n %s', 258 | // oldTree && oldTree.outerHTML, 259 | // newTree && newTree.outerHTML 260 | // ) 261 | // } 262 | _$assert_3.equal(typeof oldTree, 'object', 'nanomorph: oldTree should be an object') 263 | _$assert_3.equal(typeof newTree, 'object', 'nanomorph: newTree should be an object') 264 | var tree = walk(newTree, oldTree) 265 | // if (DEBUG) console.log('=> morphed\n %s', tree.outerHTML) 266 | return tree 267 | } 268 | 269 | // Walk and morph a dom tree 270 | function walk (newNode, oldNode) { 271 | // if (DEBUG) { 272 | // console.log( 273 | // 'walk\nold\n %s\nnew\n %s', 274 | // oldNode && oldNode.outerHTML, 275 | // newNode && newNode.outerHTML 276 | // ) 277 | // } 278 | if (!oldNode) { 279 | return newNode 280 | } else if (!newNode) { 281 | return null 282 | } else if (newNode.isSameNode && newNode.isSameNode(oldNode)) { 283 | return oldNode 284 | } else if (newNode.tagName !== oldNode.tagName) { 285 | return newNode 286 | } else { 287 | _$morph_11(newNode, oldNode) 288 | updateChildren(newNode, oldNode) 289 | return oldNode 290 | } 291 | } 292 | 293 | // Update the children of elements 294 | // (obj, obj) -> null 295 | function updateChildren (newNode, oldNode) { 296 | // if (DEBUG) { 297 | // console.log( 298 | // 'updateChildren\nold\n %s\nnew\n %s', 299 | // oldNode && oldNode.outerHTML, 300 | // newNode && newNode.outerHTML 301 | // ) 302 | // } 303 | var oldChild, newChild, morphed, oldMatch 304 | 305 | // The offset is only ever increased, and used for [i - offset] in the loop 306 | var offset = 0 307 | 308 | for (var i = 0; ; i++) { 309 | oldChild = oldNode.childNodes[i] 310 | newChild = newNode.childNodes[i - offset] 311 | // if (DEBUG) { 312 | // console.log( 313 | // '===\n- old\n %s\n- new\n %s', 314 | // oldChild && oldChild.outerHTML, 315 | // newChild && newChild.outerHTML 316 | // ) 317 | // } 318 | // Both nodes are empty, do nothing 319 | if (!oldChild && !newChild) { 320 | break 321 | 322 | // There is no new child, remove old 323 | } else if (!newChild) { 324 | oldNode.removeChild(oldChild) 325 | i-- 326 | 327 | // There is no old child, add new 328 | } else if (!oldChild) { 329 | oldNode.appendChild(newChild) 330 | offset++ 331 | 332 | // Both nodes are the same, morph 333 | } else if (same(newChild, oldChild)) { 334 | morphed = walk(newChild, oldChild) 335 | if (morphed !== oldChild) { 336 | oldNode.replaceChild(morphed, oldChild) 337 | offset++ 338 | } 339 | 340 | // Both nodes do not share an ID or a placeholder, try reorder 341 | } else { 342 | oldMatch = null 343 | 344 | // Try and find a similar node somewhere in the tree 345 | for (var j = i; j < oldNode.childNodes.length; j++) { 346 | if (same(oldNode.childNodes[j], newChild)) { 347 | oldMatch = oldNode.childNodes[j] 348 | break 349 | } 350 | } 351 | 352 | // If there was a node with the same ID or placeholder in the old list 353 | if (oldMatch) { 354 | morphed = walk(newChild, oldMatch) 355 | if (morphed !== oldMatch) offset++ 356 | oldNode.insertBefore(morphed, oldChild) 357 | 358 | // It's safe to morph two nodes in-place if neither has an ID 359 | } else if (!newChild.id && !oldChild.id) { 360 | morphed = walk(newChild, oldChild) 361 | if (morphed !== oldChild) { 362 | oldNode.replaceChild(morphed, oldChild) 363 | offset++ 364 | } 365 | 366 | // Insert the node at the index if we couldn't morph or find a matching node 367 | } else { 368 | oldNode.insertBefore(newChild, oldChild) 369 | offset++ 370 | } 371 | } 372 | } 373 | } 374 | 375 | function same (a, b) { 376 | if (a.id) return a.id === b.id 377 | if (a.isSameNode) return a.isSameNode(b) 378 | if (a.tagName !== b.tagName) return false 379 | if (a.type === __TEXT_NODE_9) return a.nodeValue === b.nodeValue 380 | return false 381 | } 382 | 383 | var _$attributeToProperty_1 = attributeToProperty 384 | 385 | var transform = { 386 | 'class': 'className', 387 | 'for': 'htmlFor', 388 | 'http-equiv': 'httpEquiv' 389 | } 390 | 391 | function attributeToProperty (h) { 392 | return function (tagName, attrs, children) { 393 | for (var attr in attrs) { 394 | if (attr in transform) { 395 | attrs[transform[attr]] = attrs[attr] 396 | delete attrs[attr] 397 | } 398 | } 399 | return h(tagName, attrs, children) 400 | } 401 | } 402 | 403 | /* removed: var _$attributeToProperty_1 = require('hyperscript-attribute-to-property') */; 404 | 405 | var VAR = 0, TEXT = 1, OPEN = 2, CLOSE = 3, ATTR = 4 406 | var ATTR_KEY = 5, ATTR_KEY_W = 6 407 | var ATTR_VALUE_W = 7, ATTR_VALUE = 8 408 | var ATTR_VALUE_SQ = 9, ATTR_VALUE_DQ = 10 409 | var ATTR_EQ = 11, ATTR_BREAK = 12 410 | var COMMENT = 13 411 | 412 | var _$hyperx_2 = function (h, opts) { 413 | if (!opts) opts = {} 414 | var concat = opts.concat || function (a, b) { 415 | return String(a) + String(b) 416 | } 417 | if (opts.attrToProp !== false) { 418 | h = _$attributeToProperty_1(h) 419 | } 420 | 421 | return function (strings) { 422 | var state = TEXT, reg = '' 423 | var arglen = arguments.length 424 | var parts = [] 425 | 426 | for (var i = 0; i < strings.length; i++) { 427 | if (i < arglen - 1) { 428 | var arg = arguments[i+1] 429 | var p = parse(strings[i]) 430 | var xstate = state 431 | if (xstate === ATTR_VALUE_DQ) xstate = ATTR_VALUE 432 | if (xstate === ATTR_VALUE_SQ) xstate = ATTR_VALUE 433 | if (xstate === ATTR_VALUE_W) xstate = ATTR_VALUE 434 | if (xstate === ATTR) xstate = ATTR_KEY 435 | if (xstate === OPEN) { 436 | if (reg === '/') { 437 | p.push([ OPEN, '/', arg ]) 438 | reg = '' 439 | } else { 440 | p.push([ OPEN, arg ]) 441 | } 442 | } else { 443 | p.push([ VAR, xstate, arg ]) 444 | } 445 | parts.push.apply(parts, p) 446 | } else parts.push.apply(parts, parse(strings[i])) 447 | } 448 | 449 | var tree = [null,{},[]] 450 | var stack = [[tree,-1]] 451 | for (var i = 0; i < parts.length; i++) { 452 | var cur = stack[stack.length-1][0] 453 | var p = parts[i], s = p[0] 454 | if (s === OPEN && /^\//.test(p[1])) { 455 | var ix = stack[stack.length-1][1] 456 | if (stack.length > 1) { 457 | stack.pop() 458 | stack[stack.length-1][0][2][ix] = h( 459 | cur[0], cur[1], cur[2].length ? cur[2] : undefined 460 | ) 461 | } 462 | } else if (s === OPEN) { 463 | var c = [p[1],{},[]] 464 | cur[2].push(c) 465 | stack.push([c,cur[2].length-1]) 466 | } else if (s === ATTR_KEY || (s === VAR && p[1] === ATTR_KEY)) { 467 | var key = '' 468 | var copyKey 469 | for (; i < parts.length; i++) { 470 | if (parts[i][0] === ATTR_KEY) { 471 | key = concat(key, parts[i][1]) 472 | } else if (parts[i][0] === VAR && parts[i][1] === ATTR_KEY) { 473 | if (typeof parts[i][2] === 'object' && !key) { 474 | for (copyKey in parts[i][2]) { 475 | if (parts[i][2].hasOwnProperty(copyKey) && !cur[1][copyKey]) { 476 | cur[1][copyKey] = parts[i][2][copyKey] 477 | } 478 | } 479 | } else { 480 | key = concat(key, parts[i][2]) 481 | } 482 | } else break 483 | } 484 | if (parts[i][0] === ATTR_EQ) i++ 485 | var j = i 486 | for (; i < parts.length; i++) { 487 | if (parts[i][0] === ATTR_VALUE || parts[i][0] === ATTR_KEY) { 488 | if (!cur[1][key]) cur[1][key] = strfn(parts[i][1]) 489 | else parts[i][1]==="" || (cur[1][key] = concat(cur[1][key], parts[i][1])); 490 | } else if (parts[i][0] === VAR 491 | && (parts[i][1] === ATTR_VALUE || parts[i][1] === ATTR_KEY)) { 492 | if (!cur[1][key]) cur[1][key] = strfn(parts[i][2]) 493 | else parts[i][2]==="" || (cur[1][key] = concat(cur[1][key], parts[i][2])); 494 | } else { 495 | if (key.length && !cur[1][key] && i === j 496 | && (parts[i][0] === CLOSE || parts[i][0] === ATTR_BREAK)) { 497 | // https://html.spec.whatwg.org/multipage/infrastructure.html#boolean-attributes 498 | // empty string is falsy, not well behaved value in browser 499 | cur[1][key] = key.toLowerCase() 500 | } 501 | if (parts[i][0] === CLOSE) { 502 | i-- 503 | } 504 | break 505 | } 506 | } 507 | } else if (s === ATTR_KEY) { 508 | cur[1][p[1]] = true 509 | } else if (s === VAR && p[1] === ATTR_KEY) { 510 | cur[1][p[2]] = true 511 | } else if (s === CLOSE) { 512 | if (selfClosing(cur[0]) && stack.length) { 513 | var ix = stack[stack.length-1][1] 514 | stack.pop() 515 | stack[stack.length-1][0][2][ix] = h( 516 | cur[0], cur[1], cur[2].length ? cur[2] : undefined 517 | ) 518 | } 519 | } else if (s === VAR && p[1] === TEXT) { 520 | if (p[2] === undefined || p[2] === null) p[2] = '' 521 | else if (!p[2]) p[2] = concat('', p[2]) 522 | if (Array.isArray(p[2][0])) { 523 | cur[2].push.apply(cur[2], p[2]) 524 | } else { 525 | cur[2].push(p[2]) 526 | } 527 | } else if (s === TEXT) { 528 | cur[2].push(p[1]) 529 | } else if (s === ATTR_EQ || s === ATTR_BREAK) { 530 | // no-op 531 | } else { 532 | throw new Error('unhandled: ' + s) 533 | } 534 | } 535 | 536 | if (tree[2].length > 1 && /^\s*$/.test(tree[2][0])) { 537 | tree[2].shift() 538 | } 539 | 540 | if (tree[2].length > 2 541 | || (tree[2].length === 2 && /\S/.test(tree[2][1]))) { 542 | throw new Error( 543 | 'multiple root elements must be wrapped in an enclosing tag' 544 | ) 545 | } 546 | if (Array.isArray(tree[2][0]) && typeof tree[2][0][0] === 'string' 547 | && Array.isArray(tree[2][0][2])) { 548 | tree[2][0] = h(tree[2][0][0], tree[2][0][1], tree[2][0][2]) 549 | } 550 | return tree[2][0] 551 | 552 | function parse (str) { 553 | var res = [] 554 | if (state === ATTR_VALUE_W) state = ATTR 555 | for (var i = 0; i < str.length; i++) { 556 | var c = str.charAt(i) 557 | if (state === TEXT && c === '<') { 558 | if (reg.length) res.push([TEXT, reg]) 559 | reg = '' 560 | state = OPEN 561 | } else if (c === '>' && !quot(state) && state !== COMMENT) { 562 | if (state === OPEN && reg.length) { 563 | res.push([OPEN,reg]) 564 | } else if (state === ATTR_KEY) { 565 | res.push([ATTR_KEY,reg]) 566 | } else if (state === ATTR_VALUE && reg.length) { 567 | res.push([ATTR_VALUE,reg]) 568 | } 569 | res.push([CLOSE]) 570 | reg = '' 571 | state = TEXT 572 | } else if (state === COMMENT && /-$/.test(reg) && c === '-') { 573 | if (opts.comments) { 574 | res.push([ATTR_VALUE,reg.substr(0, reg.length - 1)],[CLOSE]) 575 | } 576 | reg = '' 577 | state = TEXT 578 | } else if (state === OPEN && /^!--$/.test(reg)) { 579 | if (opts.comments) { 580 | res.push([OPEN, reg],[ATTR_KEY,'comment'],[ATTR_EQ]) 581 | } 582 | reg = c 583 | state = COMMENT 584 | } else if (state === TEXT || state === COMMENT) { 585 | reg += c 586 | } else if (state === OPEN && c === '/' && reg.length) { 587 | // no-op, self closing tag without a space
588 | } else if (state === OPEN && /\s/.test(c)) { 589 | if (reg.length) { 590 | res.push([OPEN, reg]) 591 | } 592 | reg = '' 593 | state = ATTR 594 | } else if (state === OPEN) { 595 | reg += c 596 | } else if (state === ATTR && /[^\s"'=/]/.test(c)) { 597 | state = ATTR_KEY 598 | reg = c 599 | } else if (state === ATTR && /\s/.test(c)) { 600 | if (reg.length) res.push([ATTR_KEY,reg]) 601 | res.push([ATTR_BREAK]) 602 | } else if (state === ATTR_KEY && /\s/.test(c)) { 603 | res.push([ATTR_KEY,reg]) 604 | reg = '' 605 | state = ATTR_KEY_W 606 | } else if (state === ATTR_KEY && c === '=') { 607 | res.push([ATTR_KEY,reg],[ATTR_EQ]) 608 | reg = '' 609 | state = ATTR_VALUE_W 610 | } else if (state === ATTR_KEY) { 611 | reg += c 612 | } else if ((state === ATTR_KEY_W || state === ATTR) && c === '=') { 613 | res.push([ATTR_EQ]) 614 | state = ATTR_VALUE_W 615 | } else if ((state === ATTR_KEY_W || state === ATTR) && !/\s/.test(c)) { 616 | res.push([ATTR_BREAK]) 617 | if (/[\w-]/.test(c)) { 618 | reg += c 619 | state = ATTR_KEY 620 | } else state = ATTR 621 | } else if (state === ATTR_VALUE_W && c === '"') { 622 | state = ATTR_VALUE_DQ 623 | } else if (state === ATTR_VALUE_W && c === "'") { 624 | state = ATTR_VALUE_SQ 625 | } else if (state === ATTR_VALUE_DQ && c === '"') { 626 | res.push([ATTR_VALUE,reg],[ATTR_BREAK]) 627 | reg = '' 628 | state = ATTR 629 | } else if (state === ATTR_VALUE_SQ && c === "'") { 630 | res.push([ATTR_VALUE,reg],[ATTR_BREAK]) 631 | reg = '' 632 | state = ATTR 633 | } else if (state === ATTR_VALUE_W && !/\s/.test(c)) { 634 | state = ATTR_VALUE 635 | i-- 636 | } else if (state === ATTR_VALUE && /\s/.test(c)) { 637 | res.push([ATTR_VALUE,reg],[ATTR_BREAK]) 638 | reg = '' 639 | state = ATTR 640 | } else if (state === ATTR_VALUE || state === ATTR_VALUE_SQ 641 | || state === ATTR_VALUE_DQ) { 642 | reg += c 643 | } 644 | } 645 | if (state === TEXT && reg.length) { 646 | res.push([TEXT,reg]) 647 | reg = '' 648 | } else if (state === ATTR_VALUE && reg.length) { 649 | res.push([ATTR_VALUE,reg]) 650 | reg = '' 651 | } else if (state === ATTR_VALUE_DQ && reg.length) { 652 | res.push([ATTR_VALUE,reg]) 653 | reg = '' 654 | } else if (state === ATTR_VALUE_SQ && reg.length) { 655 | res.push([ATTR_VALUE,reg]) 656 | reg = '' 657 | } else if (state === ATTR_KEY) { 658 | res.push([ATTR_KEY,reg]) 659 | reg = '' 660 | } 661 | return res 662 | } 663 | } 664 | 665 | function strfn (x) { 666 | if (typeof x === 'function') return x 667 | else if (typeof x === 'string') return x 668 | else if (x && typeof x === 'object') return x 669 | else return concat('', x) 670 | } 671 | } 672 | 673 | function quot (state) { 674 | return state === ATTR_VALUE_SQ || state === ATTR_VALUE_DQ 675 | } 676 | 677 | var hasOwn = Object.prototype.hasOwnProperty 678 | function has (obj, key) { return hasOwn.call(obj, key) } 679 | 680 | var closeRE = RegExp('^(' + [ 681 | 'area', 'base', 'basefont', 'bgsound', 'br', 'col', 'command', 'embed', 682 | 'frame', 'hr', 'img', 'input', 'isindex', 'keygen', 'link', 'meta', 'param', 683 | 'source', 'track', 'wbr', '!--', 684 | // SVG TAGS 685 | 'animate', 'animateTransform', 'circle', 'cursor', 'desc', 'ellipse', 686 | 'feBlend', 'feColorMatrix', 'feComposite', 687 | 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 688 | 'feDistantLight', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 689 | 'feGaussianBlur', 'feImage', 'feMergeNode', 'feMorphology', 690 | 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 691 | 'feTurbulence', 'font-face-format', 'font-face-name', 'font-face-uri', 692 | 'glyph', 'glyphRef', 'hkern', 'image', 'line', 'missing-glyph', 'mpath', 693 | 'path', 'polygon', 'polyline', 'rect', 'set', 'stop', 'tref', 'use', 'view', 694 | 'vkern' 695 | ].join('|') + ')(?:[\.#][a-zA-Z0-9\u007F-\uFFFF_:-]+)*$') 696 | function selfClosing (tag) { return closeRE.test(tag) } 697 | 698 | var trailingNewlineRegex = /\n[\s]+$/ 699 | var leadingNewlineRegex = /^\n[\s]+/ 700 | var trailingSpaceRegex = /[\s]+$/ 701 | var leadingSpaceRegex = /^[\s]+/ 702 | var multiSpaceRegex = /[\n\s]+/g 703 | 704 | var TEXT_TAGS = [ 705 | 'a', 'abbr', 'b', 'bdi', 'bdo', 'br', 'cite', 'data', 'dfn', 'em', 'i', 706 | 'kbd', 'mark', 'q', 'rp', 'rt', 'rtc', 'ruby', 's', 'amp', 'small', 'span', 707 | 'strong', 'sub', 'sup', 'time', 'u', 'var', 'wbr' 708 | ] 709 | 710 | var VERBATIM_TAGS = [ 711 | 'code', 'pre', 'textarea' 712 | ] 713 | 714 | var _$appendChild_4 = function appendChild (el, childs) { 715 | if (!Array.isArray(childs)) return 716 | 717 | var nodeName = el.nodeName.toLowerCase() 718 | 719 | var hadText = false 720 | var value, leader 721 | 722 | for (var i = 0, len = childs.length; i < len; i++) { 723 | var node = childs[i] 724 | if (Array.isArray(node)) { 725 | appendChild(el, node) 726 | continue 727 | } 728 | 729 | if (typeof node === 'number' || 730 | typeof node === 'boolean' || 731 | typeof node === 'function' || 732 | node instanceof Date || 733 | node instanceof RegExp) { 734 | node = node.toString() 735 | } 736 | 737 | var lastChild = el.childNodes[el.childNodes.length - 1] 738 | 739 | // Iterate over text nodes 740 | if (typeof node === 'string') { 741 | hadText = true 742 | 743 | // If we already had text, append to the existing text 744 | if (lastChild && lastChild.nodeName === '#text') { 745 | lastChild.nodeValue += node 746 | 747 | // We didn't have a text node yet, create one 748 | } else { 749 | node = document.createTextNode(node) 750 | el.appendChild(node) 751 | lastChild = node 752 | } 753 | 754 | // If this is the last of the child nodes, make sure we close it out 755 | // right 756 | if (i === len - 1) { 757 | hadText = false 758 | // Trim the child text nodes if the current node isn't a 759 | // node where whitespace matters. 760 | if (TEXT_TAGS.indexOf(nodeName) === -1 && 761 | VERBATIM_TAGS.indexOf(nodeName) === -1) { 762 | value = lastChild.nodeValue 763 | .replace(leadingNewlineRegex, '') 764 | .replace(trailingSpaceRegex, '') 765 | .replace(trailingNewlineRegex, '') 766 | .replace(multiSpaceRegex, ' ') 767 | if (value === '') { 768 | el.removeChild(lastChild) 769 | } else { 770 | lastChild.nodeValue = value 771 | } 772 | } else if (VERBATIM_TAGS.indexOf(nodeName) === -1) { 773 | // The very first node in the list should not have leading 774 | // whitespace. Sibling text nodes should have whitespace if there 775 | // was any. 776 | leader = i === 0 ? '' : ' ' 777 | value = lastChild.nodeValue 778 | .replace(leadingNewlineRegex, leader) 779 | .replace(leadingSpaceRegex, ' ') 780 | .replace(trailingSpaceRegex, '') 781 | .replace(trailingNewlineRegex, '') 782 | .replace(multiSpaceRegex, ' ') 783 | lastChild.nodeValue = value 784 | } 785 | } 786 | 787 | // Iterate over DOM nodes 788 | } else if (node && node.nodeType) { 789 | // If the last node was a text node, make sure it is properly closed out 790 | if (hadText) { 791 | hadText = false 792 | 793 | // Trim the child text nodes if the current node isn't a 794 | // text node or a code node 795 | if (TEXT_TAGS.indexOf(nodeName) === -1 && 796 | VERBATIM_TAGS.indexOf(nodeName) === -1) { 797 | value = lastChild.nodeValue 798 | .replace(leadingNewlineRegex, '') 799 | .replace(trailingNewlineRegex, '') 800 | .replace(multiSpaceRegex, ' ') 801 | 802 | // Remove empty text nodes, append otherwise 803 | if (value === '') { 804 | el.removeChild(lastChild) 805 | } else { 806 | lastChild.nodeValue = value 807 | } 808 | // Trim the child nodes if the current node is not a node 809 | // where all whitespace must be preserved 810 | } else if (VERBATIM_TAGS.indexOf(nodeName) === -1) { 811 | value = lastChild.nodeValue 812 | .replace(leadingSpaceRegex, ' ') 813 | .replace(leadingNewlineRegex, '') 814 | .replace(trailingNewlineRegex, '') 815 | .replace(multiSpaceRegex, ' ') 816 | lastChild.nodeValue = value 817 | } 818 | } 819 | 820 | // Store the last nodename 821 | var _nodeName = node.nodeName 822 | if (_nodeName) nodeName = _nodeName.toLowerCase() 823 | 824 | // Append the node to the DOM 825 | el.appendChild(node) 826 | } 827 | } 828 | } 829 | 830 | var _$svgTags_8 = [ 831 | 'svg', 'altGlyph', 'altGlyphDef', 'altGlyphItem', 'animate', 'animateColor', 832 | 'animateMotion', 'animateTransform', 'circle', 'clipPath', 'color-profile', 833 | 'cursor', 'defs', 'desc', 'ellipse', 'feBlend', 'feColorMatrix', 834 | 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 835 | 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feFlood', 836 | 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 837 | 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 838 | 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence', 'filter', 839 | 'font', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 840 | 'font-face-uri', 'foreignObject', 'g', 'glyph', 'glyphRef', 'hkern', 'image', 841 | 'line', 'linearGradient', 'marker', 'mask', 'metadata', 'missing-glyph', 842 | 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialGradient', 'rect', 843 | 'set', 'stop', 'switch', 'symbol', 'text', 'textPath', 'title', 'tref', 844 | 'tspan', 'use', 'view', 'vkern' 845 | ] 846 | 847 | var _$boolProps_5 = [ 848 | 'autofocus', 'checked', 'defaultchecked', 'disabled', 'formnovalidate', 849 | 'indeterminate', 'readonly', 'required', 'selected', 'willvalidate' 850 | ] 851 | 852 | var _$directProps_7 = [ 853 | 'indeterminate' 854 | ] 855 | 856 | var _$browser_6 = {}; 857 | /* removed: var _$hyperx_2 = require('hyperx') */; 858 | /* removed: var _$appendChild_4 = require('./append-child') */; 859 | /* removed: var _$svgTags_8 = require('./svg-tags') */; 860 | /* removed: var _$boolProps_5 = require('./bool-props') */; 861 | // Props that need to be set directly rather than with el.setAttribute() 862 | /* removed: var _$directProps_7 = require('./direct-props') */; 863 | 864 | var SVGNS = 'http://www.w3.org/2000/svg' 865 | var XLINKNS = 'http://www.w3.org/1999/xlink' 866 | 867 | var COMMENT_TAG = '!--' 868 | 869 | function nanoHtmlCreateElement (tag, props, children) { 870 | var el 871 | 872 | // If an svg tag, it needs a namespace 873 | if (_$svgTags_8.indexOf(tag) !== -1) { 874 | props.namespace = SVGNS 875 | } 876 | 877 | // If we are using a namespace 878 | var ns = false 879 | if (props.namespace) { 880 | ns = props.namespace 881 | delete props.namespace 882 | } 883 | 884 | // Create the element 885 | if (ns) { 886 | el = document.createElementNS(ns, tag) 887 | } else if (tag === COMMENT_TAG) { 888 | return document.createComment(props.comment) 889 | } else { 890 | el = document.createElement(tag) 891 | } 892 | 893 | // Create the properties 894 | for (var p in props) { 895 | if (props.hasOwnProperty(p)) { 896 | var key = p.toLowerCase() 897 | var val = props[p] 898 | // Normalize className 899 | if (key === 'classname') { 900 | key = 'class' 901 | p = 'class' 902 | } 903 | // The for attribute gets transformed to htmlFor, but we just set as for 904 | if (p === 'htmlFor') { 905 | p = 'for' 906 | } 907 | // If a property is boolean, set itself to the key 908 | if (_$boolProps_5.indexOf(key) !== -1) { 909 | if (val === 'true') val = key 910 | else if (val === 'false') continue 911 | } 912 | // If a property prefers being set directly vs setAttribute 913 | if (key.slice(0, 2) === 'on' || _$directProps_7.indexOf(key) !== -1) { 914 | el[p] = val 915 | } else { 916 | if (ns) { 917 | if (p === 'xlink:href') { 918 | el.setAttributeNS(XLINKNS, p, val) 919 | } else if (/^xmlns($|:)/i.test(p)) { 920 | // skip xmlns definitions 921 | } else { 922 | el.setAttributeNS(null, p, val) 923 | } 924 | } else { 925 | el.setAttribute(p, val) 926 | } 927 | } 928 | } 929 | } 930 | 931 | _$appendChild_4(el, children) 932 | return el 933 | } 934 | 935 | _$browser_6 = _$hyperx_2(nanoHtmlCreateElement, {comments: true}) 936 | _$browser_6.default = _$browser_6 937 | _$browser_6.createElement = nanoHtmlCreateElement 938 | 939 | /* removed: var _$browser_6 = require('nanohtml') */; 940 | 941 | var _$render_13 = function render (props) { 942 | return _$browser_6` 943 | 944 |
${props.counter}
945 | 948 | 949 | ` 950 | 951 | function onclick () { 952 | props.increment() 953 | } 954 | } 955 | 956 | var _$app_12 = {}; 957 | /* removed: var _$nanomorph_9 = require('nanomorph') */; 958 | /* removed: var _$render_13 = require('./view') */; 959 | var counter = 0 960 | 961 | function render () { 962 | _$nanomorph_9(document.body, _$render_13({ 963 | counter: counter, 964 | increment: function () { 965 | counter++ 966 | render() 967 | } 968 | })) 969 | } 970 | 971 | render() 972 | 973 | }()); 974 | -------------------------------------------------------------------------------- /example/out/standard.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | browser-pack 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /example/out/standard.js: -------------------------------------------------------------------------------- 1 | (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i 1) { 77 | stack.pop() 78 | stack[stack.length-1][0][2][ix] = h( 79 | cur[0], cur[1], cur[2].length ? cur[2] : undefined 80 | ) 81 | } 82 | } else if (s === OPEN) { 83 | var c = [p[1],{},[]] 84 | cur[2].push(c) 85 | stack.push([c,cur[2].length-1]) 86 | } else if (s === ATTR_KEY || (s === VAR && p[1] === ATTR_KEY)) { 87 | var key = '' 88 | var copyKey 89 | for (; i < parts.length; i++) { 90 | if (parts[i][0] === ATTR_KEY) { 91 | key = concat(key, parts[i][1]) 92 | } else if (parts[i][0] === VAR && parts[i][1] === ATTR_KEY) { 93 | if (typeof parts[i][2] === 'object' && !key) { 94 | for (copyKey in parts[i][2]) { 95 | if (parts[i][2].hasOwnProperty(copyKey) && !cur[1][copyKey]) { 96 | cur[1][copyKey] = parts[i][2][copyKey] 97 | } 98 | } 99 | } else { 100 | key = concat(key, parts[i][2]) 101 | } 102 | } else break 103 | } 104 | if (parts[i][0] === ATTR_EQ) i++ 105 | var j = i 106 | for (; i < parts.length; i++) { 107 | if (parts[i][0] === ATTR_VALUE || parts[i][0] === ATTR_KEY) { 108 | if (!cur[1][key]) cur[1][key] = strfn(parts[i][1]) 109 | else parts[i][1]==="" || (cur[1][key] = concat(cur[1][key], parts[i][1])); 110 | } else if (parts[i][0] === VAR 111 | && (parts[i][1] === ATTR_VALUE || parts[i][1] === ATTR_KEY)) { 112 | if (!cur[1][key]) cur[1][key] = strfn(parts[i][2]) 113 | else parts[i][2]==="" || (cur[1][key] = concat(cur[1][key], parts[i][2])); 114 | } else { 115 | if (key.length && !cur[1][key] && i === j 116 | && (parts[i][0] === CLOSE || parts[i][0] === ATTR_BREAK)) { 117 | // https://html.spec.whatwg.org/multipage/infrastructure.html#boolean-attributes 118 | // empty string is falsy, not well behaved value in browser 119 | cur[1][key] = key.toLowerCase() 120 | } 121 | if (parts[i][0] === CLOSE) { 122 | i-- 123 | } 124 | break 125 | } 126 | } 127 | } else if (s === ATTR_KEY) { 128 | cur[1][p[1]] = true 129 | } else if (s === VAR && p[1] === ATTR_KEY) { 130 | cur[1][p[2]] = true 131 | } else if (s === CLOSE) { 132 | if (selfClosing(cur[0]) && stack.length) { 133 | var ix = stack[stack.length-1][1] 134 | stack.pop() 135 | stack[stack.length-1][0][2][ix] = h( 136 | cur[0], cur[1], cur[2].length ? cur[2] : undefined 137 | ) 138 | } 139 | } else if (s === VAR && p[1] === TEXT) { 140 | if (p[2] === undefined || p[2] === null) p[2] = '' 141 | else if (!p[2]) p[2] = concat('', p[2]) 142 | if (Array.isArray(p[2][0])) { 143 | cur[2].push.apply(cur[2], p[2]) 144 | } else { 145 | cur[2].push(p[2]) 146 | } 147 | } else if (s === TEXT) { 148 | cur[2].push(p[1]) 149 | } else if (s === ATTR_EQ || s === ATTR_BREAK) { 150 | // no-op 151 | } else { 152 | throw new Error('unhandled: ' + s) 153 | } 154 | } 155 | 156 | if (tree[2].length > 1 && /^\s*$/.test(tree[2][0])) { 157 | tree[2].shift() 158 | } 159 | 160 | if (tree[2].length > 2 161 | || (tree[2].length === 2 && /\S/.test(tree[2][1]))) { 162 | throw new Error( 163 | 'multiple root elements must be wrapped in an enclosing tag' 164 | ) 165 | } 166 | if (Array.isArray(tree[2][0]) && typeof tree[2][0][0] === 'string' 167 | && Array.isArray(tree[2][0][2])) { 168 | tree[2][0] = h(tree[2][0][0], tree[2][0][1], tree[2][0][2]) 169 | } 170 | return tree[2][0] 171 | 172 | function parse (str) { 173 | var res = [] 174 | if (state === ATTR_VALUE_W) state = ATTR 175 | for (var i = 0; i < str.length; i++) { 176 | var c = str.charAt(i) 177 | if (state === TEXT && c === '<') { 178 | if (reg.length) res.push([TEXT, reg]) 179 | reg = '' 180 | state = OPEN 181 | } else if (c === '>' && !quot(state) && state !== COMMENT) { 182 | if (state === OPEN && reg.length) { 183 | res.push([OPEN,reg]) 184 | } else if (state === ATTR_KEY) { 185 | res.push([ATTR_KEY,reg]) 186 | } else if (state === ATTR_VALUE && reg.length) { 187 | res.push([ATTR_VALUE,reg]) 188 | } 189 | res.push([CLOSE]) 190 | reg = '' 191 | state = TEXT 192 | } else if (state === COMMENT && /-$/.test(reg) && c === '-') { 193 | if (opts.comments) { 194 | res.push([ATTR_VALUE,reg.substr(0, reg.length - 1)],[CLOSE]) 195 | } 196 | reg = '' 197 | state = TEXT 198 | } else if (state === OPEN && /^!--$/.test(reg)) { 199 | if (opts.comments) { 200 | res.push([OPEN, reg],[ATTR_KEY,'comment'],[ATTR_EQ]) 201 | } 202 | reg = c 203 | state = COMMENT 204 | } else if (state === TEXT || state === COMMENT) { 205 | reg += c 206 | } else if (state === OPEN && c === '/' && reg.length) { 207 | // no-op, self closing tag without a space
208 | } else if (state === OPEN && /\s/.test(c)) { 209 | if (reg.length) { 210 | res.push([OPEN, reg]) 211 | } 212 | reg = '' 213 | state = ATTR 214 | } else if (state === OPEN) { 215 | reg += c 216 | } else if (state === ATTR && /[^\s"'=/]/.test(c)) { 217 | state = ATTR_KEY 218 | reg = c 219 | } else if (state === ATTR && /\s/.test(c)) { 220 | if (reg.length) res.push([ATTR_KEY,reg]) 221 | res.push([ATTR_BREAK]) 222 | } else if (state === ATTR_KEY && /\s/.test(c)) { 223 | res.push([ATTR_KEY,reg]) 224 | reg = '' 225 | state = ATTR_KEY_W 226 | } else if (state === ATTR_KEY && c === '=') { 227 | res.push([ATTR_KEY,reg],[ATTR_EQ]) 228 | reg = '' 229 | state = ATTR_VALUE_W 230 | } else if (state === ATTR_KEY) { 231 | reg += c 232 | } else if ((state === ATTR_KEY_W || state === ATTR) && c === '=') { 233 | res.push([ATTR_EQ]) 234 | state = ATTR_VALUE_W 235 | } else if ((state === ATTR_KEY_W || state === ATTR) && !/\s/.test(c)) { 236 | res.push([ATTR_BREAK]) 237 | if (/[\w-]/.test(c)) { 238 | reg += c 239 | state = ATTR_KEY 240 | } else state = ATTR 241 | } else if (state === ATTR_VALUE_W && c === '"') { 242 | state = ATTR_VALUE_DQ 243 | } else if (state === ATTR_VALUE_W && c === "'") { 244 | state = ATTR_VALUE_SQ 245 | } else if (state === ATTR_VALUE_DQ && c === '"') { 246 | res.push([ATTR_VALUE,reg],[ATTR_BREAK]) 247 | reg = '' 248 | state = ATTR 249 | } else if (state === ATTR_VALUE_SQ && c === "'") { 250 | res.push([ATTR_VALUE,reg],[ATTR_BREAK]) 251 | reg = '' 252 | state = ATTR 253 | } else if (state === ATTR_VALUE_W && !/\s/.test(c)) { 254 | state = ATTR_VALUE 255 | i-- 256 | } else if (state === ATTR_VALUE && /\s/.test(c)) { 257 | res.push([ATTR_VALUE,reg],[ATTR_BREAK]) 258 | reg = '' 259 | state = ATTR 260 | } else if (state === ATTR_VALUE || state === ATTR_VALUE_SQ 261 | || state === ATTR_VALUE_DQ) { 262 | reg += c 263 | } 264 | } 265 | if (state === TEXT && reg.length) { 266 | res.push([TEXT,reg]) 267 | reg = '' 268 | } else if (state === ATTR_VALUE && reg.length) { 269 | res.push([ATTR_VALUE,reg]) 270 | reg = '' 271 | } else if (state === ATTR_VALUE_DQ && reg.length) { 272 | res.push([ATTR_VALUE,reg]) 273 | reg = '' 274 | } else if (state === ATTR_VALUE_SQ && reg.length) { 275 | res.push([ATTR_VALUE,reg]) 276 | reg = '' 277 | } else if (state === ATTR_KEY) { 278 | res.push([ATTR_KEY,reg]) 279 | reg = '' 280 | } 281 | return res 282 | } 283 | } 284 | 285 | function strfn (x) { 286 | if (typeof x === 'function') return x 287 | else if (typeof x === 'string') return x 288 | else if (x && typeof x === 'object') return x 289 | else return concat('', x) 290 | } 291 | } 292 | 293 | function quot (state) { 294 | return state === ATTR_VALUE_SQ || state === ATTR_VALUE_DQ 295 | } 296 | 297 | var hasOwn = Object.prototype.hasOwnProperty 298 | function has (obj, key) { return hasOwn.call(obj, key) } 299 | 300 | var closeRE = RegExp('^(' + [ 301 | 'area', 'base', 'basefont', 'bgsound', 'br', 'col', 'command', 'embed', 302 | 'frame', 'hr', 'img', 'input', 'isindex', 'keygen', 'link', 'meta', 'param', 303 | 'source', 'track', 'wbr', '!--', 304 | // SVG TAGS 305 | 'animate', 'animateTransform', 'circle', 'cursor', 'desc', 'ellipse', 306 | 'feBlend', 'feColorMatrix', 'feComposite', 307 | 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 308 | 'feDistantLight', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 309 | 'feGaussianBlur', 'feImage', 'feMergeNode', 'feMorphology', 310 | 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 311 | 'feTurbulence', 'font-face-format', 'font-face-name', 'font-face-uri', 312 | 'glyph', 'glyphRef', 'hkern', 'image', 'line', 'missing-glyph', 'mpath', 313 | 'path', 'polygon', 'polyline', 'rect', 'set', 'stop', 'tref', 'use', 'view', 314 | 'vkern' 315 | ].join('|') + ')(?:[\.#][a-zA-Z0-9\u007F-\uFFFF_:-]+)*$') 316 | function selfClosing (tag) { return closeRE.test(tag) } 317 | 318 | },{"hyperscript-attribute-to-property":1}],3:[function(require,module,exports){ 319 | assert.notEqual = notEqual 320 | assert.notOk = notOk 321 | assert.equal = equal 322 | assert.ok = assert 323 | 324 | module.exports = assert 325 | 326 | function equal (a, b, m) { 327 | assert(a == b, m) // eslint-disable-line eqeqeq 328 | } 329 | 330 | function notEqual (a, b, m) { 331 | assert(a != b, m) // eslint-disable-line eqeqeq 332 | } 333 | 334 | function notOk (t, m) { 335 | assert(!t, m) 336 | } 337 | 338 | function assert (t, m) { 339 | if (!t) throw new Error(m || 'AssertionError') 340 | } 341 | 342 | },{}],4:[function(require,module,exports){ 343 | var trailingNewlineRegex = /\n[\s]+$/ 344 | var leadingNewlineRegex = /^\n[\s]+/ 345 | var trailingSpaceRegex = /[\s]+$/ 346 | var leadingSpaceRegex = /^[\s]+/ 347 | var multiSpaceRegex = /[\n\s]+/g 348 | 349 | var TEXT_TAGS = [ 350 | 'a', 'abbr', 'b', 'bdi', 'bdo', 'br', 'cite', 'data', 'dfn', 'em', 'i', 351 | 'kbd', 'mark', 'q', 'rp', 'rt', 'rtc', 'ruby', 's', 'amp', 'small', 'span', 352 | 'strong', 'sub', 'sup', 'time', 'u', 'var', 'wbr' 353 | ] 354 | 355 | var VERBATIM_TAGS = [ 356 | 'code', 'pre', 'textarea' 357 | ] 358 | 359 | module.exports = function appendChild (el, childs) { 360 | if (!Array.isArray(childs)) return 361 | 362 | var nodeName = el.nodeName.toLowerCase() 363 | 364 | var hadText = false 365 | var value, leader 366 | 367 | for (var i = 0, len = childs.length; i < len; i++) { 368 | var node = childs[i] 369 | if (Array.isArray(node)) { 370 | appendChild(el, node) 371 | continue 372 | } 373 | 374 | if (typeof node === 'number' || 375 | typeof node === 'boolean' || 376 | typeof node === 'function' || 377 | node instanceof Date || 378 | node instanceof RegExp) { 379 | node = node.toString() 380 | } 381 | 382 | var lastChild = el.childNodes[el.childNodes.length - 1] 383 | 384 | // Iterate over text nodes 385 | if (typeof node === 'string') { 386 | hadText = true 387 | 388 | // If we already had text, append to the existing text 389 | if (lastChild && lastChild.nodeName === '#text') { 390 | lastChild.nodeValue += node 391 | 392 | // We didn't have a text node yet, create one 393 | } else { 394 | node = document.createTextNode(node) 395 | el.appendChild(node) 396 | lastChild = node 397 | } 398 | 399 | // If this is the last of the child nodes, make sure we close it out 400 | // right 401 | if (i === len - 1) { 402 | hadText = false 403 | // Trim the child text nodes if the current node isn't a 404 | // node where whitespace matters. 405 | if (TEXT_TAGS.indexOf(nodeName) === -1 && 406 | VERBATIM_TAGS.indexOf(nodeName) === -1) { 407 | value = lastChild.nodeValue 408 | .replace(leadingNewlineRegex, '') 409 | .replace(trailingSpaceRegex, '') 410 | .replace(trailingNewlineRegex, '') 411 | .replace(multiSpaceRegex, ' ') 412 | if (value === '') { 413 | el.removeChild(lastChild) 414 | } else { 415 | lastChild.nodeValue = value 416 | } 417 | } else if (VERBATIM_TAGS.indexOf(nodeName) === -1) { 418 | // The very first node in the list should not have leading 419 | // whitespace. Sibling text nodes should have whitespace if there 420 | // was any. 421 | leader = i === 0 ? '' : ' ' 422 | value = lastChild.nodeValue 423 | .replace(leadingNewlineRegex, leader) 424 | .replace(leadingSpaceRegex, ' ') 425 | .replace(trailingSpaceRegex, '') 426 | .replace(trailingNewlineRegex, '') 427 | .replace(multiSpaceRegex, ' ') 428 | lastChild.nodeValue = value 429 | } 430 | } 431 | 432 | // Iterate over DOM nodes 433 | } else if (node && node.nodeType) { 434 | // If the last node was a text node, make sure it is properly closed out 435 | if (hadText) { 436 | hadText = false 437 | 438 | // Trim the child text nodes if the current node isn't a 439 | // text node or a code node 440 | if (TEXT_TAGS.indexOf(nodeName) === -1 && 441 | VERBATIM_TAGS.indexOf(nodeName) === -1) { 442 | value = lastChild.nodeValue 443 | .replace(leadingNewlineRegex, '') 444 | .replace(trailingNewlineRegex, '') 445 | .replace(multiSpaceRegex, ' ') 446 | 447 | // Remove empty text nodes, append otherwise 448 | if (value === '') { 449 | el.removeChild(lastChild) 450 | } else { 451 | lastChild.nodeValue = value 452 | } 453 | // Trim the child nodes if the current node is not a node 454 | // where all whitespace must be preserved 455 | } else if (VERBATIM_TAGS.indexOf(nodeName) === -1) { 456 | value = lastChild.nodeValue 457 | .replace(leadingSpaceRegex, ' ') 458 | .replace(leadingNewlineRegex, '') 459 | .replace(trailingNewlineRegex, '') 460 | .replace(multiSpaceRegex, ' ') 461 | lastChild.nodeValue = value 462 | } 463 | } 464 | 465 | // Store the last nodename 466 | var _nodeName = node.nodeName 467 | if (_nodeName) nodeName = _nodeName.toLowerCase() 468 | 469 | // Append the node to the DOM 470 | el.appendChild(node) 471 | } 472 | } 473 | } 474 | 475 | },{}],5:[function(require,module,exports){ 476 | module.exports = [ 477 | 'autofocus', 'checked', 'defaultchecked', 'disabled', 'formnovalidate', 478 | 'indeterminate', 'readonly', 'required', 'selected', 'willvalidate' 479 | ] 480 | 481 | },{}],6:[function(require,module,exports){ 482 | var hyperx = require('hyperx') 483 | var appendChild = require('./append-child') 484 | var SVG_TAGS = require('./svg-tags') 485 | var BOOL_PROPS = require('./bool-props') 486 | // Props that need to be set directly rather than with el.setAttribute() 487 | var DIRECT_PROPS = require('./direct-props') 488 | 489 | var SVGNS = 'http://www.w3.org/2000/svg' 490 | var XLINKNS = 'http://www.w3.org/1999/xlink' 491 | 492 | var COMMENT_TAG = '!--' 493 | 494 | function nanoHtmlCreateElement (tag, props, children) { 495 | var el 496 | 497 | // If an svg tag, it needs a namespace 498 | if (SVG_TAGS.indexOf(tag) !== -1) { 499 | props.namespace = SVGNS 500 | } 501 | 502 | // If we are using a namespace 503 | var ns = false 504 | if (props.namespace) { 505 | ns = props.namespace 506 | delete props.namespace 507 | } 508 | 509 | // Create the element 510 | if (ns) { 511 | el = document.createElementNS(ns, tag) 512 | } else if (tag === COMMENT_TAG) { 513 | return document.createComment(props.comment) 514 | } else { 515 | el = document.createElement(tag) 516 | } 517 | 518 | // Create the properties 519 | for (var p in props) { 520 | if (props.hasOwnProperty(p)) { 521 | var key = p.toLowerCase() 522 | var val = props[p] 523 | // Normalize className 524 | if (key === 'classname') { 525 | key = 'class' 526 | p = 'class' 527 | } 528 | // The for attribute gets transformed to htmlFor, but we just set as for 529 | if (p === 'htmlFor') { 530 | p = 'for' 531 | } 532 | // If a property is boolean, set itself to the key 533 | if (BOOL_PROPS.indexOf(key) !== -1) { 534 | if (val === 'true') val = key 535 | else if (val === 'false') continue 536 | } 537 | // If a property prefers being set directly vs setAttribute 538 | if (key.slice(0, 2) === 'on' || DIRECT_PROPS.indexOf(key) !== -1) { 539 | el[p] = val 540 | } else { 541 | if (ns) { 542 | if (p === 'xlink:href') { 543 | el.setAttributeNS(XLINKNS, p, val) 544 | } else if (/^xmlns($|:)/i.test(p)) { 545 | // skip xmlns definitions 546 | } else { 547 | el.setAttributeNS(null, p, val) 548 | } 549 | } else { 550 | el.setAttribute(p, val) 551 | } 552 | } 553 | } 554 | } 555 | 556 | appendChild(el, children) 557 | return el 558 | } 559 | 560 | module.exports = hyperx(nanoHtmlCreateElement, {comments: true}) 561 | module.exports.default = module.exports 562 | module.exports.createElement = nanoHtmlCreateElement 563 | 564 | },{"./append-child":4,"./bool-props":5,"./direct-props":7,"./svg-tags":8,"hyperx":2}],7:[function(require,module,exports){ 565 | module.exports = [ 566 | 'indeterminate' 567 | ] 568 | 569 | },{}],8:[function(require,module,exports){ 570 | module.exports = [ 571 | 'svg', 'altGlyph', 'altGlyphDef', 'altGlyphItem', 'animate', 'animateColor', 572 | 'animateMotion', 'animateTransform', 'circle', 'clipPath', 'color-profile', 573 | 'cursor', 'defs', 'desc', 'ellipse', 'feBlend', 'feColorMatrix', 574 | 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 575 | 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feFlood', 576 | 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 577 | 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 578 | 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence', 'filter', 579 | 'font', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 580 | 'font-face-uri', 'foreignObject', 'g', 'glyph', 'glyphRef', 'hkern', 'image', 581 | 'line', 'linearGradient', 'marker', 'mask', 'metadata', 'missing-glyph', 582 | 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialGradient', 'rect', 583 | 'set', 'stop', 'switch', 'symbol', 'text', 'textPath', 'title', 'tref', 584 | 'tspan', 'use', 'view', 'vkern' 585 | ] 586 | 587 | },{}],9:[function(require,module,exports){ 588 | var assert = require('assert') 589 | var morph = require('./lib/morph') 590 | 591 | var TEXT_NODE = 3 592 | // var DEBUG = false 593 | 594 | module.exports = nanomorph 595 | 596 | // Morph one tree into another tree 597 | // 598 | // no parent 599 | // -> same: diff and walk children 600 | // -> not same: replace and return 601 | // old node doesn't exist 602 | // -> insert new node 603 | // new node doesn't exist 604 | // -> delete old node 605 | // nodes are not the same 606 | // -> diff nodes and apply patch to old node 607 | // nodes are the same 608 | // -> walk all child nodes and append to old node 609 | function nanomorph (oldTree, newTree) { 610 | // if (DEBUG) { 611 | // console.log( 612 | // 'nanomorph\nold\n %s\nnew\n %s', 613 | // oldTree && oldTree.outerHTML, 614 | // newTree && newTree.outerHTML 615 | // ) 616 | // } 617 | assert.equal(typeof oldTree, 'object', 'nanomorph: oldTree should be an object') 618 | assert.equal(typeof newTree, 'object', 'nanomorph: newTree should be an object') 619 | var tree = walk(newTree, oldTree) 620 | // if (DEBUG) console.log('=> morphed\n %s', tree.outerHTML) 621 | return tree 622 | } 623 | 624 | // Walk and morph a dom tree 625 | function walk (newNode, oldNode) { 626 | // if (DEBUG) { 627 | // console.log( 628 | // 'walk\nold\n %s\nnew\n %s', 629 | // oldNode && oldNode.outerHTML, 630 | // newNode && newNode.outerHTML 631 | // ) 632 | // } 633 | if (!oldNode) { 634 | return newNode 635 | } else if (!newNode) { 636 | return null 637 | } else if (newNode.isSameNode && newNode.isSameNode(oldNode)) { 638 | return oldNode 639 | } else if (newNode.tagName !== oldNode.tagName) { 640 | return newNode 641 | } else { 642 | morph(newNode, oldNode) 643 | updateChildren(newNode, oldNode) 644 | return oldNode 645 | } 646 | } 647 | 648 | // Update the children of elements 649 | // (obj, obj) -> null 650 | function updateChildren (newNode, oldNode) { 651 | // if (DEBUG) { 652 | // console.log( 653 | // 'updateChildren\nold\n %s\nnew\n %s', 654 | // oldNode && oldNode.outerHTML, 655 | // newNode && newNode.outerHTML 656 | // ) 657 | // } 658 | var oldChild, newChild, morphed, oldMatch 659 | 660 | // The offset is only ever increased, and used for [i - offset] in the loop 661 | var offset = 0 662 | 663 | for (var i = 0; ; i++) { 664 | oldChild = oldNode.childNodes[i] 665 | newChild = newNode.childNodes[i - offset] 666 | // if (DEBUG) { 667 | // console.log( 668 | // '===\n- old\n %s\n- new\n %s', 669 | // oldChild && oldChild.outerHTML, 670 | // newChild && newChild.outerHTML 671 | // ) 672 | // } 673 | // Both nodes are empty, do nothing 674 | if (!oldChild && !newChild) { 675 | break 676 | 677 | // There is no new child, remove old 678 | } else if (!newChild) { 679 | oldNode.removeChild(oldChild) 680 | i-- 681 | 682 | // There is no old child, add new 683 | } else if (!oldChild) { 684 | oldNode.appendChild(newChild) 685 | offset++ 686 | 687 | // Both nodes are the same, morph 688 | } else if (same(newChild, oldChild)) { 689 | morphed = walk(newChild, oldChild) 690 | if (morphed !== oldChild) { 691 | oldNode.replaceChild(morphed, oldChild) 692 | offset++ 693 | } 694 | 695 | // Both nodes do not share an ID or a placeholder, try reorder 696 | } else { 697 | oldMatch = null 698 | 699 | // Try and find a similar node somewhere in the tree 700 | for (var j = i; j < oldNode.childNodes.length; j++) { 701 | if (same(oldNode.childNodes[j], newChild)) { 702 | oldMatch = oldNode.childNodes[j] 703 | break 704 | } 705 | } 706 | 707 | // If there was a node with the same ID or placeholder in the old list 708 | if (oldMatch) { 709 | morphed = walk(newChild, oldMatch) 710 | if (morphed !== oldMatch) offset++ 711 | oldNode.insertBefore(morphed, oldChild) 712 | 713 | // It's safe to morph two nodes in-place if neither has an ID 714 | } else if (!newChild.id && !oldChild.id) { 715 | morphed = walk(newChild, oldChild) 716 | if (morphed !== oldChild) { 717 | oldNode.replaceChild(morphed, oldChild) 718 | offset++ 719 | } 720 | 721 | // Insert the node at the index if we couldn't morph or find a matching node 722 | } else { 723 | oldNode.insertBefore(newChild, oldChild) 724 | offset++ 725 | } 726 | } 727 | } 728 | } 729 | 730 | function same (a, b) { 731 | if (a.id) return a.id === b.id 732 | if (a.isSameNode) return a.isSameNode(b) 733 | if (a.tagName !== b.tagName) return false 734 | if (a.type === TEXT_NODE) return a.nodeValue === b.nodeValue 735 | return false 736 | } 737 | 738 | },{"./lib/morph":11,"assert":3}],10:[function(require,module,exports){ 739 | module.exports = [ 740 | // attribute events (can be set with attributes) 741 | 'onclick', 742 | 'ondblclick', 743 | 'onmousedown', 744 | 'onmouseup', 745 | 'onmouseover', 746 | 'onmousemove', 747 | 'onmouseout', 748 | 'onmouseenter', 749 | 'onmouseleave', 750 | 'ontouchcancel', 751 | 'ontouchend', 752 | 'ontouchmove', 753 | 'ontouchstart', 754 | 'ondragstart', 755 | 'ondrag', 756 | 'ondragenter', 757 | 'ondragleave', 758 | 'ondragover', 759 | 'ondrop', 760 | 'ondragend', 761 | 'onkeydown', 762 | 'onkeypress', 763 | 'onkeyup', 764 | 'onunload', 765 | 'onabort', 766 | 'onerror', 767 | 'onresize', 768 | 'onscroll', 769 | 'onselect', 770 | 'onchange', 771 | 'onsubmit', 772 | 'onreset', 773 | 'onfocus', 774 | 'onblur', 775 | 'oninput', 776 | // other common events 777 | 'oncontextmenu', 778 | 'onfocusin', 779 | 'onfocusout' 780 | ] 781 | 782 | },{}],11:[function(require,module,exports){ 783 | var events = require('./events') 784 | var eventsLength = events.length 785 | 786 | var ELEMENT_NODE = 1 787 | var TEXT_NODE = 3 788 | var COMMENT_NODE = 8 789 | 790 | module.exports = morph 791 | 792 | // diff elements and apply the resulting patch to the old node 793 | // (obj, obj) -> null 794 | function morph (newNode, oldNode) { 795 | var nodeType = newNode.nodeType 796 | var nodeName = newNode.nodeName 797 | 798 | if (nodeType === ELEMENT_NODE) { 799 | copyAttrs(newNode, oldNode) 800 | } 801 | 802 | if (nodeType === TEXT_NODE || nodeType === COMMENT_NODE) { 803 | if (oldNode.nodeValue !== newNode.nodeValue) { 804 | oldNode.nodeValue = newNode.nodeValue 805 | } 806 | } 807 | 808 | // Some DOM nodes are weird 809 | // https://github.com/patrick-steele-idem/morphdom/blob/master/src/specialElHandlers.js 810 | if (nodeName === 'INPUT') updateInput(newNode, oldNode) 811 | else if (nodeName === 'OPTION') updateOption(newNode, oldNode) 812 | else if (nodeName === 'TEXTAREA') updateTextarea(newNode, oldNode) 813 | 814 | copyEvents(newNode, oldNode) 815 | } 816 | 817 | function copyAttrs (newNode, oldNode) { 818 | var oldAttrs = oldNode.attributes 819 | var newAttrs = newNode.attributes 820 | var attrNamespaceURI = null 821 | var attrValue = null 822 | var fromValue = null 823 | var attrName = null 824 | var attr = null 825 | 826 | for (var i = newAttrs.length - 1; i >= 0; --i) { 827 | attr = newAttrs[i] 828 | attrName = attr.name 829 | attrNamespaceURI = attr.namespaceURI 830 | attrValue = attr.value 831 | if (attrNamespaceURI) { 832 | attrName = attr.localName || attrName 833 | fromValue = oldNode.getAttributeNS(attrNamespaceURI, attrName) 834 | if (fromValue !== attrValue) { 835 | oldNode.setAttributeNS(attrNamespaceURI, attrName, attrValue) 836 | } 837 | } else { 838 | if (!oldNode.hasAttribute(attrName)) { 839 | oldNode.setAttribute(attrName, attrValue) 840 | } else { 841 | fromValue = oldNode.getAttribute(attrName) 842 | if (fromValue !== attrValue) { 843 | // apparently values are always cast to strings, ah well 844 | if (attrValue === 'null' || attrValue === 'undefined') { 845 | oldNode.removeAttribute(attrName) 846 | } else { 847 | oldNode.setAttribute(attrName, attrValue) 848 | } 849 | } 850 | } 851 | } 852 | } 853 | 854 | // Remove any extra attributes found on the original DOM element that 855 | // weren't found on the target element. 856 | for (var j = oldAttrs.length - 1; j >= 0; --j) { 857 | attr = oldAttrs[j] 858 | if (attr.specified !== false) { 859 | attrName = attr.name 860 | attrNamespaceURI = attr.namespaceURI 861 | 862 | if (attrNamespaceURI) { 863 | attrName = attr.localName || attrName 864 | if (!newNode.hasAttributeNS(attrNamespaceURI, attrName)) { 865 | oldNode.removeAttributeNS(attrNamespaceURI, attrName) 866 | } 867 | } else { 868 | if (!newNode.hasAttributeNS(null, attrName)) { 869 | oldNode.removeAttribute(attrName) 870 | } 871 | } 872 | } 873 | } 874 | } 875 | 876 | function copyEvents (newNode, oldNode) { 877 | for (var i = 0; i < eventsLength; i++) { 878 | var ev = events[i] 879 | if (newNode[ev]) { // if new element has a whitelisted attribute 880 | oldNode[ev] = newNode[ev] // update existing element 881 | } else if (oldNode[ev]) { // if existing element has it and new one doesnt 882 | oldNode[ev] = undefined // remove it from existing element 883 | } 884 | } 885 | } 886 | 887 | function updateOption (newNode, oldNode) { 888 | updateAttribute(newNode, oldNode, 'selected') 889 | } 890 | 891 | // The "value" attribute is special for the element since it sets the 892 | // initial value. Changing the "value" attribute without changing the "value" 893 | // property will have no effect since it is only used to the set the initial 894 | // value. Similar for the "checked" attribute, and "disabled". 895 | function updateInput (newNode, oldNode) { 896 | var newValue = newNode.value 897 | var oldValue = oldNode.value 898 | 899 | updateAttribute(newNode, oldNode, 'checked') 900 | updateAttribute(newNode, oldNode, 'disabled') 901 | 902 | if (newValue !== oldValue) { 903 | oldNode.setAttribute('value', newValue) 904 | oldNode.value = newValue 905 | } 906 | 907 | if (newValue === 'null') { 908 | oldNode.value = '' 909 | oldNode.removeAttribute('value') 910 | } 911 | 912 | if (!newNode.hasAttributeNS(null, 'value')) { 913 | oldNode.removeAttribute('value') 914 | } else if (oldNode.type === 'range') { 915 | // this is so elements like slider move their UI thingy 916 | oldNode.value = newValue 917 | } 918 | } 919 | 920 | function updateTextarea (newNode, oldNode) { 921 | var newValue = newNode.value 922 | if (newValue !== oldNode.value) { 923 | oldNode.value = newValue 924 | } 925 | 926 | if (oldNode.firstChild && oldNode.firstChild.nodeValue !== newValue) { 927 | // Needed for IE. Apparently IE sets the placeholder as the 928 | // node value and vise versa. This ignores an empty update. 929 | if (newValue === '' && oldNode.firstChild.nodeValue === oldNode.placeholder) { 930 | return 931 | } 932 | 933 | oldNode.firstChild.nodeValue = newValue 934 | } 935 | } 936 | 937 | function updateAttribute (newNode, oldNode, name) { 938 | if (newNode[name] !== oldNode[name]) { 939 | oldNode[name] = newNode[name] 940 | if (newNode[name]) { 941 | oldNode.setAttribute(name, '') 942 | } else { 943 | oldNode.removeAttribute(name) 944 | } 945 | } 946 | } 947 | 948 | },{"./events":10}],12:[function(require,module,exports){ 949 | var morph = require('nanomorph') 950 | var view = require('./view') 951 | var counter = 0 952 | 953 | function render () { 954 | morph(document.body, view({ 955 | counter: counter, 956 | increment: function () { 957 | counter++ 958 | render() 959 | } 960 | })) 961 | } 962 | 963 | render() 964 | 965 | },{"./view":13,"nanomorph":9}],13:[function(require,module,exports){ 966 | var html = require('nanohtml') 967 | 968 | module.exports = function render (props) { 969 | return html` 970 | 971 |
${props.counter}
972 | 975 | 976 | ` 977 | 978 | function onclick () { 979 | props.increment() 980 | } 981 | } 982 | 983 | },{"nanohtml":6}]},{},[12]); 984 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "browser-pack-flat-example", 3 | "private": true, 4 | "dependencies": { 5 | "nanohtml": "^1.2.4", 6 | "nanomorph": "^5.1.3" 7 | }, 8 | "devDependencies": { 9 | "browserify": "^16.2.2", 10 | "create-html": "^3.1.0" 11 | }, 12 | "scripts": { 13 | "build:standard": "browserify src/app.js > out/standard.js && create-html -s standard.js -t browser-pack > out/standard.html", 14 | "build:flat": "browserify -p ../ src/app.js > out/flat.js && create-html -s flat.js -t browser-pack-flat > out/flat.html", 15 | "build": "npm run build:standard && npm run build:flat" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /example/readme.md: -------------------------------------------------------------------------------- 1 | # example 2 | 3 | A small counter app to show the difference in output between the default browser-pack and browser-pack-flat. 4 | 5 | - [Normal output](./out/standard.js) 6 | - ["Flat" output](./out/flat.js) 7 | 8 | ## Try it 9 | 10 | ```bash 11 | cd example/ 12 | npm run build 13 | ecstatic out/ 14 | ``` 15 | 16 | Then visit `localhost:8000`. 17 | -------------------------------------------------------------------------------- /example/src/app.js: -------------------------------------------------------------------------------- 1 | var morph = require('nanomorph') 2 | var view = require('./view') 3 | var counter = 0 4 | 5 | function render () { 6 | morph(document.body, view({ 7 | counter: counter, 8 | increment: function () { 9 | counter++ 10 | render() 11 | } 12 | })) 13 | } 14 | 15 | render() 16 | -------------------------------------------------------------------------------- /example/src/view.js: -------------------------------------------------------------------------------- 1 | var html = require('nanohtml') 2 | 3 | module.exports = function render (props) { 4 | return html` 5 | 6 |
${props.counter}
7 | 10 | 11 | ` 12 | 13 | function onclick () { 14 | props.increment() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var pathParse = require('path-parse') 2 | var path = require('path') 3 | var fs = require('fs') 4 | var transformAst = require('transform-ast') 5 | var countLines = require('count-lines') 6 | var convertSourceMap = require('convert-source-map') 7 | var combineSourceMap = require('combine-source-map') 8 | var through = require('through2') 9 | var umd = require('umd') 10 | var dedent = require('dedent') 11 | var json = require('JSONStream') 12 | var combiner = require('stream-combiner') 13 | var scan = require('scope-analyzer') 14 | var toIdentifier = require('./private_modules/identifierfy') 15 | var wrapComment = require('wrap-comment') 16 | var isRequire = require('estree-is-require') 17 | var isMemberExpression = require('estree-is-member-expression') 18 | 19 | var dedupedRx = /^arguments\[4\]\[(\d+)\]/ 20 | 21 | var kEvaluateOnDemand = Symbol('evaluate on demand') 22 | var kAst = Symbol('ast') 23 | var kIsSimpleExport = Symbol('is simple export') 24 | var kExportsName = Symbol('exports variable name') 25 | var kRequireCalls = Symbol('require calls') 26 | var kDependencyOrder = Symbol('dependency order of execution sort value') 27 | var kReferences = Symbol('module/exports references') 28 | var kMagicString = Symbol('magic string') 29 | var kSourceMap = Symbol('source map') 30 | var kDummyVars = Symbol('dummy replacement variables') 31 | var kShouldRename = Symbol('should rename binding') 32 | 33 | var createModuleFactoryCode = fs.readFileSync(require.resolve('./_createModuleFactory'), 'utf8') 34 | var exposedRequireCode = fs.readFileSync(require.resolve('./_exposedRequire'), 'utf8') 35 | 36 | // Parse the module and collect require() calls and exports assignments. 37 | function parseModule (row, index, rows, opts) { 38 | // Holds the `module.exports` variable name. 39 | var moduleExportsName = toIdentifier('_$' + getModuleName(row.file || '') + '_' + row.id) 40 | 41 | // browserify is clever about deduping modules with the same source code, 42 | // but it needs the browser-pack runtime in order to do so. 43 | // we don't have that runtime so this … re-dupes those modules. 44 | if (dedupedRx.test(row.source)) { 45 | var n = row.source.match(dedupedRx)[1] 46 | var dedup = rows.filter(function (other) { 47 | return String(other.id) === n 48 | })[0] 49 | row.source = dedup.source 50 | } 51 | 52 | var requireCalls = [] 53 | var orderOfExecution = new Map() 54 | 55 | var ast 56 | // hack to keep track of `module`/`exports` references correctly. 57 | // in node.js they're defined by a function wrapper, so their scope is 58 | // one level higher-ish than the module scope. this emulates that. 59 | var globalScope = { 60 | type: 'BrowserPackFlatWrapper', 61 | parent: null 62 | } 63 | scan.createScope(globalScope, ['require', 'module', 'exports']) 64 | 65 | var source = row.source 66 | 67 | // Determine if a require() call may not be evaluated according to its linear source position 68 | // This happens primarily if the call is inside a function, or inside a conditional branch 69 | function isOrderUnpredictable (node) { 70 | while ((node = node.parent)) { 71 | // Special-case for IIFE, behaviour is the same as evaluating inline 72 | if (node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') { 73 | // (() => {})() 74 | if (node.parent && node.parent.type === 'CallExpression' && node.parent.callee === node) { 75 | continue 76 | } 77 | // (function(){}).call(null) 78 | // this form is added by browserify to inject globals 79 | if (node.parent && node.parent.type === 'MemberExpression' && 80 | node.parent.object === node && 81 | (node.parent.property.name === 'call' || node.parent.property.name === 'apply') && 82 | node.parent.parent && node.parent.parent.type === 'CallExpression') { 83 | continue 84 | } 85 | } 86 | 87 | // if(require('d')) is still in-order 88 | // the same is technically true for while(require()) and for(require();;) but those are more rare 89 | if (node.parent && node.parent.type === 'IfStatement' && node.parent.test === node) { 90 | // Skip the IfStatement 91 | node = node.parent 92 | continue 93 | } 94 | 95 | if (node.type === 'IfStatement' || // if(false) require() 96 | node.type === 'WhileStatement' || // while(false) require() 97 | node.type === 'ForStatement' || // for(;false;) require() 98 | node.type === 'ForInStatement' || // for(x in []) require() 99 | node.type === 'FunctionExpression' || // setTimeout(function(){ require() }) 100 | node.type === 'FunctionDeclaration' || // function neverCalled(){ require() } 101 | node.type === 'ArrowFunctionExpression' // setTimeout(()=> require()) 102 | ) { 103 | return true 104 | } 105 | } 106 | return false 107 | } 108 | 109 | // Keep track of modules that were already evaluated in a predictable order so that multiple 110 | // require('a') occurences don't force 'a' to become on-demand 111 | var alreadyPredictablyEvaluated = new Set() 112 | // we'll do two walks along the AST in order to detect variables and their references. 113 | // we initialise the scopes and declarations in the first one here, and then collect 114 | // references in the second. 115 | var magicString = transformAst(source, { 116 | ecmaVersion: opts.ecmaVersion !== undefined ? opts.ecmaVersion : 10, 117 | inputFilename: row.sourceFile, 118 | sourceType: opts.sourceType || 'script' 119 | }, function (node) { 120 | if (node.type === 'Program') ast = node 121 | scan.visitScope(node) 122 | 123 | // also collect requires while we're here 124 | if (isRequire(node)) { 125 | var argument = node.arguments[0] 126 | var required = argument.type === 'Literal' ? argument.value : null 127 | 128 | if (required !== null && moduleExists(row.deps[required])) { 129 | var other = rows.byId[row.deps[required]] 130 | if (isOrderUnpredictable(node)) { 131 | if (!alreadyPredictablyEvaluated.has(other)) { 132 | other[kEvaluateOnDemand] = true 133 | } 134 | } else { 135 | alreadyPredictablyEvaluated.add(other) 136 | } 137 | requireCalls.push({ 138 | id: row.deps[required], 139 | node: node, 140 | requiredModule: other 141 | }) 142 | } else if (required !== null) { 143 | requireCalls.push({ 144 | external: true, 145 | id: row.deps[required] || required, 146 | node: node 147 | }) 148 | } 149 | 150 | if (required !== null) { 151 | orderOfExecution.set(row.deps[required] || required, node.end) 152 | } 153 | 154 | function moduleExists (id) { 155 | return id != null && !!rows.byId[id] 156 | } 157 | } 158 | }) 159 | magicString.walk(function (node) { 160 | // transform-ast has set this to `undefined` 161 | ast.parent = globalScope 162 | scan.visitBinding(node) 163 | }) 164 | 165 | var requireList = scan.scope(globalScope).getReferences('require') 166 | var moduleExportsList = scan.scope(globalScope).getReferences('module') 167 | .map(function (node) { return node.parent }) 168 | .filter(isModuleExports) 169 | var exportsList = scan.scope(globalScope).getReferences('exports') 170 | var moduleList = scan.scope(globalScope).getReferences('module') 171 | .filter(function (node) { return !isModuleExports(node.parent) }) 172 | 173 | // Detect simple exports that are just `module.exports = xyz`, we can compile them to a single 174 | // variable assignment. 175 | var isSimpleExport = false 176 | if (moduleExportsList.length === 1 && exportsList.length === 0 && moduleList.length === 0) { 177 | var node = moduleExportsList[0] 178 | if (node.parent.type === 'AssignmentExpression' && node.parent.left === node && 179 | node.parent.parent.type === 'ExpressionStatement') { 180 | isSimpleExport = scan.nearestScope(node.object, false) === ast 181 | 182 | var name = getNodeName(node.parent.right) 183 | if (name) { 184 | moduleExportsName = toIdentifier('_$' + name + '_' + row.id) 185 | } 186 | } 187 | } 188 | 189 | row[kAst] = ast 190 | row[kIsSimpleExport] = isSimpleExport 191 | row[kExportsName] = moduleExportsName 192 | row.hasExports = (moduleExportsList.length + exportsList.length) > 0 193 | row[kRequireCalls] = requireCalls 194 | row[kDependencyOrder] = orderOfExecution 195 | row[kReferences] = { 196 | require: requireList, 197 | module: moduleList, 198 | exports: exportsList, 199 | 'module.exports': moduleExportsList 200 | } 201 | row[kMagicString] = magicString 202 | } 203 | 204 | function sortModules (rows) { 205 | var index = new Map() 206 | var mod 207 | while ((mod = rows.pop())) { 208 | index.set(mod.id, mod) 209 | } 210 | 211 | function compareDependencySortOrder (a, b) { 212 | // Sort dependencies by the order of their require() calls 213 | var ao = typeof a.dependencyOrder === 'number' 214 | var bo = typeof b.dependencyOrder === 'number' 215 | if (ao && bo) { 216 | return a.dependencyOrder < b.dependencyOrder ? -1 : 1 217 | } 218 | if (ao && !bo) return -1 219 | if (!ao && bo) return 1 220 | 221 | return compareModuleSortOrder(a.module, b.module) 222 | } 223 | 224 | var modules = Array.from(index.values()).sort(compareModuleSortOrder) 225 | var seen = new Set() 226 | 227 | function visit (mod) { 228 | if (seen.has(mod.id)) return 229 | seen.add(mod.id) 230 | if (hasDeps(mod)) { 231 | values(mod.deps) 232 | .map(function attachSortOrder (id) { 233 | var dep = index.get(id) 234 | if (dep) { 235 | return { 236 | module: dep, 237 | dependencyOrder: mod[kDependencyOrder] ? mod[kDependencyOrder].get(id) : undefined 238 | } 239 | } 240 | }) 241 | .filter(Boolean) 242 | .sort(compareDependencySortOrder) 243 | .forEach(function (dep) { visit(dep.module) }) 244 | } 245 | rows.push(mod) 246 | } 247 | 248 | modules.forEach(visit) 249 | } 250 | 251 | function values (obj) { 252 | var result = [] 253 | for (var k in obj) { result.push(obj[k]) } 254 | return result 255 | } 256 | 257 | function hasDeps (mod) { 258 | return mod.deps && Object.keys(mod.deps).length > 0 259 | } 260 | 261 | function compareModuleSortOrder (a, b) { 262 | // Float entry modules to the top. 263 | if (a.entry && !b.entry) return -1 264 | if (!a.entry && b.entry) return 1 265 | // Sort entry modules by their `.order`. 266 | var ao = typeof a.order === 'number' 267 | var bo = typeof b.order === 'number' 268 | if (ao && bo) { 269 | return a.order < b.order ? -1 : 1 270 | } 271 | // Modules that have an `.order` go before modules that do not. 272 | if (ao && !bo) return -1 273 | if (!ao && bo) return 1 274 | 275 | // Else sort by ID, so that output is stable. 276 | return a.id < b.id ? -1 : 1 277 | } 278 | 279 | // Collect all global variables that are used in any module. 280 | // This is done separately from the next step (markDuplicateVariableNames) 281 | // so that global variables used in "later" modules, when colliding 282 | // with a module variable name in an "earlier" module, are correctly 283 | // deduped. See https://github.com/browserify/tinyify/issues/10 284 | function identifyGlobals (row, i, rows) { 285 | var ast = row[kAst] 286 | var globalScope = ast.parent 287 | 288 | var scope = scan.scope(ast) 289 | if (scope) { 290 | scan.scope(globalScope).getUndeclaredNames().forEach(function (name) { 291 | rows.usedGlobalVariables.add(name) 292 | }) 293 | } 294 | } 295 | 296 | // Mark module variables that collide with variable names from other modules so we can rewrite them. 297 | function markDuplicateVariableNames (row, i, rows) { 298 | var ast = row[kAst] 299 | 300 | var scope = scan.scope(ast) 301 | if (scope) { 302 | scope.forEach(function (binding, name) { 303 | binding[kShouldRename] = rows.usedGlobalVariables.has(name) 304 | rows.usedGlobalVariables.add(name) 305 | }) 306 | } 307 | } 308 | 309 | function rewriteModule (row, i, rows) { 310 | var moduleExportsName = row[kExportsName] 311 | var moduleBaseName 312 | 313 | var ast = row[kAst] 314 | var magicString = row[kMagicString] 315 | var moduleList = row[kReferences].module 316 | var moduleExportsList = row[kReferences]['module.exports'] 317 | var exportsList = row[kReferences].exports 318 | var requireList = row[kReferences].require 319 | 320 | // If `module` is used as a free variable we need to turn it into an object with an `.exports` 321 | // property, to deal with situations like: 322 | // 323 | // var a = module; 324 | // a.exports = 'hello' 325 | // 326 | // Not too common, but it happens… 327 | if (moduleList.length > 0) { 328 | moduleBaseName = moduleExportsName 329 | moduleExportsName += '.exports' 330 | } 331 | 332 | // inline "typeof require", because it will usually not be available at runtime 333 | requireList.forEach(function (node) { 334 | if (node.parent.type === 'UnaryExpression' && node.parent.operator === 'typeof') { 335 | node.parent.edit.update('"function"') 336 | } 337 | }) 338 | 339 | if (!row[kEvaluateOnDemand]) { // on-demand modules have a function wrapper and don't need to be rewritten 340 | moduleExportsList.concat(exportsList).forEach(function (node) { 341 | if (row[kIsSimpleExport]) { 342 | // var $moduleExportsName = xyz 343 | node.edit.update('var ' + moduleExportsName) 344 | } else { 345 | renameIdentifier(node, moduleExportsName) 346 | } 347 | }) 348 | moduleList.forEach(function (node) { 349 | // rewrite `typeof module` to `"object"` 350 | if (node.parent.type === 'UnaryExpression' && node.parent.operator === 'typeof') { 351 | node.parent.edit.update('"object"') 352 | } else if (isModuleParent(node.parent)) { 353 | if (row.entry) { 354 | node.parent.edit.update('null') 355 | } else { 356 | node.parent.edit.update('({})') 357 | } 358 | } else { 359 | renameIdentifier(node, moduleBaseName) 360 | } 361 | }) 362 | if (scan.scope(ast)) { 363 | // rename colliding global variable names 364 | scan.scope(ast).forEach(function (binding, name) { 365 | if (binding[kShouldRename]) { 366 | renameBinding(binding, toIdentifier('__' + name + '_' + row.id)) 367 | } 368 | }) 369 | } 370 | } 371 | 372 | row[kRequireCalls].forEach(function (req) { 373 | var node = req.node 374 | var other = req.requiredModule 375 | if (req.external) { 376 | node.edit.update('require(' + JSON.stringify(req.id) + ')') 377 | } else if (other && other[kEvaluateOnDemand]) { 378 | node.edit.update(other[kExportsName] + '({})') // `module.parent` value = {} 379 | } else if (other && other[kExportsName]) { 380 | renameImport(row, node, other[kExportsName]) 381 | } else { 382 | // TODO this is an unknown module, so probably something went wrong and we should throw an error? 383 | node.edit.update(toIdentifier('_$module_' + req.id)) 384 | } 385 | }) 386 | 387 | if (row[kEvaluateOnDemand]) { 388 | magicString.prepend('var ' + row[kExportsName] + ' = ' + rows.createModuleFactoryName + '(function (module, exports) {\n') 389 | magicString.append('\n});') 390 | } else if (moduleBaseName) { 391 | magicString 392 | .prepend('var ' + moduleBaseName + ' = { exports: {} };\n') 393 | .append('\n' + moduleBaseName + ' = ' + moduleExportsName) 394 | moduleExportsName = moduleBaseName 395 | } else if (!row[kIsSimpleExport]) { 396 | magicString.prepend('var ' + moduleExportsName + ' = {};\n') 397 | } 398 | 399 | row[kSourceMap] = magicString.map 400 | row.source = magicString.toString() 401 | } 402 | 403 | function flatten (rows, opts, stream) { 404 | rows.byId = Object.create(null) 405 | rows.forEach(function (row) { rows.byId[row.id] = row }) 406 | 407 | var containsCycles = detectCycles(rows) 408 | 409 | var combiner = opts.debug ? combineSourceMap.create() : null 410 | 411 | var intro = '' 412 | var outro = '' 413 | 414 | rows.usedGlobalVariables = new Set() 415 | rows.exposeName = generateName(rows, 'exposedRequire') 416 | rows.createModuleFactoryName = generateName(rows, 'createModuleFactory') 417 | rows.forEach(function (row, index, rows) { 418 | parseModule(row, index, rows, opts) 419 | }) 420 | sortModules(rows) 421 | rows.forEach(identifyGlobals) 422 | rows.forEach(markDuplicateVariableNames) 423 | rows.forEach(rewriteModule) 424 | moveOnDemandModulesToStart(rows) 425 | 426 | // Initialize entry modules that are marked as on-demand (because of a dependency cycle 427 | // or a conditional require() call) 428 | for (var i = 0; i < rows.length; i++) { 429 | if (rows[i].entry && rows[i][kEvaluateOnDemand]) { 430 | outro += '\n' + rows[i][kExportsName] + '();' 431 | } 432 | } 433 | 434 | // Expose modules on the global `require` function, or standalone as UMD 435 | var exposesModules = false 436 | for (var i = 0; i < rows.length; i++) { 437 | if (rows[i].expose && !opts.standalone) { 438 | exposesModules = true 439 | if (rows[i][kEvaluateOnDemand]) { 440 | // If the module is evaluated on demand, using a function, define 441 | // a getter so the function will be called. 442 | outro += '\nObject.defineProperty(' + rows.exposeName + '.m, ' + JSON.stringify(rows[i].id) + ', { get: function() { return ' + rows[i][kExportsName] + '({}); }});' 443 | } else { 444 | outro += '\n' + rows.exposeName + '.m[' + JSON.stringify(rows[i].id) + '] = ' + rows[i][kExportsName] + ';' 445 | } 446 | } 447 | 448 | var isEntryModule = rows[i].entry && rows[i].hasExports && opts.standalone 449 | // Need this for: 450 | // https://github.com/browserify/browserify/blob/0305b703b226878f3acb5b8f2ff9451c87cd3991/test/debug_standalone.js#L44-L64 451 | var isStandaloneModule = opts.standalone && rows[i].id === stream.standaloneModule 452 | if (isEntryModule || isStandaloneModule) { 453 | outro += '\nreturn ' + rows[i][kExportsName] + ';\n' 454 | } 455 | } 456 | 457 | if (opts.standalone) { 458 | intro += umd.prelude(opts.standalone) 459 | outro += umd.postlude(opts.standalone) 460 | } else if (exposesModules) { 461 | intro += dedent` 462 | require = (function (require) { 463 | var ${rows.exposeName} = ${exposedRequireCode}; 464 | ${rows.exposeName}.m = {}; 465 | ${rows.exposeName}.r = require; 466 | ` 467 | outro += '\n' + dedent` 468 | return ${rows.exposeName}; 469 | }(typeof require === 'function' ? require : void 0)); 470 | ` 471 | } else if (opts.iife || opts.iife == undefined) { 472 | intro += '(function(){\n' 473 | outro += '\n}());' 474 | } 475 | 476 | // Add the circular dependency/on-demand runtime if necessary. 477 | if (rows.some(function (mod) { return mod[kEvaluateOnDemand] })) { 478 | intro += 'var ' + rows.createModuleFactoryName + ' = ' + createModuleFactoryCode + ';\n' 479 | } 480 | 481 | var result = '' 482 | var line = 0 483 | 484 | var preludePath = path.relative( 485 | opts.basedir || process.cwd(), 486 | path.join(__dirname, '_prelude') 487 | ) 488 | var postludePath = path.relative( 489 | opts.basedir || process.cwd(), 490 | path.join(__dirname, '_postlude') 491 | ) 492 | 493 | result += intro 494 | if (opts.debug) { 495 | combiner.addFile({ 496 | sourceFile: preludePath, 497 | source: intro 498 | }, { line: line }) 499 | } 500 | 501 | line += countLines(intro) - 1 502 | 503 | rows.forEach(function (row, i) { 504 | if (i > 0) { 505 | result += '\n' 506 | line += 1 507 | } 508 | result += row.source 509 | if (opts.debug && row.sourceFile && !row.nomap) { 510 | combiner.addFile({ 511 | sourceFile: row.sourceFile, 512 | source: row.source + '\n' + convertSourceMap.fromObject(row[kSourceMap]).toComment() 513 | }, { line: line }) 514 | } 515 | 516 | line += countLines(row.source) - 1 517 | }) 518 | 519 | result += outro 520 | if (opts.debug) { 521 | combiner.addFile({ 522 | sourceFile: postludePath, 523 | source: outro 524 | }, { line: line }) 525 | } 526 | 527 | if (opts.debug) { 528 | result += '\n' + combiner.comment() 529 | } 530 | 531 | result += '\n' 532 | 533 | return Buffer.from(result) 534 | } 535 | 536 | module.exports = function browserPackFlat(opts) { 537 | // When used as a transform 538 | if (typeof opts === 'string' && typeof arguments[1] === 'object') { 539 | throw new Error('browser-pack-flat: must be used as a plugin through `browser-pack-flat/plugin`') 540 | } 541 | // When used as a plugin 542 | if (opts && typeof opts.plugin === 'function') { 543 | // Doing 'plu' + 'gin' so browserify doesn't detect this require() call 544 | // when running the self-test. Workaround for this bug: 545 | // https://github.com/browserify/browserify/issues/1260 546 | return require('./plu' + 'gin').apply(null, arguments) 547 | } 548 | 549 | opts = opts || {} 550 | 551 | var rows = [] 552 | 553 | var packer = through.obj(onwrite, onend) 554 | var stream = opts.raw ? packer : combiner([ 555 | json.parse([ true ]), 556 | packer 557 | ]) 558 | 559 | return stream 560 | 561 | function onwrite (row, enc, cb) { 562 | rows.push(row) 563 | cb(null) 564 | } 565 | function onend (cb) { 566 | try { 567 | packer.push(flatten(rows, opts || {}, stream)) 568 | packer.push(null) 569 | cb(null) 570 | } catch (err) { 571 | cb(err) 572 | } 573 | } 574 | } 575 | 576 | /** 577 | * Detect cyclical dependencies in the bundle. All modules in a dependency cycle 578 | * are moved to the top of the bundle and wrapped in functions so they're not 579 | * evaluated immediately. When other modules need a module that's in a dependency 580 | * cycle, instead of using the module's exportName, it'll call the `createModuleFactory` runtime 581 | * function, which will execute the requested module and return its exports. 582 | */ 583 | function detectCycles (rows) { 584 | var cyclicalModules = new Set() 585 | var checked = new Set() 586 | rows.forEach(function (module) { 587 | var visited = [] 588 | 589 | check(module) 590 | 591 | function check (row) { 592 | var i = visited.indexOf(row) 593 | if (i !== -1) { 594 | checked.add(row) 595 | for (; i < visited.length; i++) { 596 | cyclicalModules.add(visited[i]) 597 | } 598 | return 599 | } 600 | if (checked.has(row)) return 601 | visited.push(row) 602 | Object.keys(row.deps).forEach(function (k) { 603 | var dep = row.deps[k] 604 | var other = rows.byId[dep] 605 | if (other) check(other, visited) 606 | }) 607 | visited.pop() 608 | } 609 | }) 610 | 611 | // mark cyclical dependencies 612 | for (var i = 0; i < rows.length; i++) { 613 | rows[i][kEvaluateOnDemand] = cyclicalModules.has(rows[i]) 614 | } 615 | return cyclicalModules.size > 0 616 | } 617 | 618 | function moveOnDemandModulesToStart (rows) { 619 | for (var i = 0; i < rows.length; i++) { 620 | if (rows[i][kEvaluateOnDemand]) { 621 | var row = rows.splice(i, 1)[0] 622 | rows.unshift(row) 623 | } 624 | } 625 | } 626 | 627 | function getNodeName (node) { 628 | if (node.type === 'FunctionExpression') node = node.id 629 | else if (node.type === 'ClassExpression') node = node.id 630 | if (node && node.type === 'Identifier') { 631 | return node.name 632 | } 633 | } 634 | 635 | function isModuleExports (node) { 636 | return isMemberExpression(node, 'module.exports') 637 | } 638 | function isModuleParent (node) { 639 | return isMemberExpression(node, 'module.parent') 640 | } 641 | 642 | function isObjectKey (node) { 643 | return node.parent.type === 'Property' && node.parent.key === node 644 | } 645 | function isShorthandProperty (node) { 646 | return node.type === 'Identifier' && isObjectKey(node) && node.parent.shorthand 647 | } 648 | 649 | function renameIdentifier (node, name) { 650 | if (isShorthandProperty(node)) { 651 | node.edit.update(node.name + ': ' + name) 652 | } else { 653 | node.edit.update(name) 654 | } 655 | } 656 | 657 | function renameImport (row, node, name) { 658 | if (node.parent.type === 'VariableDeclarator' && node.parent.id.type === 'Identifier') { 659 | var binding = scan.getBinding(node.parent.id) 660 | if (binding) { 661 | renameBinding(binding, name) 662 | removeVariableDeclarator(row, node.parent) 663 | return 664 | } 665 | } 666 | node.edit.update(name) 667 | } 668 | 669 | function renameBinding (binding, newName) { 670 | binding.each(function (node) { 671 | renameIdentifier(node, newName) 672 | }) 673 | } 674 | 675 | // Remove a variable declarator -- remove the declaration entirely if it is the only one, 676 | // otherwise replace with a dummy declarator 677 | function removeVariableDeclarator (row, decl) { 678 | if (decl.parent.type === 'VariableDeclaration') { 679 | var i = decl.parent.declarations.indexOf(decl) 680 | if (decl.parent.declarations.length === 1) { 681 | var removed = decl.parent.getSource() 682 | decl.parent.edit.update(wrapComment('removed: ' + removed) + ';') 683 | } else if (i === decl.parent.declarations.length - 1) { 684 | // Remove ", a = 1" 685 | row[kMagicString].overwrite(decl.parent.declarations[i - 1].end, decl.end, '') 686 | } else { 687 | // Remove "a = 1, " 688 | row[kMagicString].overwrite(decl.start, decl.parent.declarations[i + 1].start, '') 689 | } 690 | decl.parent.declarations.splice(i, 1) 691 | } else { 692 | if (!row[kDummyVars]) row[kDummyVars] = 0 693 | var id = '__dummy_' + row.index + '$' + row[kDummyVars] 694 | row[kDummyVars]++ 695 | decl.edit.update(toIdentifier(id) + ' = 0') 696 | } 697 | } 698 | 699 | function getModuleName (file) { 700 | var parts = pathParse(file) 701 | var name = parts.base === 'index.js' 702 | ? path.basename(parts.dir) 703 | : parts.name 704 | return name || 'module' 705 | } 706 | 707 | function generateName (rows, base) { 708 | var dedupe = '' 709 | var i = 0 710 | while (true) { 711 | var inUse = rows.some(function (row) { 712 | return row.source.indexOf(base + dedupe) !== -1 713 | }) 714 | if (!inUse) { 715 | return base + dedupe 716 | } 717 | dedupe = '_' + (i++) 718 | } 719 | } 720 | -------------------------------------------------------------------------------- /lib/createModuleFactory.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Helper used in the output bundle to resolve dependency cycles. 3 | * This helper wraps a module factory and lazily executes it. 4 | * Imports of a circular module will call the factory returned by this function. 5 | */ 6 | module.exports = function createModuleFactory (factory) { 7 | var module 8 | return function (parent) { 9 | if (!module) { 10 | module = { exports: {}, parent: parent } 11 | factory(module, module.exports) 12 | } 13 | return module.exports 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/exposedRequire.js: -------------------------------------------------------------------------------- 1 | // Helper to expose a module. 2 | module.exports = function exposedRequire (m, jumped) { 3 | // A locally exposed module 4 | if (exposedRequire.m.hasOwnProperty(m)) { 5 | return exposedRequire.m[m] 6 | } 7 | // A module exposed on a later chunk 8 | if (typeof require === 'function' && !jumped) { 9 | return require(m, 1) 10 | } 11 | // A module exposed on a previous chunk 12 | if (typeof exposedRequire.r === 'function') { 13 | return exposedRequire.r(m, 1) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "browser-pack-flat", 3 | "version": "3.5.0", 4 | "description": "bundle browserify modules into a single scope, a la rollup", 5 | "main": "index.js", 6 | "bin": { 7 | "browser-pack-flat": "cli.js" 8 | }, 9 | "scripts": { 10 | "build": "node build", 11 | "prepare": "node build", 12 | "test": "node build && tape test/test.js test/expose.js test/order.js test/self.js" 13 | }, 14 | "keywords": [], 15 | "author": "Renée Kooi ", 16 | "license": "MIT", 17 | "dependencies": { 18 | "JSONStream": "^1.3.2", 19 | "combine-source-map": "^0.8.0", 20 | "convert-source-map": "^1.5.1", 21 | "count-lines": "^0.1.2", 22 | "dedent": "^0.7.0", 23 | "estree-is-member-expression": "^1.0.0", 24 | "estree-is-require": "^1.0.0", 25 | "esutils": "^2.0.2", 26 | "path-parse": "^1.0.5", 27 | "scope-analyzer": "^2.0.0", 28 | "stream-combiner": "^0.2.2", 29 | "through2": "^3.0.2", 30 | "transform-ast": "^2.4.2", 31 | "umd": "^3.0.3", 32 | "wrap-comment": "^1.0.0" 33 | }, 34 | "devDependencies": { 35 | "@babel/core": "^7.5.4", 36 | "@babel/plugin-transform-modules-commonjs": "^7.5.0", 37 | "babelify": "^10.0.0", 38 | "brfs": "^2.0.2", 39 | "browser-unpack": "^1.2.0", 40 | "browserify": "^17.0.0", 41 | "concat-stream": "^2.0.0", 42 | "nanohtml": "1.6.1", 43 | "sliced": "^1.0.1", 44 | "tape": "^5.0.0", 45 | "uglify-js": "3.6.0" 46 | }, 47 | "directories": { 48 | "test": "test" 49 | }, 50 | "repository": { 51 | "type": "git", 52 | "url": "git+https://github.com/goto-bus-stop/browser-pack-flat.git" 53 | }, 54 | "bugs": { 55 | "url": "https://github.com/goto-bus-stop/browser-pack-flat/issues" 56 | }, 57 | "homepage": "https://github.com/goto-bus-stop/browser-pack-flat#readme" 58 | } 59 | -------------------------------------------------------------------------------- /plugin.js: -------------------------------------------------------------------------------- 1 | var pack = require('./index') 2 | 3 | module.exports = function apply (b, opts) { 4 | // When used as a transform 5 | if (typeof b !== 'object') { 6 | throw new Error('browser-pack-flat: must be used as a plugin, not a transform') 7 | } 8 | 9 | opts = Object.assign({}, opts || {}, { 10 | raw: true, 11 | debug: opts.debug || b._options.debug, 12 | basedir: b._options.basedir || process.cwd() 13 | }) 14 | 15 | function addHooks () { 16 | var streams = b.pipeline.get('pack') 17 | var index = streams.indexOf(b._bpack) 18 | 19 | streams.splice(index, 1, 20 | pack(Object.assign({}, opts, { 21 | standalone: b._options.standalone, 22 | standaloneModule: b._options.standaloneModule 23 | })) 24 | ) 25 | } 26 | 27 | addHooks() 28 | b.on('reset', addHooks) 29 | } 30 | -------------------------------------------------------------------------------- /private_modules/identifierfy/LICENSE: -------------------------------------------------------------------------------- 1 | ISC License (ISC) 2 | Copyright (c) 2016, Mark Wubben 3 | 4 | Permission to use, copy, modify, and/or distribute this software for any purpose 5 | with or without fee is hereby granted, provided that the above copyright notice 6 | and this permission notice appear in all copies. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 10 | FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 12 | OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 13 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 14 | THIS SOFTWARE. 15 | -------------------------------------------------------------------------------- /private_modules/identifierfy/README.md: -------------------------------------------------------------------------------- 1 | # identifierfy 2 | 3 | Rewrites an identifier string so it's valid according to ES2015. Works in 4 | Node.js 6 and above. 5 | 6 | Please see [this awesome article by Mathias 7 | Bynens](https://mathiasbynens.be/notes/javascript-identifiers-es6) for 8 | background. 9 | 10 | ## Installation 11 | 12 | ``` 13 | npm install identifierfy 14 | ``` 15 | 16 | ## Usage 17 | 18 | The module has one default export, the `identifierfy` function: 19 | 20 | ```js 21 | const identifierfy = require('identifierfy') 22 | ``` 23 | 24 | Call `identifierfy()` with an identifier string. It'll return a string that can 25 | be used as an identifier, which is useful when [writing Babel 26 | plugins](https://github.com/thejameskyle/babel-plugin-handbook). 27 | 28 | Characters that are not allowed in identifiers are dropped. Any character that 29 | follows a removed character is uppercased, except if the dropped character was 30 | at the front of the string. 31 | 32 | If necessary the resulting identifier is prefixed with an underscore. This will 33 | happen if the string is a reserved word or if the first character cannot be used 34 | as the first character (but is fine as the second character). 35 | 36 | This behavior can be overridden by passing a second `options` argument. This 37 | should be an object. Set `prefixReservedWords` to `false` to avoid reserved 38 | words being prefixed. Set `prefixInvalidIdentifiers` to `false` to avoid 39 | prefixing identifiers where the first character cannot be used. These options 40 | are useful if the resulting value is concatenated with other characters, making 41 | it valid after all. 42 | 43 | Note that `null` is returned if all characters from the original string are 44 | dropped. 45 | 46 | ## Examples 47 | 48 | ```js 49 | identifierfy(input) 50 | ``` 51 | 52 | Input|Resulting identifier|Reason 53 | :---|:---|:--- 54 | `'class`|`'_class'`|Reserved word 55 | `'42'`|`'_42'`|Identifiers cannot start with a number 56 | `'-foo'`|`'foo'`|The `-` is dropped, but since it's as the front `f` is not uppercased 57 | `'foo-bar🙊baz'`|`'fooBarBaz'`|The `-` and `🙊` characters are dropped, and the following characters uppercased 58 | `'foo-9'`|`foo9`|`9` can't be uppercased of course 😉 59 | `'💩'`|`null`|Sadly emojis cannot be used as identifiers 😢 60 | 61 | ```js 62 | identifierfy(input, {prefixReservedWords: false}) 63 | ``` 64 | Input|Resulting identifier|Reason 65 | :---|:---|:--- 66 | `'class`|`'class'`|Reserved word, but prefixing is disabled 67 | `'42'`|`'_42'`|Identifiers cannot start with a number 68 | 69 | ```js 70 | identifierfy(input, {prefixInvalidIdentifiers: false}) 71 | ``` 72 | Input|Resulting identifier|Reason 73 | :---|:---|:--- 74 | `'class`|`'_class'`|Reserved word 75 | `'42'`|`'42'`|Identifiers cannot start with a number, however prefixing is disabled so it's OK 76 | 77 | ```js 78 | identifierfy(input, {prefixInvalidIdentifiers: false, prefixReservedWords: false}) 79 | ``` 80 | Input|Resulting identifier|Reason 81 | :---|:---|:--- 82 | `'class`|`'class'`|Reserved word, but prefixing is disabled 83 | `'42'`|`'42'`|Identifiers cannot start with a number, however prefixing is disabled so it's OK 84 | -------------------------------------------------------------------------------- /private_modules/identifierfy/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://github.com/novemberborn/identifierfy, compiled to support Node 4 3 | */ 4 | 5 | 'use strict' 6 | var keyword = require('esutils').keyword 7 | 8 | // Follow Babel's implementation: 9 | // 10 | function isValidIdentifier (name) { 11 | return !keyword.isReservedWordES6(name, true) && keyword.isIdentifierNameES6(name) 12 | } 13 | 14 | // Rewrite the name until it forms a valid identifier. 15 | module.exports = function identifierfy (name, options) { 16 | var prefixInvalidIdentifiers = options && options.prefixInvalidIdentifiers !== undefined ? options.prefixInvalidIdentifiers : true 17 | var prefixReservedWords = options && options.prefixReservedWords !== undefined ? options.prefixReservedWords : true 18 | // Start with a valid character. This way if the first character in the name 19 | // is not allowed to be used as the first character it can be prefixed with 20 | // an underscore, without having to be dropped. The same goes for if the name 21 | // is a reserved word. 22 | var intermediate = '_' 23 | 24 | // Flag whether the previous character was invalid (and thus dropped). 25 | var prevWasInvalid = false 26 | 27 | // Use for/of to iterate over the code points. This way surrogate pairs can 28 | // be avoided. 29 | for (var char of name) { 30 | // Try to uppercase the immediately following (not all characters have an 31 | // case equivalent though). Ignore if the dropped character was at the front 32 | // of the name. 33 | if (prevWasInvalid && intermediate !== '_') { 34 | char = char.toUpperCase() 35 | } 36 | 37 | // Only include characters if the name remains valid. 38 | if (isValidIdentifier(intermediate + char)) { 39 | intermediate += char 40 | prevWasInvalid = false 41 | } else { 42 | prevWasInvalid = true 43 | } 44 | } 45 | 46 | // Return `null` if no characters from the original name survive the process. 47 | if (intermediate === '_') return null 48 | 49 | // If the name is valid without the underscore prefix return it as such, 50 | // otherwise retain it, unless directed otherwise. 51 | var withoutPrefix = intermediate.slice(1) 52 | if (isValidIdentifier(withoutPrefix)) { 53 | return withoutPrefix 54 | } else if (prefixInvalidIdentifiers && prefixReservedWords) { 55 | return intermediate 56 | } else { 57 | var isIdentifierName = keyword.isIdentifierNameES6(withoutPrefix) 58 | var isReservedWord = keyword.isReservedWordES6(withoutPrefix, true) 59 | if ((!isIdentifierName && !prefixInvalidIdentifiers) || 60 | (isReservedWord && !prefixReservedWords)) { 61 | return withoutPrefix 62 | } else { 63 | return intermediate 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /private_modules/identifierfy/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "_from": "identifierfy@latest", 3 | "_id": "identifierfy@2.0.0", 4 | "_inBundle": false, 5 | "_integrity": "sha512-Gx1CmO0DbL5aECe3kclZNNDsGPIRo9NThTSTAeS3U8Pn58OsadGpU6ByxFriVHT8HQtGO9WErxZOfrXcx3yHOw==", 6 | "_location": "/identifierfy", 7 | "_phantomChildren": {}, 8 | "_requested": { 9 | "type": "tag", 10 | "registry": true, 11 | "raw": "identifierfy@latest", 12 | "name": "identifierfy", 13 | "escapedName": "identifierfy", 14 | "rawSpec": "latest", 15 | "saveSpec": null, 16 | "fetchSpec": "latest" 17 | }, 18 | "_requiredBy": [ 19 | "#USER", 20 | "/" 21 | ], 22 | "_resolved": "https://registry.npmjs.org/identifierfy/-/identifierfy-2.0.0.tgz", 23 | "_shasum": "82922a33791e28b4e4d119dd1bc4a20c9a69c9c0", 24 | "_spec": "identifierfy@latest", 25 | "_where": "/home/goto-bus-stop/Code/goto-bus-stop/browser-pack-flat", 26 | "author": { 27 | "name": "Mark Wubben", 28 | "url": "https://novemberborn.net/" 29 | }, 30 | "bugs": { 31 | "url": "https://github.com/novemberborn/identifierfy/issues" 32 | }, 33 | "bundleDependencies": false, 34 | "dependencies": { 35 | "esutils": "^2.0.2" 36 | }, 37 | "deprecated": false, 38 | "description": "Rewrites an identifier string so its valid according to ES2015", 39 | "devDependencies": { 40 | "@novemberborn/as-i-preach": "^11.0.0", 41 | "ava": "^1.0.0-beta.8", 42 | "nyc": "^13.0.1" 43 | }, 44 | "engines": { 45 | "node": ">= 6" 46 | }, 47 | "files": [ 48 | "index.js" 49 | ], 50 | "homepage": "https://github.com/novemberborn/identifierfy#readme", 51 | "keywords": [ 52 | "es6", 53 | "es2015", 54 | "identifier" 55 | ], 56 | "license": "ISC", 57 | "main": "index.js", 58 | "name": "identifierfy", 59 | "nyc": { 60 | "reporter": [ 61 | "lcov", 62 | "html", 63 | "text" 64 | ] 65 | }, 66 | "repository": { 67 | "type": "git", 68 | "url": "git+https://github.com/novemberborn/identifierfy.git" 69 | }, 70 | "scripts": { 71 | "lint": "as-i-preach", 72 | "test": "as-i-preach && nyc ava" 73 | }, 74 | "version": "2.0.0" 75 | } 76 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # browser-pack-flat 2 | 3 | Bundle browserify modules into a single scope, a la rollup. 4 | 5 | Caveats: 6 | 7 | - Modules are executed fully, one after another, instead of inline. 8 | This is a potential difference from Node.js and the default browserify behaviour. 9 | Usually this does not matter, but rarely the order that some things are executed in may change. 10 | - This rewrites `require()` calls to simple variable assignments. 11 | If a module wraps `require()` somehow it probably will not work. 12 | In practice this is quite rare. 13 | - Using `factor-bundle` to split output code into separate files will not work with this plugin. 14 | 15 | ## Install 16 | 17 | ```bash 18 | npm install --save-dev browser-pack-flat 19 | ``` 20 | 21 | ## Usage 22 | 23 | ```bash 24 | browserify /path/to/app.js | browser-unpack | browser-pack-flat 25 | ``` 26 | 27 | Or as a plugin: 28 | 29 | ```bash 30 | browserify /path/to/app.js -p browser-pack-flat 31 | ``` 32 | 33 | The plugin replaces the `browser-pack` module used by default by browserify. 34 | 35 | With the Node API: 36 | 37 | ```js 38 | var browserify = require('browserify') 39 | var packFlat = require('browser-pack-flat') 40 | 41 | browserify({ entries: './src/app.js' }) 42 | .plugin(packFlat, { /* options */ }) 43 | .bundle() 44 | .pipe(fs.createWriteStream('bundle.js')) 45 | ``` 46 | 47 | ## What exactly? 48 | 49 | browserify uses [browser-pack](https://github.com/browserify/browser-pack) to output a bundle. 50 | browser-pack uses a small `require`-like runtime and wraps modules in functions to get a module loading behaviour that's almost identical to Node.js. 51 | However this resolution can take a few milliseconds across an entire bundle. 52 | 53 | Input: 54 | 55 | ```js 56 | var unique = require('uniq'); 57 | 58 | var data = [1, 2, 2, 3, 4, 5, 5, 5, 6]; 59 | 60 | console.log(unique(data)); 61 | ``` 62 | 63 | With browser-pack, this bundle would output: 64 | 65 | ```js 66 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 6 |

News

7 |
8 |
9 |
10 |

${dep('title')}

11 |

12 | ${dep('excerpt')} 13 |

14 |
15 |
16 | Photo of a dimly lit room with a computer interface terminal. 17 |
18 |
19 |

By ${dep('author')}

20 | 21 |
22 | 23 | `) 24 | -------------------------------------------------------------------------------- /test/input-source-map/dep.js: -------------------------------------------------------------------------------- 1 | export default function whatever (xyz) { 2 | return xyz.toUpperCase() 3 | } 4 | -------------------------------------------------------------------------------- /test/input-source-map/expected.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | var _$dep_3 = {}; 3 | "use strict"; 4 | 5 | Object.defineProperty(_$dep_3, "__esModule", { 6 | value: true 7 | }); 8 | _$dep_3.default = whatever; 9 | function whatever(xyz) { 10 | return xyz.toUpperCase(); 11 | } 12 | 13 | var trailingNewlineRegex = /\n[\s]+$/ 14 | var leadingNewlineRegex = /^\n[\s]+/ 15 | var trailingSpaceRegex = /[\s]+$/ 16 | var leadingSpaceRegex = /^[\s]+/ 17 | var multiSpaceRegex = /[\n\s]+/g 18 | 19 | var TEXT_TAGS = [ 20 | 'a', 'abbr', 'b', 'bdi', 'bdo', 'br', 'cite', 'data', 'dfn', 'em', 'i', 21 | 'kbd', 'mark', 'q', 'rp', 'rt', 'rtc', 'ruby', 's', 'amp', 'small', 'span', 22 | 'strong', 'sub', 'sup', 'time', 'u', 'var', 'wbr' 23 | ] 24 | 25 | var VERBATIM_TAGS = [ 26 | 'code', 'pre', 'textarea' 27 | ] 28 | 29 | var _$appendChild_1 = function appendChild (el, childs) { 30 | if (!Array.isArray(childs)) return 31 | 32 | var nodeName = el.nodeName.toLowerCase() 33 | 34 | var hadText = false 35 | var value, leader 36 | 37 | for (var i = 0, len = childs.length; i < len; i++) { 38 | var node = childs[i] 39 | if (Array.isArray(node)) { 40 | appendChild(el, node) 41 | continue 42 | } 43 | 44 | if (typeof node === 'number' || 45 | typeof node === 'boolean' || 46 | typeof node === 'function' || 47 | node instanceof Date || 48 | node instanceof RegExp) { 49 | node = node.toString() 50 | } 51 | 52 | var lastChild = el.childNodes[el.childNodes.length - 1] 53 | 54 | // Iterate over text nodes 55 | if (typeof node === 'string') { 56 | hadText = true 57 | 58 | // If we already had text, append to the existing text 59 | if (lastChild && lastChild.nodeName === '#text') { 60 | lastChild.nodeValue += node 61 | 62 | // We didn't have a text node yet, create one 63 | } else { 64 | node = document.createTextNode(node) 65 | el.appendChild(node) 66 | lastChild = node 67 | } 68 | 69 | // If this is the last of the child nodes, make sure we close it out 70 | // right 71 | if (i === len - 1) { 72 | hadText = false 73 | // Trim the child text nodes if the current node isn't a 74 | // node where whitespace matters. 75 | if (TEXT_TAGS.indexOf(nodeName) === -1 && 76 | VERBATIM_TAGS.indexOf(nodeName) === -1) { 77 | value = lastChild.nodeValue 78 | .replace(leadingNewlineRegex, '') 79 | .replace(trailingSpaceRegex, '') 80 | .replace(trailingNewlineRegex, '') 81 | .replace(multiSpaceRegex, ' ') 82 | if (value === '') { 83 | el.removeChild(lastChild) 84 | } else { 85 | lastChild.nodeValue = value 86 | } 87 | } else if (VERBATIM_TAGS.indexOf(nodeName) === -1) { 88 | // The very first node in the list should not have leading 89 | // whitespace. Sibling text nodes should have whitespace if there 90 | // was any. 91 | leader = i === 0 ? '' : ' ' 92 | value = lastChild.nodeValue 93 | .replace(leadingNewlineRegex, leader) 94 | .replace(leadingSpaceRegex, ' ') 95 | .replace(trailingSpaceRegex, '') 96 | .replace(trailingNewlineRegex, '') 97 | .replace(multiSpaceRegex, ' ') 98 | lastChild.nodeValue = value 99 | } 100 | } 101 | 102 | // Iterate over DOM nodes 103 | } else if (node && node.nodeType) { 104 | // If the last node was a text node, make sure it is properly closed out 105 | if (hadText) { 106 | hadText = false 107 | 108 | // Trim the child text nodes if the current node isn't a 109 | // text node or a code node 110 | if (TEXT_TAGS.indexOf(nodeName) === -1 && 111 | VERBATIM_TAGS.indexOf(nodeName) === -1) { 112 | value = lastChild.nodeValue 113 | .replace(leadingNewlineRegex, '') 114 | .replace(trailingNewlineRegex, '') 115 | .replace(multiSpaceRegex, ' ') 116 | 117 | // Remove empty text nodes, append otherwise 118 | if (value === '') { 119 | el.removeChild(lastChild) 120 | } else { 121 | lastChild.nodeValue = value 122 | } 123 | // Trim the child nodes if the current node is not a node 124 | // where all whitespace must be preserved 125 | } else if (VERBATIM_TAGS.indexOf(nodeName) === -1) { 126 | value = lastChild.nodeValue 127 | .replace(leadingSpaceRegex, ' ') 128 | .replace(leadingNewlineRegex, '') 129 | .replace(trailingNewlineRegex, '') 130 | .replace(multiSpaceRegex, ' ') 131 | lastChild.nodeValue = value 132 | } 133 | } 134 | 135 | // Store the last nodename 136 | var _nodeName = node.nodeName 137 | if (_nodeName) nodeName = _nodeName.toLowerCase() 138 | 139 | // Append the node to the DOM 140 | el.appendChild(node) 141 | } 142 | } 143 | } 144 | 145 | var _$app_2 = {}; 146 | "use strict"; 147 | 148 | var _dep = _interopRequireDefault(_$dep_3); 149 | var _athelas, 150 | _f, 151 | _f2, 152 | _w_, 153 | _db, 154 | _pl3Ns, 155 | _flex, 156 | _ttu, 157 | _f3, 158 | _f4, 159 | _pv, 160 | _mw; 161 | function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } 162 | document.body.appendChild((_mw = document.createElement("section"), _mw.setAttribute("class", "mw7 center"), _$appendChild_1(_mw, ["\n\t ", (_athelas = document.createElement("h2"), _athelas.setAttribute("class", "athelas ph3 ph0-l"), _$appendChild_1(_athelas, ["News"]), _athelas), "\n\t ", (_pv = document.createElement("article"), _pv.setAttribute("class", "pv4 bt bb b--black-10 ph3 ph0-l"), _$appendChild_1(_pv, ["\n\t\t", (_flex = document.createElement("div"), _flex.setAttribute("class", "flex flex-column flex-row-ns"), _$appendChild_1(_flex, ["\n\t\t ", (_w_ = document.createElement("div"), _w_.setAttribute("class", "w-100 w-60-ns pr3-ns order-2 order-1-ns"), _$appendChild_1(_w_, ["\n\t\t\t ", (_f = document.createElement("h1"), _f.setAttribute("class", "f3 athelas mt0 lh-title"), _$appendChild_1(_f, [(0, _dep.default)('title')]), _f), "\n\t\t\t ", (_f2 = document.createElement("p"), _f2.setAttribute("class", "f5 f4-l lh-copy athelas"), _$appendChild_1(_f2, ["\n\t\t\t\t", (0, _dep.default)('excerpt'), "\n\t\t\t "]), _f2), "\n\t\t "]), _w_), "\n\t\t ", (_pl3Ns = document.createElement("div"), _pl3Ns.setAttribute("class", "pl3-ns order-1 order-2-ns mb4 mb0-ns w-100 w-40-ns"), _$appendChild_1(_pl3Ns, ["\n\t\t\t ", (_db = document.createElement("img"), _db.setAttribute("src", "http://mrmrs.github.io/photos/cpu.jpg"), _db.setAttribute("alt", "Photo of a dimly lit room with a computer interface terminal."), _db.setAttribute("class", "db"), _db), "\n\t\t "]), _pl3Ns), "\n\t\t"]), _flex), "\n\t\t", (_f3 = document.createElement("p"), _f3.setAttribute("class", "f6 lh-copy gray mv0"), _$appendChild_1(_f3, ["By ", (_ttu = document.createElement("span"), _ttu.setAttribute("class", "ttu"), _$appendChild_1(_ttu, [(0, _dep.default)('author')]), _ttu)]), _f3), "\n\t\t", (_f4 = document.createElement("time"), _f4.setAttribute("class", "f6 db gray"), _$appendChild_1(_f4, [(0, _dep.default)('timestamp')]), _f4), "\n\t "]), _pv), "\n "]), _mw)); 163 | 164 | }()); 165 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIl9wcmVsdWRlIiwidGVzdC9pbnB1dC1zb3VyY2UtbWFwL2RlcC5qcyIsIm5vZGVfbW9kdWxlcy9uYW5vaHRtbC9saWIvYXBwZW5kLWNoaWxkLmpzIiwidGVzdC9pbnB1dC1zb3VyY2UtbWFwL2FwcC5qcyIsIl9wb3N0bHVkZSJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQUNBOzs7Ozs7O0FDRGUsU0FBUyxRQUFRLENBQUUsR0FBRyxFQUFFO0VBQ3JDLE9BQU8sR0FBRyxDQUFDLFdBQVcsRUFBRSxDQUFBO0NBQzFCOztBQ0ZBLElBQUksb0JBQW9CLEdBQUcsVUFBVTtBQUNyQyxJQUFJLG1CQUFtQixHQUFHLFVBQVU7QUFDcEMsSUFBSSxrQkFBa0IsR0FBRyxRQUFRO0FBQ2pDLElBQUksaUJBQWlCLEdBQUcsUUFBUTtBQUNoQyxJQUFJLGVBQWUsR0FBRyxVQUFVOztBQUVoQyxJQUFJLFNBQVMsR0FBRztFQUNkLEdBQUcsRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxHQUFHO0VBQ3RFLEtBQUssRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxNQUFNO0VBQzFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUUsS0FBSyxFQUFFLEtBQUs7Q0FDbEQ7O0FBRUQsSUFBSSxhQUFhLEdBQUc7RUFDbEIsTUFBTSxFQUFFLEtBQUssRUFBRSxVQUFVO0NBQzFCOztBQUVELG1CQUFjLEdBQUcsU0FBUyxXQUFXLEVBQUUsRUFBRSxFQUFFLE1BQU0sRUFBRTtFQUNqRCxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsRUFBRSxNQUFNOztFQUVsQyxJQUFJLFFBQVEsR0FBRyxFQUFFLENBQUMsUUFBUSxDQUFDLFdBQVcsRUFBRTs7RUFFeEMsSUFBSSxPQUFPLEdBQUcsS0FBSztFQUNuQixJQUFJLEtBQUssRUFBRSxNQUFNOztFQUVqQixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxHQUFHLEdBQUcsTUFBTSxDQUFDLE1BQU0sRUFBRSxDQUFDLEdBQUcsR0FBRyxFQUFFLENBQUMsRUFBRSxFQUFFO0lBQ2pELElBQUksSUFBSSxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDcEIsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxFQUFFO01BQ3ZCLFdBQVcsQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDO01BQ3JCLFFBQVE7S0FDVDs7SUFFRCxJQUFJLE9BQU8sSUFBSSxLQUFLLFFBQVE7TUFDMUIsT0FBTyxJQUFJLEtBQUssU0FBUztNQUN6QixPQUFPLElBQUksS0FBSyxVQUFVO01BQzFCLElBQUksWUFBWSxJQUFJO01BQ3BCLElBQUksWUFBWSxNQUFNLEVBQUU7TUFDeEIsSUFBSSxHQUFHLElBQUksQ0FBQyxRQUFRLEVBQUU7S0FDdkI7O0lBRUQsSUFBSSxTQUFTLEdBQUcsRUFBRSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7OztJQUd2RCxJQUFJLE9BQU8sSUFBSSxLQUFLLFFBQVEsRUFBRTtNQUM1QixPQUFPLEdBQUcsSUFBSTs7O01BR2QsSUFBSSxTQUFTLElBQUksU0FBUyxDQUFDLFFBQVEsS0FBSyxPQUFPLEVBQUU7UUFDL0MsU0FBUyxDQUFDLFNBQVMsSUFBSSxJQUFJOzs7T0FHNUIsTUFBTTtRQUNMLElBQUksR0FBRyxRQUFRLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQztRQUNwQyxFQUFFLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQztRQUNwQixTQUFTLEdBQUcsSUFBSTtPQUNqQjs7OztNQUlELElBQUksQ0FBQyxLQUFLLEdBQUcsR0FBRyxDQUFDLEVBQUU7UUFDakIsT0FBTyxHQUFHLEtBQUs7OztRQUdmLElBQUksU0FBUyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7VUFDcEMsYUFBYSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRTtVQUN4QyxLQUFLLEdBQUcsU0FBUyxDQUFDLFNBQVM7YUFDeEIsT0FBTyxDQUFDLG1CQUFtQixFQUFFLEVBQUUsQ0FBQzthQUNoQyxPQUFPLENBQUMsa0JBQWtCLEVBQUUsRUFBRSxDQUFDO2FBQy9CLE9BQU8sQ0FBQyxvQkFBb0IsRUFBRSxFQUFFLENBQUM7YUFDakMsT0FBTyxDQUFDLGVBQWUsRUFBRSxHQUFHLENBQUM7VUFDaEMsSUFBSSxLQUFLLEtBQUssRUFBRSxFQUFFO1lBQ2hCLEVBQUUsQ0FBQyxXQUFXLENBQUMsU0FBUyxDQUFDO1dBQzFCLE1BQU07WUFDTCxTQUFTLENBQUMsU0FBUyxHQUFHLEtBQUs7V0FDNUI7U0FDRixNQUFNLElBQUksYUFBYSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRTs7OztVQUlqRCxNQUFNLEdBQUcsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLEdBQUcsR0FBRztVQUMzQixLQUFLLEdBQUcsU0FBUyxDQUFDLFNBQVM7YUFDeEIsT0FBTyxDQUFDLG1CQUFtQixFQUFFLE1BQU0sQ0FBQzthQUNwQyxPQUFPLENBQUMsaUJBQWlCLEVBQUUsR0FBRyxDQUFDO2FBQy9CLE9BQU8sQ0FBQyxrQkFBa0IsRUFBRSxFQUFFLENBQUM7YUFDL0IsT0FBTyxDQUFDLG9CQUFvQixFQUFFLEVBQUUsQ0FBQzthQUNqQyxPQUFPLENBQUMsZUFBZSxFQUFFLEdBQUcsQ0FBQztVQUNoQyxTQUFTLENBQUMsU0FBUyxHQUFHLEtBQUs7U0FDNUI7T0FDRjs7O0tBR0YsTUFBTSxJQUFJLElBQUksSUFBSSxJQUFJLENBQUMsUUFBUSxFQUFFOztNQUVoQyxJQUFJLE9BQU8sRUFBRTtRQUNYLE9BQU8sR0FBRyxLQUFLOzs7O1FBSWYsSUFBSSxTQUFTLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQztVQUNwQyxhQUFhLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFO1VBQ3hDLEtBQUssR0FBRyxTQUFTLENBQUMsU0FBUzthQUN4QixPQUFPLENBQUMsbUJBQW1CLEVBQUUsRUFBRSxDQUFDO2FBQ2hDLE9BQU8sQ0FBQyxvQkFBb0IsRUFBRSxFQUFFLENBQUM7YUFDakMsT0FBTyxDQUFDLGVBQWUsRUFBRSxHQUFHLENBQUM7OztVQUdoQyxJQUFJLEtBQUssS0FBSyxFQUFFLEVBQUU7WUFDaEIsRUFBRSxDQUFDLFdBQVcsQ0FBQyxTQUFTLENBQUM7V0FDMUIsTUFBTTtZQUNMLFNBQVMsQ0FBQyxTQUFTLEdBQUcsS0FBSztXQUM1Qjs7O1NBR0YsTUFBTSxJQUFJLGFBQWEsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUU7VUFDakQsS0FBSyxHQUFHLFNBQVMsQ0FBQyxTQUFTO2FBQ3hCLE9BQU8sQ0FBQyxpQkFBaUIsRUFBRSxHQUFHLENBQUM7YUFDL0IsT0FBTyxDQUFDLG1CQUFtQixFQUFFLEVBQUUsQ0FBQzthQUNoQyxPQUFPLENBQUMsb0JBQW9CLEVBQUUsRUFBRSxDQUFDO2FBQ2pDLE9BQU8sQ0FBQyxlQUFlLEVBQUUsR0FBRyxDQUFDO1VBQ2hDLFNBQVMsQ0FBQyxTQUFTLEdBQUcsS0FBSztTQUM1QjtPQUNGOzs7TUFHRCxJQUFJLFNBQVMsR0FBRyxJQUFJLENBQUMsUUFBUTtNQUM3QixJQUFJLFNBQVMsRUFBRSxRQUFRLEdBQUcsU0FBUyxDQUFDLFdBQVcsRUFBRTs7O01BR2pELEVBQUUsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDO0tBQ3JCO0dBQ0Y7Q0FDRjs7Ozs7QUNsSUQsSUFBQSxJQUFBLEdBQUEsc0JBQUEsQ0FBQSxPQUFBLENBQUEsQ0FBQTtBQUF1QixJQUFBLFFBQUE7RUFBQSxFQUFBO0VBQUEsR0FBQTtFQUFBLEdBQUE7RUFBQSxHQUFBO0VBQUEsTUFBQTtFQUFBLEtBQUE7RUFBQSxJQUFBO0VBQUEsR0FBQTtFQUFBLEdBQUE7RUFBQSxHQUFBO0VBQUEsR0FBQSxDQUFBO0FBQUEsU0FBQSxzQkFBQSxDQUFBLENBQUEsRUFBQSxFQUFBLE9BQUEsQ0FBQSxJQUFBLENBQUEsQ0FBQSxVQUFBLEdBQUEsQ0FBQSxHQUFBLEVBQUEsT0FBQSxFQUFBLENBQUEsRUFBQSxDQUFBLEVBQUE7QUFHdkIsUUFBUSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUEsR0FBQSxHQUFBLFFBQUEsQ0FBQSxhQUFBLENBQUEsU0FBQSxDQUFBLEVBQUEsR0FBQSxDQUFBLFlBQUEsQ0FBQSxPQUFBLEVBQUEsWUFBQSxDQUFBLEVBQUEsZUFBQSxDQUFBLEdBQUEsRUFBQSxDQUFBLE9BQUEsR0FBQSxRQUFBLEdBQUEsUUFBQSxDQUFBLGFBQUEsQ0FBQSxJQUFBLENBQUEsRUFBQSxRQUFBLENBQUEsWUFBQSxDQUFBLE9BQUEsRUFBQSxtQkFBQSxDQUFBLEVBQUEsZUFBQSxDQUFBLFFBQUEsRUFBQSxDQUFBLE1BQUEsQ0FBQSxDQUFBLEVBQUEsUUFBQSxHQUFBLE9BQUEsR0FBQSxHQUFBLEdBQUEsUUFBQSxDQUFBLGFBQUEsQ0FBQSxTQUFBLENBQUEsRUFBQSxHQUFBLENBQUEsWUFBQSxDQUFBLE9BQUEsRUFBQSxpQ0FBQSxDQUFBLEVBQUEsZUFBQSxDQUFBLEdBQUEsRUFBQSxDQUFBLFFBQUEsR0FBQSxLQUFBLEdBQUEsUUFBQSxDQUFBLGFBQUEsQ0FBQSxLQUFBLENBQUEsRUFBQSxLQUFBLENBQUEsWUFBQSxDQUFBLE9BQUEsRUFBQSw4QkFBQSxDQUFBLEVBQUEsZUFBQSxDQUFBLEtBQUEsRUFBQSxDQUFBLFVBQUEsR0FBQSxHQUFBLEdBQUEsUUFBQSxDQUFBLGFBQUEsQ0FBQSxLQUFBLENBQUEsRUFBQSxHQUFBLENBQUEsWUFBQSxDQUFBLE9BQUEsRUFBQSx5Q0FBQSxDQUFBLEVBQUEsZUFBQSxDQUFBLEdBQUEsRUFBQSxDQUFBLFdBQUEsR0FBQSxFQUFBLEdBQUEsUUFBQSxDQUFBLGFBQUEsQ0FBQSxJQUFBLENBQUEsRUFBQSxFQUFBLENBQUEsWUFBQSxDQUFBLE9BQUEsRUFBQSx5QkFBQSxDQUFBLEVBQUEsZUFBQSxDQUFBLEVBQUEsRUFBQSxDQU1pQixDQUFBLENBQUEsRUFBQSxJQUFBLENBQUEsT0FBRyxFQUFDLE9BQU8sQ0FBQyxDQUFBLENBQUEsRUFBQSxFQUFBLEdBQUEsV0FBQSxHQUFBLEdBQUEsR0FBQSxRQUFBLENBQUEsYUFBQSxDQUFBLEdBQUEsQ0FBQSxFQUFBLEdBQUEsQ0FBQSxZQUFBLENBQUEsT0FBQSxFQUFBLHlCQUFBLENBQUEsRUFBQSxlQUFBLENBQUEsR0FBQSxFQUFBLENBQUEsWUFBQSxFQUVoRCxDQUFBLENBQUEsRUFBQSxJQUFBLENBQUEsT0FBRyxFQUFDLFNBQVMsQ0FBQyxFQUFBLFdBQUEsQ0FBQSxDQUFBLEVBQUEsR0FBQSxHQUFBLFVBQUEsQ0FBQSxDQUFBLEVBQUEsR0FBQSxHQUFBLFVBQUEsR0FBQSxNQUFBLEdBQUEsUUFBQSxDQUFBLGFBQUEsQ0FBQSxLQUFBLENBQUEsRUFBQSxNQUFBLENBQUEsWUFBQSxDQUFBLE9BQUEsRUFBQSxvREFBQSxDQUFBLEVBQUEsZUFBQSxDQUFBLE1BQUEsRUFBQSxDQUFBLFdBQUEsR0FBQSxHQUFBLEdBQUEsUUFBQSxDQUFBLGFBQUEsQ0FBQSxLQUFBLENBQUEsRUFBQSxHQUFBLENBQUEsWUFBQSxDQUFBLEtBQUEsRUFBQSx1Q0FBQSxDQUFBLEVBQUEsR0FBQSxDQUFBLFlBQUEsQ0FBQSxLQUFBLEVBQUEsK0RBQUEsQ0FBQSxFQUFBLEdBQUEsQ0FBQSxZQUFBLENBQUEsT0FBQSxFQUFBLElBQUEsQ0FBQSxFQUFBLEdBQUEsR0FBQSxVQUFBLENBQUEsQ0FBQSxFQUFBLE1BQUEsR0FBQSxRQUFBLENBQUEsQ0FBQSxFQUFBLEtBQUEsR0FBQSxRQUFBLEdBQUEsR0FBQSxHQUFBLFFBQUEsQ0FBQSxhQUFBLENBQUEsR0FBQSxDQUFBLEVBQUEsR0FBQSxDQUFBLFlBQUEsQ0FBQSxPQUFBLEVBQUEscUJBQUEsQ0FBQSxFQUFBLGVBQUEsQ0FBQSxHQUFBLEVBQUEsQ0FBQSxLQUFBLEdBQUEsSUFBQSxHQUFBLFFBQUEsQ0FBQSxhQUFBLENBQUEsTUFBQSxDQUFBLEVBQUEsSUFBQSxDQUFBLFlBQUEsQ0FBQSxPQUFBLEVBQUEsS0FBQSxDQUFBLEVBQUEsZUFBQSxDQUFBLElBQUEsRUFBQSxDQU9vQyxDQUFBLENBQUEsRUFBQSxJQUFBLENBQUEsT0FBRyxFQUFDLFFBQVEsQ0FBQyxDQUFBLENBQUEsRUFBQSxJQUFBLEVBQUEsQ0FBQSxFQUFBLEdBQUEsR0FBQSxRQUFBLEdBQUEsR0FBQSxHQUFBLFFBQUEsQ0FBQSxhQUFBLENBQUEsTUFBQSxDQUFBLEVBQUEsR0FBQSxDQUFBLFlBQUEsQ0FBQSxPQUFBLEVBQUEsWUFBQSxDQUFBLEVBQUEsZUFBQSxDQUFBLEdBQUEsRUFBQSxDQUN4QyxDQUFBLENBQUEsRUFBQSxJQUFBLENBQUEsT0FBRyxFQUFDLFdBQVcsQ0FBQyxDQUFBLENBQUEsRUFBQSxHQUFBLEdBQUEsT0FBQSxDQUFBLENBQUEsRUFBQSxHQUFBLEdBQUEsTUFBQSxDQUFBLENBQUEsRUFBQSxHQUFBLEVBRzNDLENBQUE7QUN0QkY7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uKCl7XG4iLCJleHBvcnQgZGVmYXVsdCBmdW5jdGlvbiB3aGF0ZXZlciAoeHl6KSB7XG4gIHJldHVybiB4eXoudG9VcHBlckNhc2UoKVxufVxuIiwidmFyIHRyYWlsaW5nTmV3bGluZVJlZ2V4ID0gL1xcbltcXHNdKyQvXG52YXIgbGVhZGluZ05ld2xpbmVSZWdleCA9IC9eXFxuW1xcc10rL1xudmFyIHRyYWlsaW5nU3BhY2VSZWdleCA9IC9bXFxzXSskL1xudmFyIGxlYWRpbmdTcGFjZVJlZ2V4ID0gL15bXFxzXSsvXG52YXIgbXVsdGlTcGFjZVJlZ2V4ID0gL1tcXG5cXHNdKy9nXG5cbnZhciBURVhUX1RBR1MgPSBbXG4gICdhJywgJ2FiYnInLCAnYicsICdiZGknLCAnYmRvJywgJ2JyJywgJ2NpdGUnLCAnZGF0YScsICdkZm4nLCAnZW0nLCAnaScsXG4gICdrYmQnLCAnbWFyaycsICdxJywgJ3JwJywgJ3J0JywgJ3J0YycsICdydWJ5JywgJ3MnLCAnYW1wJywgJ3NtYWxsJywgJ3NwYW4nLFxuICAnc3Ryb25nJywgJ3N1YicsICdzdXAnLCAndGltZScsICd1JywgJ3ZhcicsICd3YnInXG5dXG5cbnZhciBWRVJCQVRJTV9UQUdTID0gW1xuICAnY29kZScsICdwcmUnLCAndGV4dGFyZWEnXG5dXG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gYXBwZW5kQ2hpbGQgKGVsLCBjaGlsZHMpIHtcbiAgaWYgKCFBcnJheS5pc0FycmF5KGNoaWxkcykpIHJldHVyblxuXG4gIHZhciBub2RlTmFtZSA9IGVsLm5vZGVOYW1lLnRvTG93ZXJDYXNlKClcblxuICB2YXIgaGFkVGV4dCA9IGZhbHNlXG4gIHZhciB2YWx1ZSwgbGVhZGVyXG5cbiAgZm9yICh2YXIgaSA9IDAsIGxlbiA9IGNoaWxkcy5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xuICAgIHZhciBub2RlID0gY2hpbGRzW2ldXG4gICAgaWYgKEFycmF5LmlzQXJyYXkobm9kZSkpIHtcbiAgICAgIGFwcGVuZENoaWxkKGVsLCBub2RlKVxuICAgICAgY29udGludWVcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIG5vZGUgPT09ICdudW1iZXInIHx8XG4gICAgICB0eXBlb2Ygbm9kZSA9PT0gJ2Jvb2xlYW4nIHx8XG4gICAgICB0eXBlb2Ygbm9kZSA9PT0gJ2Z1bmN0aW9uJyB8fFxuICAgICAgbm9kZSBpbnN0YW5jZW9mIERhdGUgfHxcbiAgICAgIG5vZGUgaW5zdGFuY2VvZiBSZWdFeHApIHtcbiAgICAgIG5vZGUgPSBub2RlLnRvU3RyaW5nKClcbiAgICB9XG5cbiAgICB2YXIgbGFzdENoaWxkID0gZWwuY2hpbGROb2Rlc1tlbC5jaGlsZE5vZGVzLmxlbmd0aCAtIDFdXG5cbiAgICAvLyBJdGVyYXRlIG92ZXIgdGV4dCBub2Rlc1xuICAgIGlmICh0eXBlb2Ygbm9kZSA9PT0gJ3N0cmluZycpIHtcbiAgICAgIGhhZFRleHQgPSB0cnVlXG5cbiAgICAgIC8vIElmIHdlIGFscmVhZHkgaGFkIHRleHQsIGFwcGVuZCB0byB0aGUgZXhpc3RpbmcgdGV4dFxuICAgICAgaWYgKGxhc3RDaGlsZCAmJiBsYXN0Q2hpbGQubm9kZU5hbWUgPT09ICcjdGV4dCcpIHtcbiAgICAgICAgbGFzdENoaWxkLm5vZGVWYWx1ZSArPSBub2RlXG5cbiAgICAgIC8vIFdlIGRpZG4ndCBoYXZlIGEgdGV4dCBub2RlIHlldCwgY3JlYXRlIG9uZVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbm9kZSA9IGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKG5vZGUpXG4gICAgICAgIGVsLmFwcGVuZENoaWxkKG5vZGUpXG4gICAgICAgIGxhc3RDaGlsZCA9IG5vZGVcbiAgICAgIH1cblxuICAgICAgLy8gSWYgdGhpcyBpcyB0aGUgbGFzdCBvZiB0aGUgY2hpbGQgbm9kZXMsIG1ha2Ugc3VyZSB3ZSBjbG9zZSBpdCBvdXRcbiAgICAgIC8vIHJpZ2h0XG4gICAgICBpZiAoaSA9PT0gbGVuIC0gMSkge1xuICAgICAgICBoYWRUZXh0ID0gZmFsc2VcbiAgICAgICAgLy8gVHJpbSB0aGUgY2hpbGQgdGV4dCBub2RlcyBpZiB0aGUgY3VycmVudCBub2RlIGlzbid0IGFcbiAgICAgICAgLy8gbm9kZSB3aGVyZSB3aGl0ZXNwYWNlIG1hdHRlcnMuXG4gICAgICAgIGlmIChURVhUX1RBR1MuaW5kZXhPZihub2RlTmFtZSkgPT09IC0xICYmXG4gICAgICAgICAgVkVSQkFUSU1fVEFHUy5pbmRleE9mKG5vZGVOYW1lKSA9PT0gLTEpIHtcbiAgICAgICAgICB2YWx1ZSA9IGxhc3RDaGlsZC5ub2RlVmFsdWVcbiAgICAgICAgICAgIC5yZXBsYWNlKGxlYWRpbmdOZXdsaW5lUmVnZXgsICcnKVxuICAgICAgICAgICAgLnJlcGxhY2UodHJhaWxpbmdTcGFjZVJlZ2V4LCAnJylcbiAgICAgICAgICAgIC5yZXBsYWNlKHRyYWlsaW5nTmV3bGluZVJlZ2V4LCAnJylcbiAgICAgICAgICAgIC5yZXBsYWNlKG11bHRpU3BhY2VSZWdleCwgJyAnKVxuICAgICAgICAgIGlmICh2YWx1ZSA9PT0gJycpIHtcbiAgICAgICAgICAgIGVsLnJlbW92ZUNoaWxkKGxhc3RDaGlsZClcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgbGFzdENoaWxkLm5vZGVWYWx1ZSA9IHZhbHVlXG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKFZFUkJBVElNX1RBR1MuaW5kZXhPZihub2RlTmFtZSkgPT09IC0xKSB7XG4gICAgICAgICAgLy8gVGhlIHZlcnkgZmlyc3Qgbm9kZSBpbiB0aGUgbGlzdCBzaG91bGQgbm90IGhhdmUgbGVhZGluZ1xuICAgICAgICAgIC8vIHdoaXRlc3BhY2UuIFNpYmxpbmcgdGV4dCBub2RlcyBzaG91bGQgaGF2ZSB3aGl0ZXNwYWNlIGlmIHRoZXJlXG4gICAgICAgICAgLy8gd2FzIGFueS5cbiAgICAgICAgICBsZWFkZXIgPSBpID09PSAwID8gJycgOiAnICdcbiAgICAgICAgICB2YWx1ZSA9IGxhc3RDaGlsZC5ub2RlVmFsdWVcbiAgICAgICAgICAgIC5yZXBsYWNlKGxlYWRpbmdOZXdsaW5lUmVnZXgsIGxlYWRlcilcbiAgICAgICAgICAgIC5yZXBsYWNlKGxlYWRpbmdTcGFjZVJlZ2V4LCAnICcpXG4gICAgICAgICAgICAucmVwbGFjZSh0cmFpbGluZ1NwYWNlUmVnZXgsICcnKVxuICAgICAgICAgICAgLnJlcGxhY2UodHJhaWxpbmdOZXdsaW5lUmVnZXgsICcnKVxuICAgICAgICAgICAgLnJlcGxhY2UobXVsdGlTcGFjZVJlZ2V4LCAnICcpXG4gICAgICAgICAgbGFzdENoaWxkLm5vZGVWYWx1ZSA9IHZhbHVlXG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgIC8vIEl0ZXJhdGUgb3ZlciBET00gbm9kZXNcbiAgICB9IGVsc2UgaWYgKG5vZGUgJiYgbm9kZS5ub2RlVHlwZSkge1xuICAgICAgLy8gSWYgdGhlIGxhc3Qgbm9kZSB3YXMgYSB0ZXh0IG5vZGUsIG1ha2Ugc3VyZSBpdCBpcyBwcm9wZXJseSBjbG9zZWQgb3V0XG4gICAgICBpZiAoaGFkVGV4dCkge1xuICAgICAgICBoYWRUZXh0ID0gZmFsc2VcblxuICAgICAgICAvLyBUcmltIHRoZSBjaGlsZCB0ZXh0IG5vZGVzIGlmIHRoZSBjdXJyZW50IG5vZGUgaXNuJ3QgYVxuICAgICAgICAvLyB0ZXh0IG5vZGUgb3IgYSBjb2RlIG5vZGVcbiAgICAgICAgaWYgKFRFWFRfVEFHUy5pbmRleE9mKG5vZGVOYW1lKSA9PT0gLTEgJiZcbiAgICAgICAgICBWRVJCQVRJTV9UQUdTLmluZGV4T2Yobm9kZU5hbWUpID09PSAtMSkge1xuICAgICAgICAgIHZhbHVlID0gbGFzdENoaWxkLm5vZGVWYWx1ZVxuICAgICAgICAgICAgLnJlcGxhY2UobGVhZGluZ05ld2xpbmVSZWdleCwgJycpXG4gICAgICAgICAgICAucmVwbGFjZSh0cmFpbGluZ05ld2xpbmVSZWdleCwgJycpXG4gICAgICAgICAgICAucmVwbGFjZShtdWx0aVNwYWNlUmVnZXgsICcgJylcblxuICAgICAgICAgIC8vIFJlbW92ZSBlbXB0eSB0ZXh0IG5vZGVzLCBhcHBlbmQgb3RoZXJ3aXNlXG4gICAgICAgICAgaWYgKHZhbHVlID09PSAnJykge1xuICAgICAgICAgICAgZWwucmVtb3ZlQ2hpbGQobGFzdENoaWxkKVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBsYXN0Q2hpbGQubm9kZVZhbHVlID0gdmFsdWVcbiAgICAgICAgICB9XG4gICAgICAgIC8vIFRyaW0gdGhlIGNoaWxkIG5vZGVzIGlmIHRoZSBjdXJyZW50IG5vZGUgaXMgbm90IGEgbm9kZVxuICAgICAgICAvLyB3aGVyZSBhbGwgd2hpdGVzcGFjZSBtdXN0IGJlIHByZXNlcnZlZFxuICAgICAgICB9IGVsc2UgaWYgKFZFUkJBVElNX1RBR1MuaW5kZXhPZihub2RlTmFtZSkgPT09IC0xKSB7XG4gICAgICAgICAgdmFsdWUgPSBsYXN0Q2hpbGQubm9kZVZhbHVlXG4gICAgICAgICAgICAucmVwbGFjZShsZWFkaW5nU3BhY2VSZWdleCwgJyAnKVxuICAgICAgICAgICAgLnJlcGxhY2UobGVhZGluZ05ld2xpbmVSZWdleCwgJycpXG4gICAgICAgICAgICAucmVwbGFjZSh0cmFpbGluZ05ld2xpbmVSZWdleCwgJycpXG4gICAgICAgICAgICAucmVwbGFjZShtdWx0aVNwYWNlUmVnZXgsICcgJylcbiAgICAgICAgICBsYXN0Q2hpbGQubm9kZVZhbHVlID0gdmFsdWVcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBTdG9yZSB0aGUgbGFzdCBub2RlbmFtZVxuICAgICAgdmFyIF9ub2RlTmFtZSA9IG5vZGUubm9kZU5hbWVcbiAgICAgIGlmIChfbm9kZU5hbWUpIG5vZGVOYW1lID0gX25vZGVOYW1lLnRvTG93ZXJDYXNlKClcblxuICAgICAgLy8gQXBwZW5kIHRoZSBub2RlIHRvIHRoZSBET01cbiAgICAgIGVsLmFwcGVuZENoaWxkKG5vZGUpXG4gICAgfVxuICB9XG59XG4iLCJpbXBvcnQgZGVwIGZyb20gXCIuL2RlcFwiXG5pbXBvcnQgaHRtbCBmcm9tICdiZWwnXG5cbmRvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQoaHRtbGBcbiAgPHNlY3Rpb24gY2xhc3M9XCJtdzcgY2VudGVyXCI+XG5cdCA8aDIgY2xhc3M9XCJhdGhlbGFzIHBoMyBwaDAtbFwiPk5ld3M8L2gyPlxuXHQgPGFydGljbGUgY2xhc3M9XCJwdjQgYnQgYmIgYi0tYmxhY2stMTAgcGgzIHBoMC1sXCI+XG5cdFx0PGRpdiBjbGFzcz1cImZsZXggZmxleC1jb2x1bW4gZmxleC1yb3ctbnNcIj5cblx0XHQgIDxkaXYgY2xhc3M9XCJ3LTEwMCB3LTYwLW5zIHByMy1ucyBvcmRlci0yIG9yZGVyLTEtbnNcIj5cblx0XHRcdCA8aDEgY2xhc3M9XCJmMyBhdGhlbGFzIG10MCBsaC10aXRsZVwiPiR7ZGVwKCd0aXRsZScpfTwvaDE+XG5cdFx0XHQgPHAgY2xhc3M9XCJmNSBmNC1sIGxoLWNvcHkgYXRoZWxhc1wiPlxuXHRcdFx0XHQke2RlcCgnZXhjZXJwdCcpfVxuXHRcdFx0IDwvcD5cblx0XHQgIDwvZGl2PlxuXHRcdCAgPGRpdiBjbGFzcz1cInBsMy1ucyBvcmRlci0xIG9yZGVyLTItbnMgbWI0IG1iMC1ucyB3LTEwMCB3LTQwLW5zXCI+XG5cdFx0XHQgPGltZyBzcmM9XCJodHRwOi8vbXJtcnMuZ2l0aHViLmlvL3Bob3Rvcy9jcHUuanBnXCIgY2xhc3M9XCJkYlwiIGFsdD1cIlBob3RvIG9mIGEgZGltbHkgbGl0IHJvb20gd2l0aCBhIGNvbXB1dGVyIGludGVyZmFjZSB0ZXJtaW5hbC5cIj5cblx0XHQgIDwvZGl2PlxuXHRcdDwvZGl2PlxuXHRcdDxwIGNsYXNzPVwiZjYgbGgtY29weSBncmF5IG12MFwiPkJ5IDxzcGFuIGNsYXNzPVwidHR1XCI+JHtkZXAoJ2F1dGhvcicpfTwvc3Bhbj48L3A+XG5cdFx0PHRpbWUgY2xhc3M9XCJmNiBkYiBncmF5XCI+JHtkZXAoJ3RpbWVzdGFtcCcpfTwvdGltZT5cblx0IDwvYXJ0aWNsZT5cbiAgPC9zZWN0aW9uPlxuYClcbiIsIlxufSgpKTsiXX0= 166 | -------------------------------------------------------------------------------- /test/input-source-map/options.json: -------------------------------------------------------------------------------- 1 | { 2 | "debug": true, 3 | "preludePath": "node_modules/browserify/_prelude.js", 4 | "transform": "babelify" 5 | } 6 | -------------------------------------------------------------------------------- /test/lazy-cycles/a.js: -------------------------------------------------------------------------------- 1 | var b = require('./b') 2 | module.exports = function () { 3 | return b() 4 | } 5 | -------------------------------------------------------------------------------- /test/lazy-cycles/app.js: -------------------------------------------------------------------------------- 1 | console.log( 2 | require('./a')() 3 | ) 4 | -------------------------------------------------------------------------------- /test/lazy-cycles/b.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | return require('./a').toString() 3 | } 4 | -------------------------------------------------------------------------------- /test/lazy-cycles/expected.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | var createModuleFactory = function createModuleFactory(t){var e;return function(r){return e||t(e={exports:{},parent:r},e.exports),e.exports}}; 3 | var _$a_1 = createModuleFactory(function (module, exports) { 4 | var b = _$b_3({}) 5 | module.exports = function () { 6 | return b() 7 | } 8 | 9 | }); 10 | var _$b_3 = createModuleFactory(function (module, exports) { 11 | module.exports = function () { 12 | return _$a_1({}).toString() 13 | } 14 | 15 | }); 16 | var _$app_2 = {}; 17 | console.log( 18 | _$a_1({})() 19 | ) 20 | 21 | }()); 22 | -------------------------------------------------------------------------------- /test/lazy-expose/a.js: -------------------------------------------------------------------------------- 1 | var b = require('./b') 2 | module.exports = function () { 3 | return b() 4 | } 5 | -------------------------------------------------------------------------------- /test/lazy-expose/app.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./a')() 2 | -------------------------------------------------------------------------------- /test/lazy-expose/b.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | return require('./a').toString() 3 | } 4 | -------------------------------------------------------------------------------- /test/lazy-order/a.js: -------------------------------------------------------------------------------- 1 | console.log('always') 2 | -------------------------------------------------------------------------------- /test/lazy-order/app.js: -------------------------------------------------------------------------------- 1 | require('./a') 2 | global.later = function () { 3 | require('./b') // should not run immediately 4 | } 5 | if (require('./d')>0.5) { 6 | require('./c') // should not always run 7 | } 8 | -------------------------------------------------------------------------------- /test/lazy-order/b.js: -------------------------------------------------------------------------------- 1 | console.log('later') 2 | -------------------------------------------------------------------------------- /test/lazy-order/c.js: -------------------------------------------------------------------------------- 1 | console.log('conditionally') 2 | -------------------------------------------------------------------------------- /test/lazy-order/d.js: -------------------------------------------------------------------------------- 1 | module.exports = Math.random() 2 | -------------------------------------------------------------------------------- /test/lazy-order/expected.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | var createModuleFactory = function createModuleFactory(t){var e;return function(r){return e||t(e={exports:{},parent:r},e.exports),e.exports}}; 3 | var _$c_4 = createModuleFactory(function (module, exports) { 4 | console.log('conditionally') 5 | 6 | }); 7 | var _$b_3 = createModuleFactory(function (module, exports) { 8 | console.log('later') 9 | 10 | }); 11 | var _$a_1 = {}; 12 | console.log('always') 13 | 14 | var _$d_5 = Math.random() 15 | 16 | var _$app_2 = {}; 17 | (function (global){(function (){ 18 | _$a_1 19 | global.later = function () { 20 | _$b_3({}) // should not run immediately 21 | } 22 | if (_$d_5>0.5) { 23 | _$c_4({}) // should not always run 24 | } 25 | 26 | }).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 27 | }()); 28 | -------------------------------------------------------------------------------- /test/module-parent/app.js: -------------------------------------------------------------------------------- 1 | require('./child') 2 | 3 | if (module.parent) { 4 | throw Error('should be entry point') 5 | } 6 | -------------------------------------------------------------------------------- /test/module-parent/child.js: -------------------------------------------------------------------------------- 1 | if (module.parent) { 2 | module.exports = 'required' 3 | } else { 4 | module.exports = 'entry point' 5 | } 6 | -------------------------------------------------------------------------------- /test/module-parent/expected.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | var _$child_2 = { exports: {} }; 3 | if (({})) { 4 | _$child_2.exports = 'required' 5 | } else { 6 | _$child_2.exports = 'entry point' 7 | } 8 | 9 | _$child_2 = _$child_2.exports 10 | var _$app_1 = { exports: {} }; 11 | _$child_2 12 | 13 | if (null) { 14 | throw Error('should be entry point') 15 | } 16 | 17 | _$app_1 = _$app_1.exports 18 | }()); 19 | -------------------------------------------------------------------------------- /test/order.js: -------------------------------------------------------------------------------- 1 | var test = require('tape') 2 | var vm = require('vm') 3 | var concat = require('concat-stream') 4 | var pack = require('../') 5 | 6 | test('should evaluate entry modules by their `.order` property', function (t) { 7 | t.plan(1) 8 | var p = pack({ raw: true }) 9 | 10 | p.pipe(concat(onbundle)) 11 | 12 | p.write({ 13 | id: 4, index: 4, 14 | deps: {}, 15 | source: 'module.exports="hello"' 16 | }) 17 | p.write({ 18 | id: 0, index: 0, 19 | entry: true, 20 | order: 1, 21 | deps: {}, 22 | source: 'console.log(1)' 23 | }) 24 | p.write({ 25 | id: 2, index: 2, 26 | entry: true, 27 | order: 2, 28 | deps: {}, 29 | source: 'console.log(2)' 30 | }) 31 | p.write({ 32 | id: 1, index: 3, 33 | entry: true, 34 | order: 0, 35 | deps: { x: 4 }, 36 | source: 'console.log(require("x"))' 37 | }) 38 | p.end() 39 | 40 | function onbundle (code) { 41 | var result = [] 42 | vm.runInNewContext(code, { 43 | console: { 44 | log: function (text) { result.push(text) } 45 | } 46 | }) 47 | t.equal(result.join('\n'), 'hello\n1\n2') 48 | } 49 | }) 50 | -------------------------------------------------------------------------------- /test/parent-cycle/app.js: -------------------------------------------------------------------------------- 1 | exports.a = 1 2 | exports.b = 2 3 | 4 | require('./router') 5 | 6 | if (!module.parent) { 7 | console.log(exports.a + exports.b) 8 | } 9 | -------------------------------------------------------------------------------- /test/parent-cycle/router.js: -------------------------------------------------------------------------------- 1 | if (module.parent) { 2 | require('./app').a = 3 3 | } 4 | -------------------------------------------------------------------------------- /test/plugin.js: -------------------------------------------------------------------------------- 1 | var test = require('tape') 2 | var through = require('through2') 3 | var fromString = require('from2-string') 4 | var browserify = require('browserify') 5 | var packFlat = require('../plugin') 6 | 7 | test('plugin should replace browser-pack', function (t) { 8 | t.plan(1) 9 | 10 | var input = fromString('module.exports = "whatever"') 11 | var b = browserify(input) 12 | // Add some streams around the browser-pack stream 13 | b.pipeline.get('pack').unshift(through.obj()) 14 | b.pipeline.get('pack').push(through.obj()) 15 | 16 | b.plugin(packFlat) 17 | b.bundle(onbundle) 18 | 19 | function onbundle (err) { 20 | t.ifError(err) 21 | } 22 | }) 23 | -------------------------------------------------------------------------------- /test/remove-decl/a.js: -------------------------------------------------------------------------------- 1 | module.exports = function test_module_please_ignore () { 2 | } 3 | -------------------------------------------------------------------------------- /test/remove-decl/app.js: -------------------------------------------------------------------------------- 1 | var a = require('./a') 2 | const __dummy = 'whatever' 3 | var b, c = require('./a') 4 | let d; const e = require('./a') 5 | const f = require('./a'), g = null 6 | 7 | c(a(f)) 8 | -------------------------------------------------------------------------------- /test/remove-decl/expected.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | var _$test_module_please_ignore_1 = function test_module_please_ignore () { 3 | } 4 | 5 | var _$app_2 = {}; 6 | /* removed: var _$test_module_please_ignore_1 = require('./a') */; 7 | const __dummy = 'whatever' 8 | var b 9 | let d; /* removed: const _$test_module_please_ignore_1 = require('./a') */; 10 | const g = null 11 | 12 | _$test_module_please_ignore_1(_$test_module_please_ignore_1(_$test_module_please_ignore_1)) 13 | 14 | }()); 15 | -------------------------------------------------------------------------------- /test/self.js: -------------------------------------------------------------------------------- 1 | var test = require('tape') 2 | var fs = require('fs') 3 | var path = require('path') 4 | var assert = require('assert') 5 | var browserify = require('browserify') 6 | var through = require('through2') 7 | var unpack = require('browser-unpack') 8 | 9 | function unpackStream () { 10 | var d = '' 11 | return through({ objectMode: true }, function (chunk, enc, cb) { 12 | d += chunk 13 | cb() 14 | }, function (cb) { 15 | unpack(d).forEach(this.push, this) 16 | cb(null) 17 | }) 18 | } 19 | 20 | function runBundleUnpack (packer) { 21 | var b = browserify({ 22 | entries: path.join(__dirname, '../index'), 23 | node: true, 24 | transform: 'brfs' 25 | }) 26 | 27 | return b.bundle() 28 | .pipe(unpackStream()) 29 | .pipe(packer({ raw: true, standalone: 'packFlat' })) 30 | } 31 | 32 | function runBundlePlugin (packer) { 33 | var b = browserify({ 34 | entries: path.join(__dirname, '../plugin'), 35 | node: true, 36 | standalone: 'packFlat', 37 | transform: 'brfs' 38 | }) 39 | b.plugin(packer) 40 | 41 | return b.bundle() 42 | } 43 | 44 | test('bundling itself with itself: plugin edition', function (t) { 45 | t.plan(1) 46 | runBundlePlugin(require('../plugin')) 47 | .pipe(fs.createWriteStream(path.join(__dirname, './self.plugin.expected.js'))) 48 | .on('finish', onbundle) 49 | 50 | function onbundle () { 51 | runBundlePlugin(require('./self.plugin.expected')) 52 | .pipe(fs.createWriteStream(path.join(__dirname, './self.plugin.actual.js'))) 53 | .on('finish', oncompare) 54 | } 55 | 56 | function oncompare () { 57 | t.is( 58 | fs.readFileSync(path.join(__dirname, './self.plugin.expected.js'), 'utf8'), 59 | fs.readFileSync(path.join(__dirname, './self.plugin.actual.js'), 'utf8'), 60 | 'flattened browserified code should have the same output as the commonjs version' 61 | ) 62 | t.end() 63 | } 64 | }) 65 | 66 | test('bundling itself with itself: repack edition', function (t) { 67 | t.plan(1) 68 | runBundleUnpack(require('../index')) 69 | .pipe(fs.createWriteStream(path.join(__dirname, './self.unpack.expected.js'))) 70 | .on('finish', onbundle) 71 | 72 | function onbundle () { 73 | runBundleUnpack(require('./self.unpack.expected')) 74 | .pipe(fs.createWriteStream(path.join(__dirname, './self.unpack.actual.js'))) 75 | .on('finish', oncompare) 76 | } 77 | 78 | function oncompare () { 79 | t.is( 80 | fs.readFileSync(path.join(__dirname, './self.unpack.expected.js'), 'utf8'), 81 | fs.readFileSync(path.join(__dirname, './self.unpack.actual.js'), 'utf8'), 82 | 'flattened browserified code should have the same output as the commonjs version' 83 | ) 84 | t.end() 85 | } 86 | }) 87 | -------------------------------------------------------------------------------- /test/set-exports/app.js: -------------------------------------------------------------------------------- 1 | exports.moduleExports = require('./module-exports') 2 | exports.both = require('./both') 3 | exports.exportsOnly = require('./exports-only') 4 | exports.quoted = require('./quoted') 5 | exports.free = require('./free-module') 6 | -------------------------------------------------------------------------------- /test/set-exports/both.js: -------------------------------------------------------------------------------- 1 | module.exports = exports = 2 2 | -------------------------------------------------------------------------------- /test/set-exports/expected.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | var _$moduleExports_5 = 1 3 | 4 | var _$both_2 = {}; 5 | _$both_2 = _$both_2 = 2 6 | 7 | var _$exportsOnly_3 = {}; 8 | _$exportsOnly_3 = 3 9 | 10 | var _$quoted_6 = 4 11 | 12 | var _$freeModule_4 = { exports: {} }; 13 | var something = function () { 14 | return _$freeModule_4 15 | } 16 | something().exports = 5 17 | 18 | _$freeModule_4 = _$freeModule_4.exports 19 | var _$app_1 = {}; 20 | _$app_1.moduleExports = _$moduleExports_5 21 | _$app_1.both = _$both_2 22 | _$app_1.exportsOnly = _$exportsOnly_3 23 | _$app_1.quoted = _$quoted_6 24 | _$app_1.free = _$freeModule_4 25 | 26 | }()); 27 | -------------------------------------------------------------------------------- /test/set-exports/exports-only.js: -------------------------------------------------------------------------------- 1 | exports = 3 2 | -------------------------------------------------------------------------------- /test/set-exports/free-module.js: -------------------------------------------------------------------------------- 1 | var something = function () { 2 | return module 3 | } 4 | something().exports = 5 5 | -------------------------------------------------------------------------------- /test/set-exports/module-exports.js: -------------------------------------------------------------------------------- 1 | module.exports = 1 2 | -------------------------------------------------------------------------------- /test/set-exports/quoted.js: -------------------------------------------------------------------------------- 1 | module["exports"] = 4 2 | -------------------------------------------------------------------------------- /test/shorthand/app.js: -------------------------------------------------------------------------------- 1 | var globalVar = 0 2 | var importedModule = require('./importedModule') 3 | 4 | function setExports (argument) { 5 | var localVar = 1 6 | module.exports = { 7 | globalVar, 8 | importedModule, 9 | localVar, 10 | argument 11 | } 12 | } 13 | 14 | setExports(10) 15 | -------------------------------------------------------------------------------- /test/shorthand/expected.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | var globalVar = 1 3 | 4 | var _$globalVar_2 = globalVar 5 | 6 | var _$app_1 = {}; 7 | var __globalVar_1 = 0 8 | /* removed: var _$globalVar_2 = require('./importedModule') */; 9 | 10 | function setExports (argument) { 11 | var localVar = 1 12 | _$app_1 = { 13 | globalVar: __globalVar_1, 14 | importedModule: _$globalVar_2, 15 | localVar, 16 | argument 17 | } 18 | } 19 | 20 | setExports(10) 21 | 22 | }()); 23 | -------------------------------------------------------------------------------- /test/shorthand/importedModule.js: -------------------------------------------------------------------------------- 1 | var globalVar = 1 2 | 3 | module.exports = globalVar 4 | -------------------------------------------------------------------------------- /test/simplify/app.js: -------------------------------------------------------------------------------- 1 | var hello = require('./hello') 2 | var world = require('./world' /* comment */) 3 | 4 | require('./asi'), console.log(hello, world) 5 | -------------------------------------------------------------------------------- /test/simplify/asi.js: -------------------------------------------------------------------------------- 1 | // If the `test` import is removed naively, the result will be alert(test), which is incorrect. 2 | alert 3 | var test = require('./hello'); 4 | (test) 5 | -------------------------------------------------------------------------------- /test/simplify/expected.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | var _$hello_3 = 'hello' 3 | 4 | var _$world_4 = {}; 5 | var world = _$world_4 = 'world' 6 | 7 | var _$asi_2 = {}; 8 | // If the `test` import is removed naively, the result will be alert(test), which is incorrect. 9 | alert 10 | /* removed: var _$hello_3 = require('./hello'); */; 11 | (_$hello_3) 12 | 13 | var _$app_1 = {}; 14 | /* removed: var _$hello_3 = require('./hello') */; 15 | /* removed: var _$world_4 = require('./world' /* comment *\/) */; 16 | 17 | _$asi_2, console.log(_$hello_3, _$world_4) 18 | 19 | }()); 20 | -------------------------------------------------------------------------------- /test/simplify/hello.js: -------------------------------------------------------------------------------- 1 | module.exports = 'hello' 2 | -------------------------------------------------------------------------------- /test/simplify/world.js: -------------------------------------------------------------------------------- 1 | var world = module.exports = 'world' 2 | -------------------------------------------------------------------------------- /test/source-map/app.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./b') 2 | -------------------------------------------------------------------------------- /test/source-map/b.js: -------------------------------------------------------------------------------- 1 | module.exports = 10 2 | -------------------------------------------------------------------------------- /test/source-map/expected.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | var _$b_2 = 10 3 | 4 | var _$app_1 = _$b_2 5 | 6 | }()); 7 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIl9wcmVsdWRlIiwidGVzdC9zb3VyY2UtbWFwL2IuanMiLCJ0ZXN0L3NvdXJjZS1tYXAvYXBwLmpzIiwiX3Bvc3RsdWRlIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FBQ0EsQUNEQSxTQUFjLEdBQUcsRUFBRTs7QUNBbkIsV0FBYyxHQUFHLEtBQWM7QUNBL0I7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uKCl7XG4iLCJtb2R1bGUuZXhwb3J0cyA9IDEwXG4iLCJtb2R1bGUuZXhwb3J0cyA9IHJlcXVpcmUoJy4vYicpXG4iLCJcbn0oKSk7Il19 8 | -------------------------------------------------------------------------------- /test/source-map/options.json: -------------------------------------------------------------------------------- 1 | { 2 | "debug": true, 3 | "preludePath": "node_modules/browserify/_prelude.js" 4 | } 5 | -------------------------------------------------------------------------------- /test/standalone/a.js: -------------------------------------------------------------------------------- 1 | module.exports = function a() { 2 | return 'A' 3 | } 4 | -------------------------------------------------------------------------------- /test/standalone/app.js: -------------------------------------------------------------------------------- 1 | exports.a = require('./a') 2 | exports.b = require('./b') 3 | -------------------------------------------------------------------------------- /test/standalone/b.js: -------------------------------------------------------------------------------- 1 | module.exports = function b() { 2 | return 'B' 3 | } 4 | -------------------------------------------------------------------------------- /test/standalone/expected.js: -------------------------------------------------------------------------------- 1 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.modulename = f()}})(function(){var define,module,exports; 2 | var _$a_1 = function a() { 3 | return 'A' 4 | } 5 | 6 | var _$b_3 = function b() { 7 | return 'B' 8 | } 9 | 10 | var _$app_2 = {}; 11 | _$app_2.a = _$a_1 12 | _$app_2.b = _$b_3 13 | 14 | return _$app_2; 15 | 16 | }); 17 | 18 | -------------------------------------------------------------------------------- /test/standalone/options.json: -------------------------------------------------------------------------------- 1 | { "standalone": "modulename" } 2 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | var test = require('tape') 2 | var vm = require('vm') 3 | var fs = require('fs') 4 | var path = require('path') 5 | var browserify = require('browserify') 6 | var concat = require('concat-stream') 7 | var pack = require('../plugin') 8 | 9 | var tests = [ 10 | 'bare-module', 11 | 'colliding-unused', 12 | 'comment', 13 | 'dedupe', 14 | 'dep-order', 15 | 'destructure', 16 | 'dynamic-require', 17 | 'eager-cycles', 18 | 'exports-name', 19 | 'globals', 20 | 'input-source-map', 21 | 'lazy-cycles', 22 | 'lazy-order', 23 | 'module-parent', 24 | 'remove-decl', 25 | 'set-exports', 26 | 'shorthand', 27 | 'simplify', 28 | 'source-map', 29 | 'standalone', 30 | 'typeof-require', 31 | 'variable' 32 | ] 33 | 34 | tests.forEach(function (name) { 35 | test(name, { skip: /^v4/.test(process.version) && name === 'input-source-map' }, function (t) { 36 | runTest(t, name) 37 | }) 38 | }) 39 | 40 | function runTest (t, name) { 41 | t.plan(1) 42 | var basedir = path.join(__dirname, name) 43 | var optionsPath = path.join(basedir, 'options.json') 44 | var options = {} 45 | try { options = JSON.parse(fs.readFileSync(optionsPath, 'utf8')) } catch (err) {} 46 | var entry = path.join(basedir, 'app.js') 47 | var expected = path.join(basedir, 'expected.js') 48 | var actual = path.join(basedir, 'actual.js') 49 | options.entries = entry 50 | var bundle = browserify(options) 51 | .plugin(pack) 52 | .bundle() 53 | .on('error', t.fail) 54 | 55 | // Write actual output to a file for easier inspection 56 | bundle.pipe(fs.createWriteStream(actual)) 57 | 58 | bundle.pipe(concat(function (result) { 59 | t.is( 60 | result.toString('utf8'), 61 | fs.readFileSync(expected, 'utf8'), 62 | name 63 | ) 64 | t.end() 65 | })) 66 | } 67 | 68 | test('parent-cycle', function (t) { 69 | t.plan(2) 70 | 71 | var basedir = path.join(__dirname, 'parent-cycle') 72 | var entry = path.join(basedir, 'app.js') 73 | var actual = path.join(basedir, 'actual.js') 74 | 75 | browserify(entry) 76 | .plugin(pack) 77 | .bundle(function (err, result) { 78 | t.ifError(err) 79 | fs.writeFileSync(actual, result) 80 | vm.runInNewContext(result + '', { 81 | console: { log: log } 82 | }) 83 | function log (value) { 84 | t.equal(value, 5) 85 | } 86 | }) 87 | }) 88 | -------------------------------------------------------------------------------- /test/typeof-require/app.js: -------------------------------------------------------------------------------- 1 | if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') { 2 | console.log('should do this') 3 | module.exports = factory() 4 | } else { 5 | console.log('should not do this') 6 | this.Standalone = factory() 7 | } 8 | 9 | function factory () { 10 | return { value: 10 } 11 | } 12 | -------------------------------------------------------------------------------- /test/typeof-require/expected.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | var _$app_1 = { exports: {} }; 3 | if ("function" === 'function' && typeof _$app_1.exports === 'object' && "object" === 'object') { 4 | console.log('should do this') 5 | _$app_1.exports = factory() 6 | } else { 7 | console.log('should not do this') 8 | this.Standalone = factory() 9 | } 10 | 11 | function factory () { 12 | return { value: 10 } 13 | } 14 | 15 | _$app_1 = _$app_1.exports 16 | }()); 17 | -------------------------------------------------------------------------------- /test/variable/app.js: -------------------------------------------------------------------------------- 1 | exports.param = require('./param') 2 | exports.something = function () { 3 | var exports = {} 4 | exports.something = require('./param') 5 | return exports 6 | } 7 | -------------------------------------------------------------------------------- /test/variable/expected.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | var _$param_2 = function (module) { 3 | return { exports: module } 4 | } 5 | 6 | var _$app_1 = {}; 7 | _$app_1.param = _$param_2 8 | _$app_1.something = function () { 9 | var exports = {} 10 | exports.something = _$param_2 11 | return exports 12 | } 13 | 14 | }()); 15 | -------------------------------------------------------------------------------- /test/variable/param.js: -------------------------------------------------------------------------------- 1 | module.exports = function (module) { 2 | return { exports: module } 3 | } 4 | --------------------------------------------------------------------------------