@angular/ssr 22.1.0-next.3 → 22.1.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -630,27 +630,74 @@ function requireStringifier () {
630
630
  return str[0].toUpperCase() + str.slice(1)
631
631
  }
632
632
 
633
+ function atruleStart(str, node) {
634
+ let name = '@' + node.name;
635
+ let params = node.params ? str.rawValue(node, 'params') : '';
636
+
637
+ if (typeof node.raws.afterName !== 'undefined') {
638
+ name += node.raws.afterName;
639
+ } else if (params) {
640
+ name += ' ';
641
+ }
642
+
643
+ return name + params
644
+ }
645
+
646
+ function pushBody(str, stack, node) {
647
+ let nodes = node.nodes;
648
+ let last = nodes.length - 1;
649
+ while (last > 0) {
650
+ if (nodes[last].type !== 'comment') break
651
+ last -= 1;
652
+ }
653
+
654
+ let semicolon = str.raw(node, 'semicolon');
655
+ let isDocument = node.type === 'document';
656
+ for (let i = nodes.length - 1; i >= 0; i--) {
657
+ stack.push({
658
+ document: isDocument,
659
+ node: nodes[i],
660
+ semicolon: last !== i || semicolon
661
+ });
662
+ }
663
+ }
664
+
665
+ function pushBlock(str, stack, node, start) {
666
+ let between = str.raw(node, 'between', 'beforeOpen');
667
+ str.builder(escapeHTMLInCSS(start + between) + '{', node, 'start');
668
+
669
+ let hasNodes = node.nodes && node.nodes.length;
670
+ let close = () => {
671
+ let after = hasNodes
672
+ ? str.raw(node, 'after')
673
+ : str.raw(node, 'after', 'emptyBody');
674
+ if (after) str.builder(escapeHTMLInCSS(after));
675
+ str.builder('}', node, 'end');
676
+ if (node.type === 'rule' && node.raws.ownSemicolon) {
677
+ str.builder(escapeHTMLInCSS(node.raws.ownSemicolon), node, 'end');
678
+ }
679
+ };
680
+
681
+ if (hasNodes) {
682
+ stack.push(close);
683
+ pushBody(str, stack, node);
684
+ } else {
685
+ close();
686
+ }
687
+ }
688
+
633
689
  class Stringifier {
634
690
  constructor(builder) {
635
691
  this.builder = builder;
636
692
  }
637
693
 
638
694
  atrule(node, semicolon) {
639
- let raws = node.raws;
640
- let name = '@' + node.name;
641
- let params = node.params ? this.rawValue(node, 'params') : '';
642
-
643
- if (typeof raws.afterName !== 'undefined') {
644
- name += raws.afterName;
645
- } else if (params) {
646
- name += ' ';
647
- }
648
-
695
+ let start = atruleStart(this, node);
649
696
  if (node.nodes) {
650
- this.block(node, name + params);
697
+ this.block(node, start);
651
698
  } else {
652
- let end = (raws.between || '') + (semicolon ? ';' : '');
653
- this.builder(escapeHTMLInCSS(name + params + end), node);
699
+ let end = (node.raws.between || '') + (semicolon ? ';' : '');
700
+ this.builder(escapeHTMLInCSS(start + end), node);
654
701
  }
655
702
  }
656
703
 
@@ -700,20 +747,38 @@ function requireStringifier () {
700
747
  }
701
748
 
702
749
  body(node) {
703
- let nodes = node.nodes;
704
- let last = nodes.length - 1;
705
- while (last > 0) {
706
- if (nodes[last].type !== 'comment') break
707
- last -= 1;
708
- }
750
+ // Rules and at-rules are expanded into an explicit stack instead of
751
+ // recursive `stringify()` calls to survive deeply nested trees.
752
+ // If a subclass changes the traversal methods, its children go
753
+ // through `stringify()` to keep the override in charge.
754
+ let proto = Stringifier.prototype;
755
+ let expandable = ['atrule', 'block', 'body', 'rule', 'stringify'].every(
756
+ method => this[method] === proto[method]
757
+ );
758
+
759
+ let stack = [];
760
+ pushBody(this, stack, node);
761
+
762
+ while (stack.length > 0) {
763
+ let entry = stack.pop();
764
+ if (typeof entry === 'function') {
765
+ entry();
766
+ continue
767
+ }
709
768
 
710
- let semicolon = this.raw(node, 'semicolon');
711
- let isDocument = node.type === 'document';
712
- for (let i = 0; i < nodes.length; i++) {
713
- let child = nodes[i];
769
+ let child = entry.node;
714
770
  let before = this.raw(child, 'before');
715
- if (before) this.builder(isDocument ? before : escapeHTMLInCSS(before));
716
- this.stringify(child, last !== i || semicolon);
771
+ if (before) {
772
+ this.builder(entry.document ? before : escapeHTMLInCSS(before));
773
+ }
774
+
775
+ if (expandable && child.type === 'rule') {
776
+ pushBlock(this, stack, child, this.rawValue(child, 'selector'));
777
+ } else if (expandable && child.type === 'atrule' && child.nodes) {
778
+ pushBlock(this, stack, child, atruleStart(this, child));
779
+ } else {
780
+ this.stringify(child, entry.semicolon);
781
+ }
717
782
  }
718
783
  }
719
784
 
@@ -1021,25 +1086,41 @@ function requireNode$1 () {
1021
1086
 
1022
1087
  function cloneNode(obj, parent) {
1023
1088
  let cloned = new obj.constructor();
1024
-
1025
- for (let i in obj) {
1026
- if (!Object.prototype.hasOwnProperty.call(obj, i)) {
1027
- /* c8 ignore next 2 */
1028
- continue
1029
- }
1030
- if (i === 'proxyCache') continue
1031
- let value = obj[i];
1032
- let type = typeof value;
1033
-
1034
- if (i === 'parent' && type === 'object') {
1035
- if (parent) cloned[i] = parent;
1036
- } else if (i === 'source') {
1037
- cloned[i] = value;
1038
- } else if (Array.isArray(value)) {
1039
- cloned[i] = value.map(j => cloneNode(j, cloned));
1040
- } else {
1041
- if (type === 'object' && value !== null) value = cloneNode(value);
1042
- cloned[i] = value;
1089
+ // An explicit stack instead of recursive calls to survive deeply
1090
+ // nested trees. Each entry is [source, its clone, clone's parent].
1091
+ let stack = [[obj, cloned, parent]];
1092
+
1093
+ while (stack.length > 0) {
1094
+ let [source, target, targetParent] = stack.pop();
1095
+ for (let i in source) {
1096
+ if (!Object.prototype.hasOwnProperty.call(source, i)) {
1097
+ /* c8 ignore next 2 */
1098
+ continue
1099
+ }
1100
+ if (i === 'proxyCache') continue
1101
+ let value = source[i];
1102
+ let type = typeof value;
1103
+
1104
+ if (i === 'parent' && type === 'object') {
1105
+ if (targetParent) target[i] = targetParent;
1106
+ } else if (i === 'source') {
1107
+ target[i] = value;
1108
+ } else if (Array.isArray(value)) {
1109
+ let children = [];
1110
+ target[i] = children;
1111
+ for (let j of value) {
1112
+ let childClone = new j.constructor();
1113
+ children.push(childClone);
1114
+ stack.push([j, childClone, target]);
1115
+ }
1116
+ } else {
1117
+ if (type === 'object' && value !== null) {
1118
+ let valueClone = new value.constructor();
1119
+ stack.push([value, valueClone, undefined]);
1120
+ value = valueClone;
1121
+ }
1122
+ target[i] = value;
1123
+ }
1043
1124
  }
1044
1125
  }
1045
1126
 
@@ -1083,11 +1164,15 @@ function requireNode$1 () {
1083
1164
  this[isClean] = false;
1084
1165
  this[my] = true;
1085
1166
 
1086
- for (let name in defaults) {
1167
+ for (let name of Object.keys(defaults)) {
1168
+ if (name === '__proto__') continue
1087
1169
  if (name === 'nodes') {
1088
1170
  this.nodes = [];
1089
1171
  for (let node of defaults[name]) {
1090
- if (typeof node.clone === 'function') {
1172
+ // Clone only nodes that already belong to another tree, so passing a
1173
+ // freshly created (parent-less) node adopts that instance instead of
1174
+ // a copy and keeps the caller's reference usable. See #1987.
1175
+ if (typeof node.clone === 'function' && node.parent) {
1091
1176
  this.append(node.clone());
1092
1177
  } else {
1093
1178
  this.append(node);
@@ -1220,14 +1305,18 @@ function requireNode$1 () {
1220
1305
  }
1221
1306
 
1222
1307
  positionBy(opts = {}) {
1223
- let pos = this.source.start;
1308
+ let inputString =
1309
+ 'document' in this.source.input
1310
+ ? this.source.input.document
1311
+ : this.source.input.css;
1312
+ let pos = {
1313
+ column: this.source.start.column,
1314
+ line: this.source.start.line,
1315
+ offset: sourceOffset(inputString, this.source.start)
1316
+ };
1224
1317
  if (opts.index) {
1225
1318
  pos = this.positionInside(opts.index);
1226
1319
  } else if (opts.word) {
1227
- let inputString =
1228
- 'document' in this.source.input
1229
- ? this.source.input.document
1230
- : this.source.input.css;
1231
1320
  let stringRepresentation = inputString.slice(
1232
1321
  sourceOffset(inputString, this.source.start),
1233
1322
  sourceOffset(inputString, this.source.end)
@@ -1312,7 +1401,7 @@ function requireNode$1 () {
1312
1401
  line: opts.start.line,
1313
1402
  offset: sourceOffset(inputString, opts.start)
1314
1403
  };
1315
- } else if (opts.index) {
1404
+ } else if (typeof opts.index === 'number') {
1316
1405
  start = this.positionInside(opts.index);
1317
1406
  }
1318
1407
 
@@ -1324,7 +1413,7 @@ function requireNode$1 () {
1324
1413
  };
1325
1414
  } else if (typeof opts.endIndex === 'number') {
1326
1415
  end = this.positionInside(opts.endIndex);
1327
- } else if (opts.index) {
1416
+ } else if (typeof opts.index === 'number') {
1328
1417
  end = this.positionInside(opts.index + 1);
1329
1418
  }
1330
1419
  }
@@ -1388,47 +1477,68 @@ function requireNode$1 () {
1388
1477
  }
1389
1478
 
1390
1479
  toJSON(_, inputs) {
1391
- let fixed = {};
1392
1480
  let emitInputs = inputs == null;
1393
1481
  inputs = inputs || new Map();
1394
- let inputsNextIndex = 0;
1395
1482
 
1396
- for (let name in this) {
1397
- if (!Object.prototype.hasOwnProperty.call(this, name)) {
1398
- /* c8 ignore next 2 */
1399
- continue
1400
- }
1401
- if (name === 'parent' || name === 'proxyCache') continue
1402
- let value = this[name];
1483
+ // A worklist instead of recursive `toJSON()` calls to survive deeply
1484
+ // nested trees. Each entry converts one node and writes the result
1485
+ // into the already converted parent by [holder, key].
1486
+ let holderOfRoot = [];
1487
+ let queue = [[this, holderOfRoot, 0]];
1403
1488
 
1404
- if (Array.isArray(value)) {
1405
- fixed[name] = value.map(i => {
1406
- if (typeof i === 'object' && i.toJSON) {
1407
- return i.toJSON(null, inputs)
1489
+ for (let step = 0; step < queue.length; step++) {
1490
+ let [node, holder, key] = queue[step];
1491
+ let fixed = {};
1492
+ holder[key] = fixed;
1493
+
1494
+ for (let name in node) {
1495
+ if (!Object.prototype.hasOwnProperty.call(node, name)) {
1496
+ /* c8 ignore next 2 */
1497
+ continue
1498
+ }
1499
+ if (name === 'parent' || name === 'proxyCache') continue
1500
+ let value = node[name];
1501
+
1502
+ if (Array.isArray(value)) {
1503
+ let fixedArray = [];
1504
+ fixed[name] = fixedArray;
1505
+ for (let i = 0; i < value.length; i++) {
1506
+ let item = value[i];
1507
+ if (typeof item === 'object' && item.toJSON) {
1508
+ if (item.toJSON === Node.prototype.toJSON) {
1509
+ queue.push([item, fixedArray, i]);
1510
+ } else {
1511
+ fixedArray[i] = item.toJSON(null, inputs);
1512
+ }
1513
+ } else {
1514
+ fixedArray[i] = item;
1515
+ }
1516
+ }
1517
+ } else if (typeof value === 'object' && value.toJSON) {
1518
+ if (value.toJSON === Node.prototype.toJSON) {
1519
+ queue.push([value, fixed, name]);
1408
1520
  } else {
1409
- return i
1521
+ fixed[name] = value.toJSON(null, inputs);
1410
1522
  }
1411
- });
1412
- } else if (typeof value === 'object' && value.toJSON) {
1413
- fixed[name] = value.toJSON(null, inputs);
1414
- } else if (name === 'source') {
1415
- if (value == null) continue
1416
- let inputId = inputs.get(value.input);
1417
- if (inputId == null) {
1418
- inputId = inputsNextIndex;
1419
- inputs.set(value.input, inputsNextIndex);
1420
- inputsNextIndex++;
1523
+ } else if (name === 'source') {
1524
+ if (value == null) continue
1525
+ let inputId = inputs.get(value.input);
1526
+ if (inputId == null) {
1527
+ inputId = inputs.size;
1528
+ inputs.set(value.input, inputId);
1529
+ }
1530
+ fixed[name] = {
1531
+ end: value.end,
1532
+ inputId,
1533
+ start: value.start
1534
+ };
1535
+ } else {
1536
+ fixed[name] = value;
1421
1537
  }
1422
- fixed[name] = {
1423
- end: value.end,
1424
- inputId,
1425
- start: value.start
1426
- };
1427
- } else {
1428
- fixed[name] = value;
1429
1538
  }
1430
1539
  }
1431
1540
 
1541
+ let fixed = holderOfRoot[0];
1432
1542
  if (emitInputs) {
1433
1543
  fixed.inputs = [...inputs.keys()].map(input => input.toJSON());
1434
1544
  }
@@ -1532,18 +1642,25 @@ function requireContainer$1 () {
1532
1642
  let AtRule, parse, Root, Rule;
1533
1643
 
1534
1644
  function cleanSource(nodes) {
1535
- return nodes.map(i => {
1536
- if (i.nodes) i.nodes = cleanSource(i.nodes);
1537
- delete i.source;
1538
- return i
1539
- })
1645
+ let stack = nodes.slice();
1646
+ while (stack.length > 0) {
1647
+ let node = stack.pop();
1648
+ delete node.source;
1649
+ if (node.nodes) {
1650
+ node.nodes = node.nodes.slice();
1651
+ for (let i of node.nodes) stack.push(i);
1652
+ }
1653
+ }
1654
+ return nodes.slice()
1540
1655
  }
1541
1656
 
1542
1657
  function markTreeDirty(node) {
1543
- node[isClean] = false;
1544
- if (node.proxyOf.nodes) {
1545
- for (let i of node.proxyOf.nodes) {
1546
- markTreeDirty(i);
1658
+ let stack = [node];
1659
+ while (stack.length > 0) {
1660
+ let next = stack.pop();
1661
+ next[isClean] = false;
1662
+ if (next.proxyOf.nodes) {
1663
+ for (let i of next.proxyOf.nodes) stack.push(i);
1547
1664
  }
1548
1665
  }
1549
1666
  }
@@ -1571,9 +1688,18 @@ function requireContainer$1 () {
1571
1688
  }
1572
1689
 
1573
1690
  cleanRaws(keepBetween) {
1574
- super.cleanRaws(keepBetween);
1575
- if (this.nodes) {
1576
- for (let node of this.nodes) node.cleanRaws(keepBetween);
1691
+ let stack = [this];
1692
+ while (stack.length > 0) {
1693
+ let node = stack.pop();
1694
+ if (node !== this && node.cleanRaws !== Container.prototype.cleanRaws) {
1695
+ // Subclass with own logic; let it handle its subtree
1696
+ node.cleanRaws(keepBetween);
1697
+ continue
1698
+ }
1699
+ Node.prototype.cleanRaws.call(node, keepBetween);
1700
+ if (node.nodes) {
1701
+ for (let child of node.nodes) stack.push(child);
1702
+ }
1577
1703
  }
1578
1704
  }
1579
1705
 
@@ -1833,19 +1959,48 @@ function requireContainer$1 () {
1833
1959
  }
1834
1960
 
1835
1961
  walk(callback) {
1836
- return this.each((child, i) => {
1962
+ if (!this.proxyOf.nodes) return undefined
1963
+
1964
+ // An explicit stack instead of recursive `each()` calls to survive
1965
+ // deeply nested trees. Each frame keeps a live `indexes` slot, so
1966
+ // insertion and removal during the walk behave like `each()`: the
1967
+ // slot stays at the current child until its subtree is finished.
1968
+ let stack = [{ iterator: this.getIterator(), node: this.proxyOf }];
1969
+
1970
+ while (stack.length > 0) {
1971
+ let { iterator, node } = stack[stack.length - 1];
1972
+ let index = node.indexes[iterator];
1973
+
1974
+ if (index >= node.proxyOf.nodes.length) {
1975
+ delete node.indexes[iterator];
1976
+ stack.pop();
1977
+ let parent = stack[stack.length - 1];
1978
+ // Finish the parent’s step for the child subtree we just left
1979
+ if (parent) parent.node.indexes[parent.iterator] += 1;
1980
+ continue
1981
+ }
1982
+
1983
+ let child = node.proxyOf.nodes[index];
1837
1984
  let result;
1838
1985
  try {
1839
- result = callback(child, i);
1986
+ result = callback(child, index);
1840
1987
  } catch (e) {
1841
1988
  throw child.addToError(e)
1842
1989
  }
1843
- if (result !== false && child.walk) {
1844
- result = child.walk(callback);
1990
+ if (result === false) {
1991
+ for (let opened of stack) {
1992
+ delete opened.node.indexes[opened.iterator];
1993
+ }
1994
+ return false
1995
+ }
1996
+ if (child.walk && child.proxyOf.nodes) {
1997
+ stack.push({ iterator: child.getIterator(), node: child });
1998
+ } else {
1999
+ node.indexes[iterator] += 1;
1845
2000
  }
2001
+ }
1846
2002
 
1847
- return result
1848
- })
2003
+ return undefined
1849
2004
  }
1850
2005
 
1851
2006
  walkAtRules(name, callback) {
@@ -1948,24 +2103,26 @@ function requireContainer$1 () {
1948
2103
 
1949
2104
  /* c8 ignore start */
1950
2105
  Container.rebuild = node => {
1951
- if (node.type === 'atrule') {
1952
- Object.setPrototypeOf(node, AtRule.prototype);
1953
- } else if (node.type === 'rule') {
1954
- Object.setPrototypeOf(node, Rule.prototype);
1955
- } else if (node.type === 'decl') {
1956
- Object.setPrototypeOf(node, Declaration.prototype);
1957
- } else if (node.type === 'comment') {
1958
- Object.setPrototypeOf(node, Comment.prototype);
1959
- } else if (node.type === 'root') {
1960
- Object.setPrototypeOf(node, Root.prototype);
1961
- }
2106
+ let stack = [node];
2107
+ while (stack.length > 0) {
2108
+ let next = stack.pop();
2109
+ if (next.type === 'atrule') {
2110
+ Object.setPrototypeOf(next, AtRule.prototype);
2111
+ } else if (next.type === 'rule') {
2112
+ Object.setPrototypeOf(next, Rule.prototype);
2113
+ } else if (next.type === 'decl') {
2114
+ Object.setPrototypeOf(next, Declaration.prototype);
2115
+ } else if (next.type === 'comment') {
2116
+ Object.setPrototypeOf(next, Comment.prototype);
2117
+ } else if (next.type === 'root') {
2118
+ Object.setPrototypeOf(next, Root.prototype);
2119
+ }
1962
2120
 
1963
- node[my] = true;
2121
+ next[my] = true;
1964
2122
 
1965
- if (node.nodes) {
1966
- node.nodes.forEach(child => {
1967
- Container.rebuild(child);
1968
- });
2123
+ if (next.nodes) {
2124
+ for (let child of next.nodes) stack.push(child);
2125
+ }
1969
2126
  }
1970
2127
  };
1971
2128
  /* c8 ignore stop */
@@ -2059,7 +2216,7 @@ function requireNonSecure () {
2059
2216
  return (size = defaultSize) => {
2060
2217
  let id = '';
2061
2218
  let i = size | 0;
2062
- while (i--) {
2219
+ while (i-- > 0) {
2063
2220
  id += alphabet[(Math.random() * alphabet.length) | 0];
2064
2221
  }
2065
2222
  return id
@@ -2069,7 +2226,7 @@ function requireNonSecure () {
2069
2226
  let nanoid = (size = 21) => {
2070
2227
  let id = '';
2071
2228
  let i = size | 0;
2072
- while (i--) {
2229
+ while (i-- > 0) {
2073
2230
  id += urlAlphabet[(Math.random() * 64) | 0];
2074
2231
  }
2075
2232
  return id
@@ -2087,7 +2244,7 @@ function requirePreviousMap () {
2087
2244
  hasRequiredPreviousMap = 1;
2088
2245
 
2089
2246
  let { existsSync, readFileSync } = require$$2;
2090
- let { dirname, join } = require$$2;
2247
+ let { dirname, isAbsolute, join, relative, sep } = require$$2;
2091
2248
  let { SourceMapConsumer, SourceMapGenerator } = require$$2;
2092
2249
 
2093
2250
  function fromBase64(str) {
@@ -2171,11 +2328,20 @@ function requirePreviousMap () {
2171
2328
  }
2172
2329
 
2173
2330
  loadFile(path, cssFile, trusted) {
2174
- /* c8 ignore next 5 */
2175
2331
  if (!trusted && !this.unsafeMap) {
2176
2332
  if (!/\.map$/i.test(path)) {
2177
2333
  return undefined
2178
2334
  }
2335
+ if (cssFile) {
2336
+ let relativePath = relative(dirname(cssFile), path);
2337
+ if (
2338
+ relativePath === '..' ||
2339
+ relativePath.startsWith('..' + sep) ||
2340
+ isAbsolute(relativePath)
2341
+ ) {
2342
+ return undefined
2343
+ }
2344
+ }
2179
2345
  }
2180
2346
  this.root = dirname(path);
2181
2347
  if (existsSync(path)) {
@@ -2461,12 +2627,21 @@ function requireInput () {
2461
2627
  if (!this.map) return false
2462
2628
  let consumer = this.map.consumer();
2463
2629
 
2464
- let from = consumer.originalPositionFor({ column, line });
2630
+ let from = consumer.originalPositionFor({ column: column - 1, line });
2465
2631
  if (!from.source) return false
2466
2632
 
2467
2633
  let to;
2468
2634
  if (typeof endLine === 'number') {
2469
- to = consumer.originalPositionFor({ column: endColumn, line: endLine });
2635
+ let toPosition = consumer.originalPositionFor({
2636
+ column: endColumn - 1,
2637
+ line: endLine
2638
+ });
2639
+ // The source map may not have a mapping that covers the end position
2640
+ // (`originalPositionFor()` then returns `null` for `line`/`column`
2641
+ // instead of omitting them). Treat that the same as not requesting
2642
+ // an end position at all, so `endLine`/`endColumn` stay a consistent
2643
+ // `undefined` pair instead of a mix of `null` and a bogus number.
2644
+ if (toPosition.source) to = toPosition;
2470
2645
  }
2471
2646
 
2472
2647
  let fromUrl;
@@ -2481,8 +2656,8 @@ function requireInput () {
2481
2656
  }
2482
2657
 
2483
2658
  let result = {
2484
- column: from.column,
2485
- endColumn: to && to.column,
2659
+ column: from.column + 1,
2660
+ endColumn: to && to.column + 1,
2486
2661
  endLine: to && to.line,
2487
2662
  line: from.line,
2488
2663
  url: fromUrl.toString()
@@ -2548,6 +2723,19 @@ function requireRoot () {
2548
2723
  }
2549
2724
 
2550
2725
  normalize(child, sample, type) {
2726
+ let keepBefore = new Set();
2727
+ for (let node of Array.isArray(child) ? child : [child]) {
2728
+ if (
2729
+ node &&
2730
+ typeof node === 'object' &&
2731
+ !node.parent &&
2732
+ node.raws &&
2733
+ typeof node.raws.before !== 'undefined'
2734
+ ) {
2735
+ keepBefore.add(node.raws);
2736
+ }
2737
+ }
2738
+
2551
2739
  let nodes = super.normalize(child);
2552
2740
 
2553
2741
  if (sample) {
@@ -2559,7 +2747,9 @@ function requireRoot () {
2559
2747
  }
2560
2748
  } else if (this.first !== sample) {
2561
2749
  for (let node of nodes) {
2562
- node.raws.before = sample.raws.before;
2750
+ if (!keepBefore.has(node.raws)) {
2751
+ node.raws.before = sample.raws.before;
2752
+ }
2563
2753
  }
2564
2754
  }
2565
2755
  }
@@ -2714,26 +2904,24 @@ function requireFromJSON () {
2714
2904
  let Root = requireRoot();
2715
2905
  let Rule = requireRule();
2716
2906
 
2717
- function fromJSON(json, inputs) {
2718
- if (Array.isArray(json)) return json.map(n => fromJSON(n))
2719
-
2720
- let { inputs: ownInputs, ...defaults } = json;
2721
- if (ownInputs) {
2722
- inputs = [];
2723
- for (let input of ownInputs) {
2724
- let inputHydrated = { ...input, __proto__: Input.prototype };
2725
- if (inputHydrated.map) {
2726
- inputHydrated.map = {
2727
- ...inputHydrated.map,
2728
- __proto__: PreviousMap.prototype
2729
- };
2730
- }
2731
- inputs.push(inputHydrated);
2907
+ function hydrateInputs(json, inputs) {
2908
+ if (!json.inputs) return inputs
2909
+ return json.inputs.map(input => {
2910
+ let inputHydrated = { ...input, __proto__: Input.prototype };
2911
+ if (inputHydrated.map) {
2912
+ inputHydrated.map = {
2913
+ ...inputHydrated.map,
2914
+ __proto__: PreviousMap.prototype
2915
+ };
2732
2916
  }
2733
- }
2734
- if (defaults.nodes) {
2735
- defaults.nodes = json.nodes.map(n => fromJSON(n, inputs));
2736
- }
2917
+ return inputHydrated
2918
+ })
2919
+ }
2920
+
2921
+ function constructNode(json, inputs, children) {
2922
+ let defaults = { ...json };
2923
+ delete defaults.inputs;
2924
+ delete defaults.nodes;
2737
2925
  if (defaults.source) {
2738
2926
  let { inputId, ...source } = defaults.source;
2739
2927
  defaults.source = source;
@@ -2741,19 +2929,74 @@ function requireFromJSON () {
2741
2929
  defaults.source.input = inputs[inputId];
2742
2930
  }
2743
2931
  }
2932
+
2933
+ let node;
2744
2934
  if (defaults.type === 'root') {
2745
- return new Root(defaults)
2935
+ node = new Root(defaults);
2746
2936
  } else if (defaults.type === 'decl') {
2747
- return new Declaration(defaults)
2937
+ node = new Declaration(defaults);
2748
2938
  } else if (defaults.type === 'rule') {
2749
- return new Rule(defaults)
2939
+ node = new Rule(defaults);
2750
2940
  } else if (defaults.type === 'comment') {
2751
- return new Comment(defaults)
2941
+ node = new Comment(defaults);
2752
2942
  } else if (defaults.type === 'atrule') {
2753
- return new AtRule(defaults)
2943
+ node = new AtRule(defaults);
2754
2944
  } else {
2755
2945
  throw new Error('Unknown node type: ' + json.type)
2756
2946
  }
2947
+
2948
+ // Rehydrated children are attached after construction. Passing them
2949
+ // through the container constructor would re-run insertion spacing
2950
+ // normalization and overwrite each child's own `raws.before`.
2951
+ if (children) {
2952
+ node.nodes = children;
2953
+ for (let child of children) child.parent = node;
2954
+ }
2955
+
2956
+ return node
2957
+ }
2958
+
2959
+ function fromJSON(json, inputs) {
2960
+ if (Array.isArray(json)) return json.map(n => fromJSON(n))
2961
+
2962
+ // An explicit stack instead of recursive calls to survive deeply
2963
+ // nested trees. Children are rehydrated before their parent node
2964
+ // is constructed.
2965
+ let result;
2966
+ let stack = [
2967
+ { childIndex: 0, children: [], inputs: hydrateInputs(json, inputs), json }
2968
+ ];
2969
+
2970
+ while (stack.length > 0) {
2971
+ let frame = stack[stack.length - 1];
2972
+ let jsonNodes = frame.json.nodes;
2973
+
2974
+ if (jsonNodes && frame.childIndex < jsonNodes.length) {
2975
+ let childJson = jsonNodes[frame.childIndex];
2976
+ frame.childIndex += 1;
2977
+ stack.push({
2978
+ childIndex: 0,
2979
+ children: [],
2980
+ inputs: hydrateInputs(childJson, frame.inputs),
2981
+ json: childJson
2982
+ });
2983
+ continue
2984
+ }
2985
+
2986
+ stack.pop();
2987
+ let node = constructNode(
2988
+ frame.json,
2989
+ frame.inputs,
2990
+ jsonNodes ? frame.children : undefined
2991
+ );
2992
+ if (stack.length > 0) {
2993
+ stack[stack.length - 1].children.push(node);
2994
+ } else {
2995
+ result = node;
2996
+ }
2997
+ }
2998
+
2999
+ return result
2757
3000
  }
2758
3001
 
2759
3002
  fromJSON_1 = fromJSON;
@@ -4320,8 +4563,14 @@ function requireLazyResult () {
4320
4563
  }
4321
4564
 
4322
4565
  function cleanMarks(node) {
4323
- node[isClean] = false;
4324
- if (node.nodes) node.nodes.forEach(i => cleanMarks(i));
4566
+ let stack = [node];
4567
+ while (stack.length > 0) {
4568
+ let next = stack.pop();
4569
+ next[isClean] = false;
4570
+ if (next.nodes) {
4571
+ for (let i of next.nodes) stack.push(i);
4572
+ }
4573
+ }
4325
4574
  return node
4326
4575
  }
4327
4576
 
@@ -4752,21 +5001,57 @@ function requireLazyResult () {
4752
5001
  }
4753
5002
 
4754
5003
  walkSync(node) {
5004
+ // An explicit stack like in async `visitTick()` to survive deeply
5005
+ // nested trees. Unlike `visitTick()`, nodes are marked clean only
5006
+ // on entering, so a node dirtied by its own visitors is revisited
5007
+ // on the next pass.
4755
5008
  node[isClean] = true;
4756
- let events = getEvents(node);
4757
- for (let event of events) {
4758
- if (event === CHILDREN) {
4759
- if (node.nodes) {
4760
- node.each(child => {
4761
- if (!child[isClean]) this.walkSync(child);
4762
- });
5009
+ let stack = [{ eventIndex: 0, events: getEvents(node), iterator: 0, node }];
5010
+
5011
+ while (stack.length > 0) {
5012
+ let visit = stack[stack.length - 1];
5013
+ let visitNode = visit.node;
5014
+
5015
+ if (visit.iterator !== 0) {
5016
+ let iterator = visit.iterator;
5017
+ let child;
5018
+ let descended = false;
5019
+ while ((child = visitNode.nodes[visitNode.indexes[iterator]])) {
5020
+ visitNode.indexes[iterator] += 1;
5021
+ if (!child[isClean]) {
5022
+ child[isClean] = true;
5023
+ stack.push({
5024
+ eventIndex: 0,
5025
+ events: getEvents(child),
5026
+ iterator: 0,
5027
+ node: child
5028
+ });
5029
+ descended = true;
5030
+ break
5031
+ }
4763
5032
  }
4764
- } else {
4765
- let visitors = this.listeners[event];
4766
- if (visitors) {
4767
- if (this.visitSync(visitors, node.toProxy())) return
5033
+ if (descended) continue
5034
+ visit.iterator = 0;
5035
+ delete visitNode.indexes[iterator];
5036
+ }
5037
+
5038
+ if (visit.eventIndex < visit.events.length) {
5039
+ let event = visit.events[visit.eventIndex];
5040
+ visit.eventIndex += 1;
5041
+ if (event === CHILDREN) {
5042
+ if (visitNode.nodes && visitNode.nodes.length) {
5043
+ visit.iterator = visitNode.getIterator();
5044
+ }
5045
+ } else {
5046
+ let visitors = this.listeners[event];
5047
+ if (visitors) {
5048
+ if (this.visitSync(visitors, visitNode.toProxy())) stack.pop();
5049
+ }
4768
5050
  }
5051
+ continue
4769
5052
  }
5053
+
5054
+ stack.pop();
4770
5055
  }
4771
5056
  }
4772
5057
 
@@ -4946,7 +5231,7 @@ function requireProcessor () {
4946
5231
 
4947
5232
  class Processor {
4948
5233
  constructor(plugins = []) {
4949
- this.version = '8.5.15';
5234
+ this.version = '8.5.19';
4950
5235
  this.plugins = this.normalize(plugins);
4951
5236
  }
4952
5237
 
@@ -11555,9 +11840,10 @@ function serializeStylesheet(ast, options) {
11555
11840
  }
11556
11841
  return;
11557
11842
  }
11558
- if (type === "end" && result === "}" && node?.raws?.semicolon) {
11843
+ if (type === "end" && result === "}" && node?.raws?.semicolon && (node.type === "rule" || node.type === "atrule")) {
11844
+ const lastChild = node.nodes?.[node.nodes.length - 1];
11559
11845
  const lastItemIdx = cssParts.length - 2;
11560
- if (lastItemIdx >= 0 && cssParts[lastItemIdx]) {
11846
+ if (lastChild?.type === "decl" && lastItemIdx >= 0 && cssParts[lastItemIdx]) {
11561
11847
  cssParts[lastItemIdx] = cssParts[lastItemIdx].slice(0, -1);
11562
11848
  }
11563
11849
  }
@@ -11732,13 +12018,15 @@ function createDocument(html) {
11732
12018
  const document = parseDocument(html, { decodeEntities: false });
11733
12019
  extendDocument(document);
11734
12020
  extendElement(Element.prototype);
11735
- let beastiesContainer = document.querySelector("[data-beasties-container]");
11736
- if (!beastiesContainer) {
12021
+ let beastiesContainers = document.querySelectorAll("[data-beasties-container]");
12022
+ if (!beastiesContainers.length) {
11737
12023
  document.documentElement?.setAttribute("data-beasties-container", "");
11738
- beastiesContainer = document.documentElement || document;
12024
+ beastiesContainers = [document.documentElement || document];
12025
+ }
12026
+ document.beastiesContainers = beastiesContainers;
12027
+ for (const container of beastiesContainers) {
12028
+ buildCache(container);
11739
12029
  }
11740
- document.beastiesContainer = beastiesContainer;
11741
- buildCache(beastiesContainer);
11742
12030
  return document;
11743
12031
  }
11744
12032
  function serializeDocument(document) {
@@ -11916,6 +12204,11 @@ function extendDocument(document) {
11916
12204
  }
11917
12205
  return selectAll(sel, this);
11918
12206
  }
12207
+ },
12208
+ beastiesContainer: {
12209
+ get() {
12210
+ return this.beastiesContainers?.[0];
12211
+ }
11919
12212
  }
11920
12213
  });
11921
12214
  }
@@ -12203,6 +12496,9 @@ class Beasties {
12203
12496
  * Fetch CSS content for a linked stylesheet
12204
12497
  */
12205
12498
  async fetchStylesheet(link, document) {
12499
+ if (link.hasAttribute("data-beasties-skip")) {
12500
+ return void 0;
12501
+ }
12206
12502
  const href = link.getAttribute("href");
12207
12503
  const pathname = href?.split("?")[0]?.split("#")[0];
12208
12504
  if (!pathname?.endsWith(".css")) {
@@ -12339,7 +12635,7 @@ class Beasties {
12339
12635
  return;
12340
12636
  const name = style.$$name ? style.$$name.replace(LEADING_SLASH_RE, "") : "inline CSS";
12341
12637
  const options = this.options;
12342
- const beastiesContainer = document.beastiesContainer;
12638
+ const beastiesContainers = document.beastiesContainers;
12343
12639
  let keyframesMode = options.keyframes ?? "critical";
12344
12640
  if (keyframesMode === true)
12345
12641
  keyframesMode = "all";
@@ -12420,7 +12716,7 @@ class Beasties {
12420
12716
  if (!sel)
12421
12717
  return false;
12422
12718
  try {
12423
- return beastiesContainer.exists(sel);
12719
+ return beastiesContainers.some((container) => container.exists(sel));
12424
12720
  } catch (e) {
12425
12721
  failedSelectors.push(`${sel} -> ${e.message || e.toString()}`);
12426
12722
  return false;