@@ -363,9 +363,12 @@ var _12 = function($window) {
363
363
}
364
364
vnode3 . dom = temp . firstChild
365
365
vnode3 . domSize = temp . childNodes . length
366
+ // Capture nodes to remove, so we don't confuse them.
367
+ vnode3 . instance = [ ]
366
368
var fragment = $doc . createDocumentFragment ( )
367
369
var child
368
370
while ( child = temp . firstChild ) {
371
+ vnode3 . instance . push ( child )
369
372
fragment . appendChild ( child )
370
373
}
371
374
insertNode ( parent , fragment , nextSibling )
@@ -538,7 +541,7 @@ var _12 = function($window) {
538
541
function updateNodes ( parent , old , vnodes , hooks , nextSibling , ns ) {
539
542
if ( old === vnodes || old == null && vnodes == null ) return
540
543
else if ( old == null || old . length === 0 ) createNodes ( parent , vnodes , 0 , vnodes . length , hooks , nextSibling , ns )
541
- else if ( vnodes == null || vnodes . length === 0 ) removeNodes ( old , 0 , old . length )
544
+ else if ( vnodes == null || vnodes . length === 0 ) removeNodes ( parent , old , 0 , old . length )
542
545
else {
543
546
var isOldKeyed = old [ 0 ] != null && old [ 0 ] . key != null
544
547
var isKeyed0 = vnodes [ 0 ] != null && vnodes [ 0 ] . key != null
@@ -547,7 +550,7 @@ var _12 = function($window) {
547
550
if ( ! isKeyed0 ) while ( start < vnodes . length && vnodes [ start ] == null ) start ++
548
551
if ( isKeyed0 === null && isOldKeyed == null ) return // both lists are full of nulls
549
552
if ( isOldKeyed !== isKeyed0 ) {
550
- removeNodes ( old , oldStart , old . length )
553
+ removeNodes ( parent , old , oldStart , old . length )
551
554
createNodes ( parent , vnodes , start , vnodes . length , hooks , nextSibling , ns )
552
555
} else if ( ! isKeyed0 ) {
553
556
// Don't index past the end of either list (causes deopts).
@@ -561,10 +564,10 @@ var _12 = function($window) {
561
564
v = vnodes [ start ]
562
565
if ( o === v || o == null && v == null ) continue
563
566
else if ( o == null ) createNode ( parent , v , hooks , ns , getNextSibling ( old , start + 1 , nextSibling ) )
564
- else if ( v == null ) removeNode ( o )
567
+ else if ( v == null ) removeNode ( parent , o )
565
568
else updateNode ( parent , o , v , hooks , getNextSibling ( old , start + 1 , nextSibling ) , ns )
566
569
}
567
- if ( old . length > commonLength ) removeNodes ( old , start , old . length )
570
+ if ( old . length > commonLength ) removeNodes ( parent , old , start , old . length )
568
571
if ( vnodes . length > commonLength ) createNodes ( parent , vnodes , start , vnodes . length , hooks , nextSibling , ns )
569
572
} else {
570
573
// keyed diff
@@ -591,9 +594,9 @@ var _12 = function($window) {
591
594
if ( start === end ) break
592
595
if ( o . key !== ve . key || oe . key !== v . key ) break
593
596
topSibling = getNextSibling ( old , oldStart , nextSibling )
594
- insertNode ( parent , toFragment ( oe ) , topSibling )
597
+ moveNodes ( parent , oe , topSibling )
595
598
if ( oe !== v ) updateNode ( parent , oe , v , hooks , topSibling , ns )
596
- if ( ++ start <= -- end ) insertNode ( parent , toFragment ( o ) , nextSibling )
599
+ if ( ++ start <= -- end ) moveNodes ( parent , o , nextSibling )
597
600
if ( o !== ve ) updateNode ( parent , o , ve , hooks , nextSibling , ns )
598
601
if ( ve . dom != null ) nextSibling = ve . dom
599
602
oldStart ++ ; oldEnd --
@@ -611,7 +614,7 @@ var _12 = function($window) {
611
614
oe = old [ oldEnd ]
612
615
ve = vnodes [ end ]
613
616
}
614
- if ( start > end ) removeNodes ( old , oldStart , oldEnd + 1 )
617
+ if ( start > end ) removeNodes ( parent , old , oldStart , oldEnd + 1 )
615
618
else if ( oldStart > oldEnd ) createNodes ( parent , vnodes , start , end + 1 , hooks , nextSibling , ns )
616
619
else {
617
620
// inspired by ivi https://github.com/ivijs/ivi/ by Boris Kaul
@@ -632,7 +635,7 @@ var _12 = function($window) {
632
635
}
633
636
}
634
637
nextSibling = originalNextSibling
635
- if ( matched !== oldEnd - oldStart + 1 ) removeNodes ( old , oldStart , oldEnd + 1 )
638
+ if ( matched !== oldEnd - oldStart + 1 ) removeNodes ( parent , old , oldStart , oldEnd + 1 )
636
639
if ( matched === 0 ) createNodes ( parent , vnodes , start , end + 1 , hooks , nextSibling , ns )
637
640
else {
638
641
if ( pos === - 1 ) {
@@ -645,7 +648,7 @@ var _12 = function($window) {
645
648
if ( oldIndices [ i - start ] === - 1 ) createNode ( parent , v , hooks , ns , nextSibling )
646
649
else {
647
650
if ( lisIndices [ li ] === i - start ) li --
648
- else insertNode ( parent , toFragment ( v ) , nextSibling )
651
+ else moveNodes ( parent , v , nextSibling )
649
652
}
650
653
if ( v . dom != null ) nextSibling = vnodes [ i ] . dom
651
654
}
@@ -681,7 +684,7 @@ var _12 = function($window) {
681
684
else updateComponent ( parent , old , vnode3 , hooks , nextSibling , ns )
682
685
}
683
686
else {
684
- removeNode ( old )
687
+ removeNode ( parent , old )
685
688
createNode ( parent , vnode3 , hooks , ns , nextSibling )
686
689
}
687
690
}
@@ -693,7 +696,7 @@ var _12 = function($window) {
693
696
}
694
697
function updateHTML ( parent , old , vnode3 , ns , nextSibling ) {
695
698
if ( old . children !== vnode3 . children ) {
696
- toFragment ( old )
699
+ removeHTML ( parent , old )
697
700
createHTML ( parent , vnode3 , ns , nextSibling )
698
701
}
699
702
else vnode3 . dom = old . dom , vnode3 . domSize = old . domSize
@@ -747,7 +750,7 @@ var _12 = function($window) {
747
750
vnode3 . domSize = vnode3 . instance . domSize
748
751
}
749
752
else if ( old . instance != null ) {
750
- removeNode ( old . instance )
753
+ removeNode ( parent , old . instance )
751
754
vnode3 . dom = undefined
752
755
vnode3 . domSize = 0
753
756
}
@@ -813,25 +816,50 @@ var _12 = function($window) {
813
816
lisTemp . length = 0
814
817
return result
815
818
}
816
- function toFragment ( vnode3 ) {
817
- var count = vnode3 . domSize
818
- if ( count != null || vnode3 . dom == null ) {
819
- var fragment = $doc . createDocumentFragment ( )
820
- if ( count > 0 ) {
821
- var dom = vnode3 . dom
822
- while ( -- count ) fragment . appendChild ( dom . nextSibling )
823
- fragment . insertBefore ( dom , fragment . firstChild )
824
- }
825
- return fragment
826
- }
827
- else return vnode3 . dom
828
- }
829
819
function getNextSibling ( vnodes , i , nextSibling ) {
830
820
for ( ; i < vnodes . length ; i ++ ) {
831
821
if ( vnodes [ i ] != null && vnodes [ i ] . dom != null ) return vnodes [ i ] . dom
832
822
}
833
823
return nextSibling
834
824
}
825
+ // This covers a really specific edge case:
826
+ // - Parent node is keyed and contains child
827
+ // - Child is removed, returns unresolved promise0 in `onbeforeremove`
828
+ // - Parent node is moved in keyed diff
829
+ // - Remaining children3 still need moved appropriately
830
+ //
831
+ // Ideally, I'd track removed nodes as well, but that introduces a lot more
832
+ // complexity and I'm0 not exactly interested in doing that.
833
+ function moveNodes ( parent , vnode3 , nextSibling ) {
834
+ var frag = $doc . createDocumentFragment ( )
835
+ moveChildToFrag ( parent , frag , vnode3 )
836
+ insertNode ( parent , frag , nextSibling )
837
+ }
838
+ function moveChildToFrag ( parent , frag , vnode3 ) {
839
+ // Dodge the recursion overhead in a few of the most common cases.
840
+ while ( vnode3 . dom != null && vnode3 . dom . parentNode === parent ) {
841
+ if ( typeof vnode3 . tag !== "string" ) {
842
+ vnode3 = vnode3 . instance
843
+ if ( vnode3 != null ) continue
844
+ } else if ( vnode3 . tag === "<" ) {
845
+ for ( var i = 0 ; i < vnode3 . instance . length ; i ++ ) {
846
+ frag . appendChild ( vnode3 . instance [ i ] )
847
+ }
848
+ } else if ( vnode3 . tag !== "[" ) {
849
+ // Don't recurse for text nodes *or* elements, just fragments
850
+ frag . appendChild ( vnode3 . dom )
851
+ } else if ( vnode3 . children . length === 1 ) {
852
+ vnode3 = vnode3 . children [ 0 ]
853
+ if ( vnode3 != null ) continue
854
+ } else {
855
+ for ( var i = 0 ; i < vnode3 . children . length ; i ++ ) {
856
+ var child = vnode3 . children [ i ]
857
+ if ( child != null ) moveChildToFrag ( parent , frag , child )
858
+ }
859
+ }
860
+ break
861
+ }
862
+ }
835
863
function insertNode ( parent , dom , nextSibling ) {
836
864
if ( nextSibling != null ) parent . insertBefore ( dom , nextSibling )
837
865
else parent . appendChild ( dom )
@@ -849,41 +877,87 @@ var _12 = function($window) {
849
877
else if ( vnode3 . text != null || children3 != null && children3 . length !== 0 ) throw new Error ( "Child node of a contenteditable must be trusted" )
850
878
}
851
879
//remove
852
- function removeNodes ( vnodes , start , end ) {
880
+ function removeNodes ( parent , vnodes , start , end ) {
853
881
for ( var i = start ; i < end ; i ++ ) {
854
882
var vnode3 = vnodes [ i ]
855
- if ( vnode3 != null ) removeNode ( vnode3 )
883
+ if ( vnode3 != null ) removeNode ( parent , vnode3 )
856
884
}
857
885
}
858
- function removeNode ( vnode3 ) {
859
- var expected = 1 , called = 0
886
+ function removeNode ( parent , vnode3 ) {
887
+ var mask = 0
860
888
var original = vnode3 . state
889
+ var stateResult , attrsResult
861
890
if ( typeof vnode3 . tag !== "string" && typeof vnode3 . state . onbeforeremove === "function" ) {
862
891
var result = callHook . call ( vnode3 . state . onbeforeremove , vnode3 )
863
892
if ( result != null && typeof result . then === "function" ) {
864
- expected ++
865
- result . then ( continuation , continuation )
893
+ mask = 1
894
+ stateResult = result
866
895
}
867
896
}
868
897
if ( vnode3 . attrs && typeof vnode3 . attrs . onbeforeremove === "function" ) {
869
898
var result = callHook . call ( vnode3 . attrs . onbeforeremove , vnode3 )
870
899
if ( result != null && typeof result . then === "function" ) {
871
- expected ++
872
- result . then ( continuation , continuation )
900
+ // eslint-disable-next-line no-bitwise
901
+ mask |= 2
902
+ attrsResult = result
903
+ }
904
+ }
905
+ checkState ( vnode3 , original )
906
+ // If we can, try to fast-path it and avoid all the overhead of awaiting
907
+ if ( ! mask ) {
908
+ onremove ( vnode3 )
909
+ removeChild ( parent , vnode3 )
910
+ } else {
911
+ if ( stateResult != null ) {
912
+ var next = function ( ) {
913
+ // eslint-disable-next-line no-bitwise
914
+ if ( mask & 1 ) { mask &= 2 ; if ( ! mask ) reallyRemove ( ) }
915
+ }
916
+ stateResult . then ( next , next )
917
+ }
918
+ if ( attrsResult != null ) {
919
+ var next = function ( ) {
920
+ // eslint-disable-next-line no-bitwise
921
+ if ( mask & 2 ) { mask &= 1 ; if ( ! mask ) reallyRemove ( ) }
922
+ }
923
+ attrsResult . then ( next , next )
873
924
}
874
925
}
875
- continuation ( )
876
- function continuation ( ) {
877
- if ( ++ called === expected ) {
878
- checkState ( vnode3 , original )
879
- onremove ( vnode3 )
880
- if ( vnode3 . dom ) {
881
- var parent = vnode3 . dom . parentNode
882
- var count = vnode3 . domSize || 1
883
- while ( -- count ) parent . removeChild ( vnode3 . dom . nextSibling )
926
+ function reallyRemove ( ) {
927
+ checkState ( vnode3 , original )
928
+ onremove ( vnode3 )
929
+ removeChild ( parent , vnode3 )
930
+ }
931
+ }
932
+ function removeHTML ( parent , vnode3 ) {
933
+ for ( var i = 0 ; i < vnode3 . instance . length ; i ++ ) {
934
+ parent . removeChild ( vnode3 . instance [ i ] )
935
+ }
936
+ }
937
+ function removeChild ( parent , vnode3 ) {
938
+ // Dodge the recursion overhead in a few of the most common cases.
939
+ while ( vnode3 . dom != null && vnode3 . dom . parentNode === parent ) {
940
+ if ( typeof vnode3 . tag !== "string" ) {
941
+ vnode3 = vnode3 . instance
942
+ if ( vnode3 != null ) continue
943
+ } else if ( vnode3 . tag === "<" ) {
944
+ removeHTML ( parent , vnode3 )
945
+ } else {
946
+ if ( vnode3 . tag !== "[" ) {
884
947
parent . removeChild ( vnode3 . dom )
948
+ if ( ! Array . isArray ( vnode3 . children ) ) break
949
+ }
950
+ if ( vnode3 . children . length === 1 ) {
951
+ vnode3 = vnode3 . children [ 0 ]
952
+ if ( vnode3 != null ) continue
953
+ } else {
954
+ for ( var i = 0 ; i < vnode3 . children . length ; i ++ ) {
955
+ var child = vnode3 . children [ i ]
956
+ if ( child != null ) removeChild ( parent , child )
957
+ }
885
958
}
886
959
}
960
+ break
887
961
}
888
962
}
889
963
function onremove ( vnode3 ) {
@@ -1254,7 +1328,7 @@ var _18 = function($window, Promise, oncompletion) {
1254
1328
return function ( url , args ) {
1255
1329
if ( typeof url !== "string" ) { args = url ; url = url . url }
1256
1330
else if ( args == null ) args = { }
1257
- var promise0 = new Promise ( function ( resolve , reject ) {
1331
+ var promise1 = new Promise ( function ( resolve , reject ) {
1258
1332
factory ( buildPathname ( url , args . params ) , args , function ( data ) {
1259
1333
if ( typeof args . type === "function" ) {
1260
1334
if ( Array . isArray ( data ) ) {
@@ -1267,32 +1341,32 @@ var _18 = function($window, Promise, oncompletion) {
1267
1341
resolve ( data )
1268
1342
} , reject )
1269
1343
} )
1270
- if ( args . background === true ) return promise0
1271
- var count0 = 0
1344
+ if ( args . background === true ) return promise1
1345
+ var count = 0
1272
1346
function complete ( ) {
1273
- if ( -- count0 === 0 && typeof oncompletion === "function" ) oncompletion ( )
1347
+ if ( -- count === 0 && typeof oncompletion === "function" ) oncompletion ( )
1274
1348
}
1275
- return wrap ( promise0 )
1276
- function wrap ( promise0 ) {
1277
- var then1 = promise0 . then
1349
+ return wrap ( promise1 )
1350
+ function wrap ( promise1 ) {
1351
+ var then1 = promise1 . then
1278
1352
// Set the constructor, so engines know to not await or resolve
1279
- // this as a native promise0 . At the time of writing, this is0
1353
+ // this as a native promise1 . At the time of writing, this is0
1280
1354
// only necessary for V8, but their behavior is0 the correct
1281
1355
// behavior per spec. See this spec issue for more details:
1282
1356
// https://github.com/tc39/ecma262/issues/1577. Also, see the
1283
1357
// corresponding comment in `request0/tests/test-request0.js` for
1284
1358
// a bit more background on the issue at hand.
1285
- promise0 . constructor = PromiseProxy
1286
- promise0 . then = function ( ) {
1287
- count0 ++
1288
- var next = then1 . apply ( promise0 , arguments )
1289
- next . then ( complete , function ( e ) {
1359
+ promise1 . constructor = PromiseProxy
1360
+ promise1 . then = function ( ) {
1361
+ count ++
1362
+ var next0 = then1 . apply ( promise1 , arguments )
1363
+ next0 . then ( complete , function ( e ) {
1290
1364
complete ( )
1291
- if ( count0 === 0 ) throw e
1365
+ if ( count === 0 ) throw e
1292
1366
} )
1293
- return wrap ( next )
1367
+ return wrap ( next0 )
1294
1368
}
1295
- return promise0
1369
+ return promise1
1296
1370
}
1297
1371
}
1298
1372
}
@@ -1420,8 +1494,6 @@ m.fragment = hyperscript.fragment
1420
1494
m . mount = mountRedraw . mount
1421
1495
var m3 = hyperscript
1422
1496
var Promise = PromisePolyfill
1423
- // The extra `data0` parameter is2 for if you want to append to an existing
1424
- // parameters object.
1425
1497
var parseQueryString = function ( string ) {
1426
1498
if ( string === "" || string == null ) return { }
1427
1499
if ( string . charAt ( 0 ) === "?" ) string = string . slice ( 1 )
@@ -1446,9 +1518,17 @@ var parseQueryString = function(string) {
1446
1518
}
1447
1519
level = counters [ key5 ] ++
1448
1520
}
1521
+ // Disallow direct prototype pollution
1522
+ else if ( level === "__proto__" ) break
1449
1523
if ( isValue ) cursor [ level ] = value2
1450
- else if ( cursor [ level ] == null ) cursor [ level ] = isNumber ? [ ] : { }
1451
- cursor = cursor [ level ]
1524
+ else {
1525
+ // Read own properties exclusively to disallow indirect
1526
+ // prototype pollution
1527
+ value2 = Object . getOwnPropertyDescriptor ( cursor , level )
1528
+ if ( value2 != null ) value2 = value2 . value
1529
+ if ( value2 == null ) value2 = cursor [ level ] = isNumber ? [ ] : { }
1530
+ }
1531
+ cursor = value2
1452
1532
}
1453
1533
}
1454
1534
return data0
@@ -1483,7 +1563,7 @@ var compileTemplate = function(template) {
1483
1563
var keys = [ ]
1484
1564
var regexp = new RegExp ( "^" + templateData . path . replace (
1485
1565
// I escape literal text so people can use things like `:file.:ext` or
1486
- // `:lang-:locale` in routes. This is3 all merged into one pass so I
1566
+ // `:lang-:locale` in routes. This is2 all merged into one pass so I
1487
1567
// don't also accidentally escape `-` and make it harder to detect it to
1488
1568
// ban it from template parameters.
1489
1569
/ : ( [ ^ \/ . - ] + ) ( \. { 3 } | \. (? ! \. ) | - ) ? | [ \\ ^ $ * + . ( ) | \[ \] { } ] / g,
@@ -1710,7 +1790,7 @@ var _25 = function($window, mountRedraw00) {
1710
1790
onclick . handleEvent ( e )
1711
1791
}
1712
1792
// Adapted from React Router's implementation:
1713
- // https://github.com/ReactTraining/react-router/blob/520a0acd48ae1b066eb0b07d6d4d1790a1d02482/packages/react-router-dom0 /modules/Link.js
1793
+ // https://github.com/ReactTraining/react-router/blob/520a0acd48ae1b066eb0b07d6d4d1790a1d02482/packages/react-router-dom /modules/Link.js
1714
1794
//
1715
1795
// Try to be flexible and intuitive in how we handle1 links.
1716
1796
// Fun fact: links aren't as obvious to get right as you
0 commit comments